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
推し活の ハイトラフィックに立ち向かう Railsとアーキテクチャ - Kaigi on Ra...
Search
Hayato OKUMOTO
October 26, 2024
Programming
6
3k
推し活の ハイトラフィックに立ち向かう Railsとアーキテクチャ - Kaigi on Rails 2024
Hayato OKUMOTO
October 26, 2024
Tweet
Share
More Decks by Hayato OKUMOTO
See All by Hayato OKUMOTO
Angular x Auth0 複数サービス展開での認証基盤を考える
falcon8823
0
450
Angular Schematicsを利用した アプリ量産体制
falcon8823
0
84
iOSとIonicとHEIF画像
falcon8823
0
320
Ionicアプリのビルド自動化
falcon8823
0
19
Firebase Authentication - Ionic Meetup #12 Tokyo
falcon8823
0
250
IonicアプリをAuth0で認証する - Ionic Meetup #16 in Online
falcon8823
0
380
Other Decks in Programming
See All in Programming
Jakarta Concurrencyによる並行処理プログラミングの始め方 (JJUG CCC 2024 Fall)
tnagao7
1
290
ペアーズにおけるAmazon Bedrockを⽤いた障害対応⽀援 ⽣成AIツールの導⼊事例 @ 20241115配信AWSウェビナー登壇
fukubaka0825
6
1.9k
Less waste, more joy, and a lot more green: How Quarkus makes Java better
hollycummins
0
100
Streams APIとTCPフロー制御 / Web Streams API and TCP flow control
tasshi
2
350
3rd party scriptでもReactを使いたい! Preact + Reactのハイブリッド開発
righttouch
PRO
1
600
Duckdb-Wasmでローカルダッシュボードを作ってみた
nkforwork
0
120
Tauriでネイティブアプリを作りたい
tsucchinoko
0
370
エンジニアとして関わる要件と仕様(公開用)
murabayashi
0
280
最新TCAキャッチアップ
0si43
0
140
Quine, Polyglot, 良いコード
qnighy
4
640
NSOutlineView何もわからん:( 前編 / I Don't Understand About NSOutlineView :( Pt. 1
usagimaru
0
330
as(型アサーション)を書く前にできること
marokanatani
9
2.6k
Featured
See All Featured
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
506
140k
The Art of Programming - Codeland 2020
erikaheidi
52
13k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
44
6.8k
A Philosophy of Restraint
colly
203
16k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
31
2.7k
Building an army of robots
kneath
302
43k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
44
2.2k
It's Worth the Effort
3n
183
27k
Producing Creativity
orderedlist
PRO
341
39k
Agile that works and the tools we love
rasmusluckow
327
21k
A Modern Web Designer's Workflow
chriscoyier
693
190k
Making the Leap to Tech Lead
cromwellryan
133
8.9k
Transcript
2024年10月26日 推 し 活 の ハ イ ト ラ フ
ィ ッ ク に 立 ち 向 か う R a i l s と ア ー キ テ ク チ ャ 株式会社TwoGate 取締役CTO 奥本 隼
奥本 隼 (Hayato OKUMOTO) @falcon_8823 株式会社TwoGate 取締役CTO チーム組成から11年 / 創業8年
長野高専出身 Rails歴10年以上 自己紹介
Ruby Sponsor
TwoGateの主要なソリューション ライブイベント向け OEM型モバイルオーダーアプリ オンラインくじ ファンクラブアプリ チケットサイト 共通会員ID基盤 Shopify EC構築支援 多数のサービス展開
ライブエンタメ領域に対して、 コンパウンド戦略でサービスを複数展開 しています。
Caravan - イベント物販に特化したアプリ
特徴 サーバサイドはマルチテナント アプリはOEM型 1アーティスト=1アプリ 短納期での提供 内製向けローコード化 負荷対策に強い
事例 TwoGate inc. のApp Storeで一部配信されています。 累計220万DL / 100万ユーザ登録 エンタメ業界、事例を公開しにくい… TwoGateのブースでこっそりお教えします。
累計50アプリほど提供
きっと会場内にも ユーザがいるはず
技術スタック サーバサイド フロントエンド インフラ
Fastly インフラアーキテクチャ 実はシンプル+モノリシックなRailsアプリ ALB nginx nginx Rails App Aurora PostgreSQL
ElastiCache Redis (Cache) ElastiCache Redis (Queue) Sidekiq API Request Amazon ECS
ピークトラフィック CDN 50,000 RPS ALB / Rails 8,000 RPS 決済エンドポイント
400 RPS 先日660 RPSに記録更新
トラフィックに 耐えきれず 障害の経験も
Rails × ハイトラフィック 本発表のテーマ
推し活 × ハイトラフィック
ハイトラフィックに挑む設計 スロークエリをおこさないように実装 CDNでのキャッシュを活用する 後から導入ではなく最初から / CDNでキャッシュするエ ンドポイントは名前空間を切る アプリケーションキャッシュ(Redis)の活用 CDNでのキャッシュがどうしても難しいとき
この規模で起きる問題 DBレイヤーでのボトルネックから始まる インデックスの不足 / クエリが悪い / テーブル設計が悪い 実行計画が変わって急に遅くなることも 各種外部APIのレートリミットに引っかかる ピーク性能を出すパラメータチューニングが必要
ALBのスケーリングが間に合わずにエラーが発生する
どのように対処しているか Performance Insight / APMによる分析 アプリケーションログの分析 特定条件だけ遅いケース:ある商品だけ在庫が非常に多い 実行計画の解析 ChatGPTに投げ込むと便利 負荷試験
ChatGPTで実行計画を解析
先着販売 予告した日時に販売が開始する 在庫限りでの販売 受け取り時間枠選択→商品選択→カート→決済の流れ 本発表で扱うプロダクトの機能 ユーザが一同にアクセスし、在庫の奪い合いが始まる。
ライブエンタメでの販売の難しさ 在庫を綺麗に売り切りたい 在庫数を大幅に超過してはいけない 決済エラー等によって在庫が浮いたままではいけない ピークトラフィックでサーバダウンできない レスポンスタイムの悪化はユーザの不満になる
本発表で扱うテーマ 本発表では、次の2つのテーマについて取り扱います。 高スループットかつ正確な在庫確保のアーキテクチャ 外部決済APIのレートリミットとの向き合い
在庫確保 × パフォーマンス Part.1
在庫確保の簡易な実装 商品ID 在庫数 販売数 P1 100 20 P2 150 10
P3 50 30 在庫テーブル 商品P1を10購入 UPDATE 在庫テーブル SET 販売数 = 販売数 - 10 WHERE 商品ID = P1;
在庫確保の簡易な実装 商品ID 在庫数 販売数 P1 100 10 P2 150 10
P3 50 30 在庫テーブル 商品P1を10購入 UPDATE 在庫テーブル SET 販売数 = 販売数 - 10 WHERE 商品ID = P1; SQLでトランザクションを 学ぶ題材でよく出てくる実装
在庫確保の簡易な実装 商品ID 在庫数 販売数 P1 100 20 P2 150 10
P3 50 30 在庫テーブル 商品P1を10購入 UPDATE 在庫テーブル SET 販売数 = 販売数 - 10 WHERE 商品ID = P1; 同時に購入者がいると… 商品P2を20購入 UPDATE 在庫テーブル SET 販売数 = 販売数 - 20 WHERE 商品ID = P2;
在庫確保の簡易な実装 商品ID 在庫数 販売数 P1 100 -10 P2 150 10
P3 50 30 在庫テーブル 同時に購入者がいると… 在庫数を確認したタイミングと 更新するまでの間に更新が走れ ば、在庫数を超過する。 解決策 行ロックを導入する
在庫確保の安全な実装 商品ID 在庫数 販売数 P1 100 20 P2 150 10
P3 50 30 在庫テーブル 商品P1を10購入 BEGIN; SELECT * FROM 在庫テーブル WHERE 商品ID = P1 FOR UPDATE; -- ここで在庫数 > 販売数を確認 UPDATE 在庫テーブル SET 販売数 = 販売数 - 10 WHERE 商品ID = P1; COMMIT;
行ロックを掛けることで正確な数量の販売ができるように しかし、 数百RPSでの在庫確保のワークロードでは… 同じ行を更新するユーザが多数いる ロックの奪い合いでロック待ち, デッドロックが頻発する 在庫確保の安全な実装
ロック競合を回避するには =同じデータを同時に書き換えないような構造に変更する 次の疑問 どうやって行を奪い合わないようにすればよい?? 同じ行を同時に書き換えるから競合する
在庫テーブルの設計を変える 在庫ID 商品ID ユーザID Z1 P1 Z2 P1 Z3 P1
Z4 P1 在庫テーブル 1行1在庫のテーブルに変える 順番に排出できれば、競合を回避 できるはず。 どのように実装する??
FOR UPDATE SKIP LOCKED これを対処する実装は非常に シンプル 行ロックされている行をスキ ップした結果を応答してくれ る PostgreSQL
9.5~ MySQL 8.0~ BEGIN; SELECT * FROM 在庫テーブル WHERE 商品ID = P1 LIMIT 4 FOR UPDATE SKIP LOCKED; -- ここで行数 = 購入数を確認 UPDATE 在庫テーブル SET ユーザID = Ua WHERE 商品ID = P1; COMMIT;
在庫テーブルの設計を変える 在庫ID 商品ID ユーザID Z1 P1 Z2 P1 Z3 P1
Z4 P1 在庫テーブル ユーザUaがP1を2行取得&ロック 1. ロックが無い2行取得 SELECT * FROM 在庫テーブル WHERE 商品ID = P1 LIMIT 2 FOR UPDATE SKIP LOCKED;
在庫テーブルの設計を変える 在庫ID 商品ID ユーザID Z1 P1 Z2 P1 Z3 P1
Z4 P1 在庫テーブル 2. ユーザUbがP1を3行取得 SELECT * FROM 在庫テーブル WHERE 商品ID = P1 LIMIT 3 FOR UPDATE SKIP LOCKED; Uaがロックしている行をスキップ Z3,Z4の2行だけを返す 足りないので在庫不足で扱う
高スループットでの在庫確保が可能に 行ロックされていない行を必ず返答する保証がある 競合することがなくなり、実測で数百TPSでの処理が可 能に 【余談】Solid QueueはDBをバックエンドにしているが、 同様にFOR UPDATE SKIP LOCKEDを使って実現してい
る
在庫処理まとめ 1在庫1行のデータ構造で管理する 欠点としてテーブルが肥大化するが、販売が終わったら 消すことで解消 FOR UPDATE SKIP LOCKEDで競合を回避する 数百TPSの注文処理を捌ける 先日は200万在庫のテーブルで運用し問題無く捌いた
決済 × パフォーマンス Part.2
前提 クレジットカード決済には外部のペイメントプロバイダを利用 非通過、非保持化のため 決済関連のAPIレートリミットは20-30 rps程度 stripeでもデフォルトは100 rps 決済会社との交渉や料率の交渉が必要 そもそも400 rps近くまでの緩和は厳しい
与信確保 (オーソリ) 決済と在庫確保の流れ 決済できずに宙に浮く在庫を無くすため、この流れで実装。 在庫確保 売上確定 与信開放 (キャンセル) 在庫OK 在庫NG
売り切れた在庫が復活すると、タイミングと件数 によってはクレームが発生するため。
本当にあった怖い話 与信確保→在庫確保→売上確定 売上確定時にレートリミットエラー→ロールバック 奇跡的に与信確保できた人でも、 売上確定時にレートリミットエラー 結局、ほとんど誰も買えない事態に。
じゃあどうする? そもそも、決済プロバイダのレートを上げることができない 非同期にして後から決済を通知する? 待機してもらう?
諦めて待機してもらう いずれにせよ、 解決しない問題なので 諦めました
正しく諦める 決済システムの限界よりもリクエストを受け付けな いようにする これ以上捌けないのに処理を発行しない レートリミットを導入
レートリミットの実装 CDN/WAFで対応する? 正確性や条件制御が単純なため不採用 お高いプランにするとできたりする 正確なレートリミットのためにRedisで自作
決済×パフォーマンスまとめ コロンブスの卵的な対応だが… 限界に対して正しく向き合うことは大事 負荷試験で外部APIをモックするときはレートリミ ット時の挙動も考慮すること
最後に… Railsでハイトラフィックを捌いている事例をお伝 えしました TwoGateはライブエンタメ業界に全方位プロダク トを展開していきます
ASK THE SPEAKER 以下の場所で質疑をお受け付けします! TwoGate企業ブース FREE AFTER PARTY by TWOGATE
& KOMOJU 本日19時開催 『推し活のハイトラフィックに立 ち向かうRailsとアーキテクチャ』 【登壇者】取締役CTO 奥本 『Type on Rails: Railsアプリ ケーションの安全性と開発体験を 型で革新する』 【登壇者】エンジニア 村田 Speakers
None