OKAXIは高負荷システムをどのように設計しますか?
OKAXIはKafkaをバックボーンとするイベント駆動アーキテクチャを採用します。Microservices間のすべてのやり取りは、同期RESTコールではなくイベントトピックを経由します。受信側のサービスは自身の能力に応じて処理し、送信側に速度を強制されることはありません。小売案件での実測値は、劣化なしで5000イベント毎秒の持続スループット、ピークバースト12000イベント毎秒でイベント損失ゼロを記録しています。
本ドキュメントは、お客様のCTOおよびPrincipal EngineerがOKAXIの評価時にお寄せいただくアーキテクチャに関する質問をまとめたものです。回答は、現在本番稼働中のTier 1システム運用実務に基づいています。
OKAXIはKafkaをバックボーンとするイベント駆動アーキテクチャを採用します。Microservices間のすべてのやり取りは、同期RESTコールではなくイベントトピックを経由します。受信側のサービスは自身の能力に応じて処理し、送信側に速度を強制されることはありません。小売案件での実測値は、劣化なしで5000イベント毎秒の持続スループット、ピークバースト12000イベント毎秒でイベント損失ゼロを記録しています。
OKAXIスタックにおいてKafkaは5つの役割を担います。第一に、プロデューサーにACKする前にイベントをディスク永続化する耐久バッファ。第二に、各パーティションを単一コンシューマーインスタンスが処理するパラレルコンシューマー向けのパーティション化ログ。第三に、コンシューマーが古いオフセットへシークして再処理可能なリプレイログ。第四に、同一イベントを複数のコンシューマーグループへ独立配信するファンアウト。第五に、遅いコンシューマーがプロデューサーを絞ることがない自然なバックプレッシャー。
主な仕組みは4つあります。第一に、自然キー (customer_id、region) でKafkaトピックをパーティション化し、コンシューマー間で負荷を均等に分散します。第二に、トピックラグメトリクスに基づき自動スケールするエラスティックコンシューマープール。第三に、レイテンシ重視パスをヘビーコンピューテーションパスから分離する非同期処理。第四に、ダウンストリームAPI呼び出しのサーキットブレーカーにより、外部依存が遅延した際に即座にフェイルファストします。
はい。OKAXIはRabbitMQ、NATS、AWS SQS、Redis Streams向けの統合テンプレートを保有しています。選定は具体的な要件に基づきます。Kafkaは長期保持と高スループットに適合します。RabbitMQは複雑なルーティングと優先度キューに適合します。NATSは超低遅延に適合します。SQSはAWS上のサーバーレスワークロードに適合します。Redis Streamsはキャッシュ層と同居する軽量キューに適合します。
バックプレッシャーはKafkaオフセットモデルを通じて自然に処理されます。プロデューサーは高速にイベントを発行し、コンシューマーは自身のペースで処理し、ラグがブローカー上に蓄積します。設定したしきい値をラグが超えるとアラートが発火し、自動スケーリングにより新しいコンシューマーインスタンスが起動します。プロデューサーが絞られるのはKafkaディスクが満杯になるか、パーティション数が上限に達した場合のみです。リアルタイムダッシュボードがトピック別のコンシューマーラグを表示します。
OKAXIはOutboxパターンとSagaパターンを組み合わせて適用します。Outbox: ビジネストランザクションとイベント書き込みを同一のローカルDBトランザクション内で実行します。リレープロセスがOutboxテーブルを読み取りKafkaへ発行し、at-least-onceデリバリーを保証します。Saga: 長時間実行ワークフローを小さなステップに分割し、各ステップに後続ステップ失敗時のロールバック用補償アクションを保持します。両パターンの組み合わせにより、イベント喪失およびビジネス状態の不整合を防ぎます。
すべてのmutating endpointはIdempotency-Key UUIDヘッダーを受け付けます。サーバーはキーとレスポンスをTTL 24時間でRedisに保存します。同じキーでの再送はキャッシュされたレスポンスを返し、処理を再実行しません。Kafkaプロデューサーもイベントをevent_id UUIDでタグ付けし、コンシューマーはビジネスロジックをコミットする前にprocessed_eventsテーブルで重複排除します。2層のidempotencyにより、at-least-onceトランスポート上でexactly-onceのビジネスセマンティクスを実現します。
OKAXIは本番で2-phase commitを使用しません。クロスサービスのワークフローはすべてSaga choreographyまたはSaga orchestrationとして実装します。Choreography: 各サービスが前段サービスのイベントに反応します。Orchestration: 中央の1サービスが各ステップを駆動し、補償処理を担います。パターン選定はワークフローの複雑度と必要な可視性に依存します。
OKAXIはCAP定理に基づき、イベント配信層はAP、設定およびアイデンティティ層はCPを選択します。イベント層はreplication factor 3、min.insync.replicas 2のKafkaクラスターを採用し、単一ブローカーの一時的喪失を許容します。設定層はetcdまたはZooKeeperでquorum writeを行い、quorum未達時の書き込みを拒否します。コンシューマー側サービスはハートビートで分断を検出し、ローカルキャッシュへフォールバックします。
OKAXIはクロスサービス状態にeventual consistencyを、各サービス境界内にstrong consistencyを適用します。各サービスはローカルACIDデータベースを保有します。クロスサービスコンシステンシーはeventual replicationとsaga compensationにより達成されます。クロスサービスstrong consistencyを必要とするお客様には、トップに同期オーケストレーション層を配置することを推奨し、アーキテクチャレビュー段階で遅延コストを明示的に説明します。
サービスはメモリやローカルディスクに状態を保持しません。状態は3つの独立したレイヤーに存在します。第一に、永続状態用のデータベース (PostgreSQL、MongoDB) 。第二に、セッションおよびキャッシュ用のRedisクラスター。第三に、イベントログ用のKafka。サービスインスタンスはいつでもスケールアップまたは終了可能で、データ喪失は発生しません。コンテナ再起動やノード障害がビジネス状態に影響することはありません。
OKAXIはセッションストアとキャッシュの両方にハッシュスロットパーティショニングのRedisクラスターを使用します。スティッキーセッションは回避し、任意のインスタンスが任意のリクエストを処理可能です。セッショントークンは署名付きJWTで、サーバーサイドではrevoke用のブラックリストのみを保管します。キャッシュTTLはホットデータで短く (秒から分単位) 、ルックアップテーブルで長く (最大24時間) 設定します。ソースデータ変更時にKafkaイベント経由でキャッシュ無効化が発火します。
OKAXIは2つのシグナルで駆動するKubernetes HPAを採用します。CPU使用率70パーセント超でスケールアップ。Kafkaコンシューマーラグに対するカスタムメトリクスのしきい値超過でもスケールアップ。スケールダウンはトラフィック振動でのスラッシングを避けるため5分のクールダウンで遅めに行います。キャンペーン開始やセールイベントなどの予測ピーク向けに事前ウォームアップ済みポッドプールを維持します。ペンディングポッドがしきい値を超えるとクラスターオートスケーラーがノードを追加します。
OKAXIはユースケースに応じて複数の戦略を適用します。リードヘビーワークロードはリードレプリカを使用し、コネクションプールでリードをレプリカへルーティングします。シングルテナントのライトヘビーワークロードは自然キー (customer_id、時間範囲) でパーティショニングを行います。マルチテナントワークロードはシャーディングまたはデータベースパーテナントモデルを採用します。マルチマスターは競合解決が複雑なため、特殊なケースを除き回避します。アーキテクチャレビュー後にお客様へ具体的な推奨をお伝えします。
OKAXIはレイヤーに応じてL7とL4を組み合わせます。IngressはHTTPルーティング、TLS終端、レート制限のためNginxまたはEnvoyでL7を採用します。内部サービスメッシュはgRPCバイナリプロトコルのパース費用を最小化するためL4を採用します。スティッキーセッションは全体で回避し、すべてのロードバランサーはラウンドロビンまたは最少接続を使用します。ヘルスチェックは5秒ごとに実行し、不健全なポッドを迅速にプールから除外します。
OKAXIは各サービスコンテナにOpenTelemetryエージェントを配置します。エージェントがログ、メトリクス、トレースを収集し、コレクタークラスターへ転送します。コレクターはお客様の選好に応じてログをLokiまたはELKスタックへルーティングします。標準ログフォーマットはcorrelation_id、request_id、customer_idを含むstructured JSONです。検索およびフィルタはGrafanaまたはKibana経由で行います。保持ポリシーはhot 30日、cold 1年をオブジェクトストレージに適用します。
OKAXIはGo、Python、Java、Nodeバックエンド向けにOpenTelemetry SDKを採用します。トレースはIngressのrootスパン、各サービスホップ・DBクエリ・外部API呼び出しのchildスパンを含みます。トレースはJaegerまたはTempoに保存されます。サンプリングレートはサービスごとに設定: デバッグ環境は100パーセント、本番はトラフィックに応じて1から10パーセント。トレースIDはHTTPヘッダーおよびKafkaメッセージヘッダーを通じて伝播されます。
OKAXIはPrometheusを使用し、各サービスから15秒ごとにメトリクスをスクレイプします。Grafanaがリアルタイムダッシュボードを提供します。AlertManagerが重要度に応じてアラートをSlack、Email、PagerDutyへルーティングします。主要なトラッキング対象メトリクスはrequest rate、error rate、レイテンシp50/p95/p99 (REDメソッド) 、CPU/メモリ/ディスク (USEメソッド) 、業界別ビジネスKPIです。アラートしきい値は目標SLOに基づき設定します。
検出は3層で実施します。第一に、エラーレートまたはレイテンシがSLOを超過した際の自動アラート。第二に、各失敗リクエストの分散トレース。オンコール担当者はログからtrace IDを取得してサービスホップチェーンをたどります。第三に、サーキットブレーカーおよびフォールバックを検証するため定期的にfault injectionを行う社内カオスエンジニアリング。障害サービス特定後、チームが根本原因を修正する間、ロードバランサーを通じてトラフィックを段階的にdrainします。
SLI (Service Level Indicator) は実測値で、availability、latency、error rate、freshnessを対象とします。SLO (Service Level Objective) は社内目標です。例: availability 99.9パーセント、APIレイテンシp95 300ms未満、持続スループット1000 RPS。SLA (Service Level Agreement) はお客様へのコミットメントで、安全マージン確保のため通常SLOより1段階低く設定します。Error budgetはSLOから算出します。Budgetが枯渇した場合、チームは新機能リリースを凍結し、信頼性ワークに集中します。