📝ノート💻テック

システムデザイン面接:Ticketmaster設計(元Meta Staff Engineer)

Tony Duong

Tony Duong

6月 5, 20262

他の言語:🇫🇷🇬🇧
#system-design#ticketmaster#interview#consistency#elasticsearch#redis
システムデザイン面接:Ticketmaster設計(元Meta Staff Engineer)

Hello Interview(元Meta staff engineer)によるTicketmaster風チケット予約サービス設計のメモ — Metaのプロダクトデザイン面接・システムデザイン面接で頻出の問題。

面接のロードマップ

  1. 要件(機能要件 + 非機能要件)
  2. コアエンティティ + API
  3. 高レベル設計(機能要件を満たす)
  4. 深掘り(非機能要件を満たす)

要件は約5分以内に収める。

機能要件

  • ユーザーがイベントを検索できる
  • ユーザーがイベントを閲覧できる(詳細、座席マップ、空きチケット)
  • ユーザーがチケットを予約できる

非機能要件(文脈に即した記述)

「スケーラビリティ」「可用性」を並べるだけでなく、このシステムが難しい理由を説明する。

懸念 Ticketmaster固有のフレーミング
一貫性 vs 可用性(CAP) 予約は強い一貫性 — 二重予約なし(1席、1ユーザー)。検索・閲覧は高可用性 — 新イベントが数秒遅れて表示されてもOK
読み取り/書き込み比率 約100:1(閲覧が多く購入は少ない;約1%のコンバージョン)
スケーリング 汎用的なスケールではなく — 人気イベントによる急増(Taylor Swift、Super Bowl、ワールドカップ)
低レイテンシ検索 フルテーブルスキャンは通用しない

スコープ外(線の下に記載):GDPR、汎用的な障害耐性の詳細など — 面接官と優先度を確認する。

コアエンティティ

  • Event(会場、出演者、メタデータ、チケットとの関係)
  • Venue(場所、座席マップ)
  • Performer
  • Ticket(座席、価格、ステータス、event FK)

まずエンティティ名から始め、設計が進むにつれてフィールドを詳細化する。

API

イベント閲覧

GET /events/{eventId} → イベント、会場、出演者、チケット一覧(座席マップ用)

検索

GET /search?term=&location=&type=&date=...部分的なイベント一覧(結果表示に十分;詳細は閲覧エンドポイント経由)

予約(2フェーズ — 実際のTicketmasterと同様)

  1. Reserve: POST /booking/reserve — ボディ: ticketId のみ;ユーザーはJWT/ヘッダーから取得、ボディには含めない(セキュリティ)
  2. Confirm: PUT/PATCH /booking/confirmticketId + 支払い詳細 → Stripe(成功時にwebhookコールバック)

Reserveはユーザーが支払いを完了するまで約10分間座席を確保する。

高レベルアーキテクチャ

ClientAPI Gateway(認証、レート制限、ルーティング)→ マイクロサービス:

サービス 役割
Event CRUD イベント閲覧、座席マップデータの読み込み
Search イベント発見
Booking Reserve + confirm

PostgreSQLをプライマリストレージに — リレーション(event → tickets)、予約の正確性のためのACIDトランザクション。面接ではSQL vs NoSQLの議論は弱い;必要な品質(トランザクション、チケットの一貫性)に焦点を当てる。PostgresでもDynamoDB + トランザクションでも成立しうる。

チケットステータス: available | reserved | booked(予約済み時はユーザーID付き)

Stripeで支払い(非同期;bookedにマークする前にwebhookで成功を確認)。

予約期限 — 重要な設計判断

問題: ユーザーが予約後、支払いを放棄 — 座席がreservedのまま永遠にロックされる。

ミドルレベル: タイムスタンプ + クエリまたはcron

  • reserved_timestampを追加;10分超のreservedを空きとして扱うクエリ
  • または約10分ごとのcronで古い予約をリセット

欠点(シニアとの差): cronは遅延nを導入 — 座席が10分を過ぎてもcron間隔分ロックされ続ける可能性(例: 合計19分)。

