概要
Shopifyの 在庫予約システム は、Black Friday 2025のピーク時に $5.1M/分の売上 を処理。 RedisからMySQLへの移行で ACIDトランザクション による一貫性とスケーラビリティを実現。 SKIP LOCKED を活用した一行一単位の設計と、1,000行上限のプール方式を導入。 ボトルネックはCPUではなく DB接続数 であると判明し、接続管理の可視化で解決。 段階的な切り替えと徹底した検証で、信頼性とパフォーマンスを両立。
Shopifyの在庫オーバーセル保護システムの進化
- オーバーセル保護 は、購入完了時に商品がまだ購入可能かを保証する仕組み
- 誤判定による 二重販売 や 販売機会損失 を防止
- Black Friday 2025では 過去最高のトランザクション数 を記録
- すべての取引で 在庫管理システム が関与
オーバーセル保護の主な処理
- Reserve :支払い開始時に在庫を一時的に予約
- Claim :支払い成功時に在庫台帳から数量を恒久的に差し引き
- 予約の 速度と正確性 が購入体験と売上に直結
システム要件
- 高スループット対応 :ピークトラフィックでもリクエストを落とさない
- 複数ロケーション対応 :発送可能な拠点からのみ予約
- ACID保証 :予約と台帳間で一貫性維持
- 正確性最優先 :オーバーセル・アンダーセルの排除
Redisモデルの限界とMySQL移行
- 旧システムは Redis を利用し、DECR/INCRで在庫を管理
- 予約と台帳が分離 し、原子的な同時更新が困難
- オーバーセルやアンダーセル を引き起こすリスク
- マルチロケーション非対応、Redis運用コストも課題
- MySQL統合 でACIDトランザクション・シングルシステム運用へ
MySQLでのSKIP LOCKED設計
- 一商品一行 から 一単位一行 へ設計変更
- 例:在庫10個なら10行で管理
- SKIP LOCKED で同時予約時の競合を回避しスケーラブルに
- 1,000行上限のプール 方式を採用
- プール枯渇時はインラインで補充
- 補充時はロック でスロットル、スローレスポンスだが正確性を担保
主要な技術的工夫
- 複合主キー でロック数削減
- shop_id, inventory_item_id, inventory_group_id, id の組み合わせ
- READ COMMITTED でギャップロック回避
- REPEATABLE READから変更し、デッドロック防止
- ロック取得順序統一 でデッドロック解消
- 予約・確定処理でテーブル操作順を標準化
- UNION ALLによるバッチ処理 でDBラウンドトリップ削減
真のボトルネック:DB接続数
- CPUやクエリ最適化 後もスループットが頭打ち
- 接続数枯渇 が主因と判明
- 各SQLに コメントタグ でビジネスプロセスを明示
- ProxySQL でタグごとに接続保持時間を可視化
- 接続時間の多いプロセス を特定し最適化
- checkout pathの見直し でDB負荷半減
- InnoDBスレッド並列度 も現状に合わせて最適化
安全な切り替えと検証
- RedisとMySQLの並行運用 (シャドウモード)で安全性担保
- 双方に書き込みつつRedisを正として比較検証
- 問題発生時は キルスイッチ で即時リバート可能
- 段階的ロールアウト でリスク最小化
得られた教訓
- 過去の設計判断の見直し の重要性
- ボトルネックの真因 を正しく特定・可視化することの価値
- DB設計・運用・監視 の細部が大規模ECの信頼性を左右
まとめ
- 在庫予約の正確性とスケーラビリティ は、ECプラットフォームの根幹
- MySQLの新機能と設計工夫 でRedis時代を超える性能・一貫性を実現
- 運用・監視の改善 がシステム進化の鍵