Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Update Billion Records
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
ta1kt0me
October 27, 2023
Programming
5.5k
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
71
Running with version up
ta1kt0me
0
86
omotesandorb_8.pdf
ta1kt0me
1
430
Rubyでのプロファイリング
ta1kt0me
0
130
開発環境でdockerを使ってみた
ta1kt0me
0
470
Other Decks in Programming
See All in Programming
テストを司るデーモンに会いに行く 〜隔離した仮想マシンでテストを通すまで〜
h1d3mun3
1
560
AWS Step Functions 大規模並列の壁を越える / jaws-sonic-2026-niigata-step-functions
kasacchiful
PRO
1
510
AgentCore CLI で進化した AWS での AI エージェントの作り方 : 必要な機能を必要な時に
icoxfog417
PRO
3
370
Go × SIMDで高速化するベクトル検索 ~ルーフラインモデルでSIMDが効く境界を探れ! ~
po3rin
1
2.8k
一人だけ、Kiroが静止する日
hideg
0
130
選挙速報を多くのユーザーへ 届ける Live Activities 設計
hamayokokuririn
0
160
Snowflakeで業務アプリを作ろう。 Snowflakeのアプリ機能解説&実践ガイド
ayumu_yamaguchi
2
300
Building an Out-of-Order CPU
latte72
1
800
Family mrubyの進捗
kishima
1
130
WebMCP Challenge に星空観察アプリで参加した話
okajun35
0
190
マイコン向けの軽量Ruby「PicoRuby」で各種デバイスを制御するネイティブアプリの実現手法
bash0c7
0
440
【高い買い物LT会】初任給で話題の国産フィジカルAIを買った話
akagami
PRO
0
170
Featured
See All Featured
Designing Powerful Visuals for Engaging Learning
tmiket
1
580
30 Presentation Tips
portentint
PRO
1
400
Building a Scalable Design System with Sketch
lauravandoore
464
34k
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
74
42k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Test your architecture with Archunit
thirion
2
2.4k
The Language of Interfaces
destraynor
162
27k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6.1k
Chasing Engaging Ingredients in Design
codingconduct
0
320
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
480
Bridging the Design Gap: How Collaborative Modelling removes blockers to flow between stakeholders and teams @FastFlow conf
baasie
0
700
4 Signs Your Business is Dying
shpigford
187
23k
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
⼀緒に最⾼のカレンダーサービス作りませんか?