シニア: Redis分散ロック + TTL

  • 予約時: Postgresのステータスは更新しない — RedisにticketIdTTL = 10分で設定
  • 座席マップ表示時: availableチケットをクエリし、Redisロックに存在するIDを除外
  • TTL期限切れ → 座席は自動的に空きになる(cron遅延なし)
  • 複数のbookingサービスインスタンスが一貫したロックビューを必要とするため、Redisは別途用意

Redis障害時: 二重予約の試行が可能になる短いウィンドウ;PostgresのACIDはconfirm時に依然として1人の勝者を保証 — 敗者にとっては悪いUXだが、プロダクトと議論すべき許容可能なトレードオフ。

深掘り

低レイテンシ検索 — Elasticsearch + CDC

初期設計: SQL LIKEワイルドカード → フルテーブルスキャン — 遅すぎる。

Elasticsearchで転置インデックスによるテキスト検索;位置情報用のジオスペーシャルサポート。

ESをプライマリストアにしない(耐久性、トランザクション)。Postgresから同期:

  • アプリコードでのデュアルライト(部分障害の処理)、または
  • CDC → ストリーム → ES更新(面接でよくある回答;イベント/会場はめったに変わらない — キュー不要)

人気検索のキャッシュ:

  • OpenSearchノードのクエリキャッシュ
  • 検索語をキーにしたRedis
  • CDNGET /searchを約30–60秒キャッシュ(同一クエリパラメータで有効;パーソナライズされたランキングや緯度経度のような高カーディナリティパラメータでは機能しない)

リアルタイム座席マップ + 急増対応

古い座席マップ: ユーザーがページを読み込み;数秒で座席が売り切れる → クリックでエラー表示。

選択肢:

  • Long polling — 安価、ページ上の短いセッションに適する
  • SSE (Server-Sent Events) — サーバーが座席更新をクライアントにプッシュ(一方向;ここでは十分)。WebSocketsも可能だが過剰。

人気イベント: ページ読み込み、座席が即座に消える — 悪いUX。

仮想待機キュー(Redis sorted setで到着時刻順、または公平性のためランダム):

  • 数百万人が同時アクセス → イベントページではなくキュー入りメッセージを表示
  • キャパシティに応じてバッチでユーザーを解放(例: 予約された座席数ごと)
  • 入場許可時にSSEで通知 → その後予約

シンプルで創造的な絞り込みポイント — 常に最も複雑な技術である必要はない。

読み取りのスケーリング

  • API Gateway + サービスは水平スケール(マネージドLB)
  • イベント/会場/出演者をRedisにキャッシュ(めったに変わらない) — 閲覧APIは動的チケットのみDBにアクセス
  • 計算で必要と判明したらPostgresをシャーディング(シャードキーの議論: 地理的にはeventId vs venueId

計算のコツ: 結果が設計を変える場合にのみバックオブザベンベロープ見積もりを行う — 最初のチェックボックス作業ではない。

DDIAとの関連

Designing Data-Intensive Applicationsを想起させるパターン:

  • 派生データ — 正(ソースオブトゥルース)から維持されるElasticsearchインデックス(Ch. 11 CDC、データ統合)
  • ログ/ストリーム — OLTP DBからの変更ストリームとしてのCDC
  • 一貫性 — ビジネスが要求する箇所では強い保証(予約)、許容できる箇所では緩和(検索)
  • キャッシュ — ホットパスで鮮度と読み取りレイテンシのトレードオフ

要点

  • 二重予約の防止予約パスの強い一貫性を駆動;検索/閲覧は可用性を優先できる
  • 2フェーズ予約(reserve → 支払い → confirm)は標準;APIをそれに合わせて設計する
  • Redis TTLロックは10分ホールドにcronより優れる — シニアとの差別化ポイント
  • 検索にはElasticsearch + CDC;Postgresとのデュアルプライマリではない
  • セレブイベント急増には仮想待機キュー
  • 座席マップの鮮度と読み取り偏重トラフィックにはSSE + キャッシュ
  • 非機能要件は汎用バズワードではなく問題の文脈で具体化する

🌐 Claudeによる翻訳

Tony Duong

著者: Tony Duong

デジタル日記。思考、経験、そして人生についての考え。