Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Update Billion Records
Search
ta1kt0me
October 27, 2023
Programming
5.4k
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Update Billion Records
Kaigi on Rails 2023
ta1kt0me
October 27, 2023
More Decks by ta1kt0me
See All by ta1kt0me
過去の改善から考える オブザーバビリティの必要性
ta1kt0me
0
59
Running with version up
ta1kt0me
0
80
omotesandorb_8.pdf
ta1kt0me
1
430
Rubyでのプロファイリング
ta1kt0me
0
120
開発環境でdockerを使ってみた
ta1kt0me
0
470
Other Decks in Programming
See All in Programming
Observability in Practice:Grafana 與 Edge Device SRE 的那些事
blueswen
0
140
生成AI時代にこそ効くGo | Why Go Works in the Age of Generative AI
mom0tomo
8
3.2k
RTSPクライアントを自作してみた話
simotin13
0
510
JavaDoc 再入門
nagise
0
300
Why Laravel apps break—Mastering the fundamentals to keep them maintainable
kentaroutakeda
1
340
AIエージェントと協働するCLI開発 — BunとOpenClawで学んだこと
yoshikouki
1
240
DynamoDBには集計系のクエリがないけどなんとかしたい
musan
1
130
メソッドのジェネリクスでGoの夢は広がるか? / Kyoto.go #65
utgwkk
3
610
キャリア迷子上等 ─ "ない道"は自分で作ればいい
16bitidol
3
1.8k
Javaの型とAI時代に型が大事な理由 / java types and type in AI era
kishida
2
110
Oxcを導入して開発体験が向上した話
yug1224
4
290
Spring Security 実践 ─ GraphQL APIで実務に役立つ 認証・認可 を学ぶ
wagyu
0
190
Featured
See All Featured
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
290
How to make the Groovebox
asonas
2
2.2k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
140
Exploring anti-patterns in Rails
aemeredith
3
400
Bash Introduction
62gerente
615
210k
First, design no harm
axbom
PRO
2
1.2k
Music & Morning Musume
bryan
47
7.2k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2k
The World Runs on Bad Software
bkeepers
PRO
72
12k
Reality Check: Gamification 10 Years Later
codingconduct
0
2.2k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
9
1.4k
More Than Pixels: Becoming A User Experience Designer
marktimemedia
3
430
Transcript
Update Billion Records Kaigi on Rails 2023
Kaigi on Rails 2023 開催 🎉
• ⾃⼰紹介 • 課題と前提 • レコード更新チャレンジ • 学び 写真・画像 Agenda
写真・画像 Hiroki Tokutomi 株式会社TimeTree • CTO室所属、Backendチーム/SREチーム https://twitter.com/talkto_me https://github.com/ta1kt0me ⾃⼰紹介
写真・画像 • 簡単に予定を共有できる • カレンダーの中で気軽に相談できる スマホの中で⾒れる壁掛けカレンダー カレンダーシェアアプリ
None
begin
写真・画像 課題と前提
きっかけ IUUQTUJNFUSFFBQQDPNJOUMKBOFXTSPPNTIBSFEFWFOUDMPTF
👦 < ちょっとモデルの関連キー⾒直したいんだよね!
👦 < 新キーのカラムは追加してるよ!数⼗億件あるけど! 👦 < ちょっとモデルの関連キー⾒直したいんだよね!
👦 < 新キーのカラムは追加してるよ!数⼗億件あるけど! 👦 < ちょっとモデルの関連キー⾒直したいんだよね! 👦 < 少し前にも全件更新したし、いけるいける!
👦 < 新キーのカラムは追加してるよ!数⼗億件あるけど! 👦 < ちょっとモデルの関連キー⾒直したいんだよね! 👦 < 少し前にも全件更新したし、いけるいける!
整理してみる • 解消する価値のある技術的負債 • 対象は1テーブル、レコード数は50~60億 • 変更内容はデータを埋めるだけ • 作業の1年前に⼤体数⼗⽇かけて同じテーブルの全データ更新を実施 •
更新作業に時間がかかることはチームで認識している • 更新期間も安定してサービスを提供したい 要求
• Monolith Ruby on Rails • Sidekiq • AWS •
CloudFront • S3 • ECS • Aurora MySQL • DynamoDB • Elasticache for Redis • etc … Backend構成要素
以前はどうやってたの? 複数プロセス起動して並列に更新する • rails runner • grosser/parallel • zdennis/activerecord-import ⼤量データを⼀括で更新するバッチ処理でよく⾒かけるパターン
巨⼤テーブルでなければこのアプローチを使うことが多い • 更新対象の from/to • parallelで起動するプロセスの並列数
写真・画像 レコード 更新チャレンジ
Take 1. 前例踏襲
過去のアプローチに従ってみる • 複数プロセス更新での実⾏時間を計測したい • アプローチの課題を理解したい
結果 • 実⾏時間は約70分/1,000万件 • サービスへの影響はなかった • この時点で⼤きめのパフォーマンスチューニングはしていない 対象は⼤体500~600倍、実⾏し続ければ1ヶ⽉弱…?
⾒えてきた課題 更新対象の指定で処理時間のブレが⼤きい サービス成⻑に起因(後述) 更新処理をコントロールしづらい 実⾏状況を外部からモニタリングしづらい ⻑時間実⾏し続けることが難しい、けど⻑時間実⾏し続けたい • 環境の都合上リリースの度に中断 • スパイクが予測される状況で中断
課題を深掘り 更新対象の指定 • 処理対象のfrom/to にテーブルのidカラム(PK)の値を指定 • Idに Snow fl ake
ID を利⽤ • 64ビットの整数値、timestampに基づいて⽣成される時系列ソート済みのID • Twitter の TweetのIDで利⽤されていた • TimeTreeの場合、timestampにcreated_atを使っている • 1億件分更新したい場合、⼤体1億件分の期間の from, to をこのフォーマットに変換して指定 + ————— —————— ——— ——— — —— — —— — —— ——— — —— ——— — —— — —+ | timestamp (41ビット) | ゾーンID (10ビット) | シーケンス番号 (13ビット) | + ————— —————— ——— ——— — —— — —— — —— ——— — —— ——— — —— — —+ 例)timestampに “2020-01-01 00:00:00.000 UTC”、ゾーンIDに”10”、シーケンス番号に”1”を指定 10110111101011110011001101110100000000000 0000001010 0000000000001 => 13235854403174481921
更新期間の指定のムラ
改善アイデア 更新対象の指定で処理時間のブレが⼤きい from/toを⼀定の期間で分割、分割期間ごとに並列で処理する 更新処理をコントロールしづらい 更新処理をSidekiq Workerで処理する⾮同期ジョブにする • rails runner の実⾏環境の制限に依存しない
• 実⾏状況のモニタリングも容易
期間の分割⾒直し Ұఆͷظؒ5ͰJEΛׂ ىಈ#BUDIͷύϥϝʔλͱͯ͠ࢦఆՄೳ ظؒ5ΛฒྻͰॲཧ Take 1 改善案 ฒྻͰJEͷൣғΛׂ
Take 2.
Take 2 アイデア • 更新対象の from/to • 分割期間
Take 2 アイデアちょっと待って • 更新対象の from/to • 分割期間
⾮同期で更新 前提 • 通常のワークロードより優先度低 • データベースの負荷を抑えたい • 全件更新に時間がかかることは問題ない 制御したいこと •
workerあたりの実⾏時間 • Sidekiqクラスター全体での更新Job数 • 更新処理を全て停⽌するトリガー
全体像 ①rails runnerで起動処理実⾏ • 更新対象の from/to • 分割期間 • Jobの同時起動数
②from/toの分割リストをRedisにpush ④更新対象のfrom/toを pop、なければ終了 ⑤更新 ③⾮同期Jobを登録 ⑥⾮同期Jobを登録
全体像 ①rails runnerで起動処理実⾏ • 更新対象の from/to • 分割期間 • Jobの同時起動数
全体像 ①rails runnerで起動処理実⾏ • 更新対象の from/to • 分割期間 • Jobの同時起動数
②from/toの分割リストをRedisにpush
全体像 ①rails runnerで起動処理実⾏ • 更新対象の from/to • 分割期間 • Jobの同時起動数
②from/toの分割リストをRedisにpush ③⾮同期Jobを登録
全体像 ①rails runnerで起動処理実⾏ • 更新対象の from/to • 分割期間 • Jobの同時起動数
④更新対象のfrom/toをpop( ) ③⾮同期Jobを登録 ②from/toの分割リストをRedisにpush
全体像 ①rails runnerで起動処理実⾏ • 更新対象の from/to • 分割期間 • Jobの同時起動数
④更新対象のfrom/toをpop ⑤更新 ③⾮同期Jobを登録 ②from/toの分割リストをRedisにpush
全体像 ①rails runnerで起動処理実⾏ • 更新対象の from/to • 分割期間 • Jobの同時起動数
⑤更新 ⑥⾮同期Jobを登録 ③⾮同期Jobを登録 ④更新対象のfrom/toをpop ②from/toの分割リストをRedisにpush
全体像 ①rails runnerで起動処理実⾏ • 更新対象の from/to • 分割期間 • Jobの同時起動数
⑤更新 ⑥⾮同期Jobを登録 ③⾮同期Jobを登録 ④更新対象のfrom/toをpop ②from/toの分割リストをRedisにpush
全体像 ①rails runnerで起動処理実⾏ • 更新対象の from/to • 分割期間 • Jobの同時起動数
⑦更新対象のfrom/toをpop( ) ⑤更新 ③⾮同期Jobを登録 ⑥⾮同期Jobを登録 ②from/toの分割リストをRedisにpush
全体像 ①rails runnerで起動処理実⾏ • 更新対象の from/to • 分割期間 • Jobの同時起動数
⑦更新対象のfrom/toをpopできない ⑤更新 ③⾮同期Jobを登録 ⑥⾮同期Jobを登録 ②from/toの分割リストをRedisにpush
全体像 ①rails runnerで起動処理実⾏ • 更新対象の from/to • 分割期間 • Jobの同時起動数
⑧分割リストのデータを削除 ⑤更新 ③⾮同期Jobを登録 ⑥⾮同期Jobを登録 ②from/toの分割リストをRedisにpush
全体像 ①rails runnerで起動処理実⾏ • 更新対象の from/to • 分割期間 • Jobの同時起動数
⑧分割リストのデータを削除 ⑤更新 ③⾮同期Jobを登録 ⑥⾮同期Jobを登録 ②from/toの分割リストをRedisにpush
コンセプト: 起動処理
コンセプト: 更新ジョブ
結果 実⾏時間 実⾏時間は約40分/1,000万件(変更前の175%⾼速化) 実⾏し続ければ約2~3週間強 Take.1 の課題 実⾏中もリリース可能、問題があれば全処理停⽌可能 カスタマイズせず、Sidekiqの管理画⾯やAPMのメトリクスで実⾏状況を確認できる Workerごとの実⾏時間もパラメータによりある程度調整可能
早くなった、楽できた、はっぴー🎃
やりきった 🎉
写真・画像 学び
学び ⼤量データの変更には時間がかかる • ⻑期戦になるので関係者の理解が必要 • ⼩さなデータで簡単なことでも、後に回せば回すほどもっと⾟くなる ⼩さく試して進める • PoCのフィードバックサイクルを素早く回す •
可能であれば⼩さいデータセットから始め、少しずつ⼤きくして問題を捉えていく 選択肢を広げるためのinputの⼤切さ • 改善のヒントは様々な場所に潜んでいるので広く、深く探す • 前例や背景、変更対象や関連のドメインの把握、制限やトレードオフの理解、少数の異常データの存在
他の全件更新に適⽤できるか? 🙅 or 🙆 • 🙆 適⽤できたケースもある • 😰 変更対象が今回と同じでもさらにデータが増え続けたら…
• 🙅 READよりもWRITE(更新)が多いケースはLockが多発して使えなかった • 🧐 変更内容や対象の特性次第で前例に捉われずに考え続ける
end
⼀緒に最⾼のカレンダーサービス作りませんか?