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
7
4.8k
推し活の ハイトラフィックに立ち向かう 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
520
Angular Schematicsを利用した アプリ量産体制
falcon8823
0
110
iOSとIonicとHEIF画像
falcon8823
0
340
Ionicアプリのビルド自動化
falcon8823
0
27
Firebase Authentication - Ionic Meetup #12 Tokyo
falcon8823
0
270
IonicアプリをAuth0で認証する - Ionic Meetup #16 in Online
falcon8823
0
390
Other Decks in Programming
See All in Programming
15分で学ぶDuckDBの可愛い使い方 DuckDBの最近の更新
notrogue
3
490
5分で理解する SOLID 原則 #phpcon_nagoya
shogogg
1
300
Boos Performance and Developer Productivity with Jakarta EE 11
ivargrimstad
0
290
Better Code Design in PHP
afilina
0
170
Ça bouge du côté des animations CSS !
goetter
2
150
新宿駅構内を三人称視点で探索してみる
satoshi7190
2
120
pylint custom ruleで始めるレビュー自動化
shogoujiie
0
150
DRFを少しずつ オニオンアーキテクチャに寄せていく DjangoCongress JP 2025
nealle
2
260
ML.NETで始める機械学習
ymd65536
0
230
ナレッジイネイブリングにAIを活用してみる ゆるSRE勉強会 #9
nealle
0
150
Flutter × Firebase Genkit で加速する生成 AI アプリ開発
coborinai
0
170
Rails アプリ地図考 Flush Cut
makicamel
1
130
Featured
See All Featured
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.1k
How STYLIGHT went responsive
nonsquared
98
5.4k
Large-scale JavaScript Application Architecture
addyosmani
511
110k
Designing Experiences People Love
moore
140
23k
RailsConf 2023
tenderlove
29
1k
Optimizing for Happiness
mojombo
376
70k
Making the Leap to Tech Lead
cromwellryan
133
9.1k
Done Done
chrislema
182
16k
GraphQLの誤解/rethinking-graphql
sonatard
68
10k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
47
5.2k
Bash Introduction
62gerente
611
210k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
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