免責事項。 この記事はStripeの公開コミュニケーション(エンジニアリングブログ、カンファレンストーク、オープンソースリポジトリ、外部ケーススタディ)のみに基づいています。Stripeの公式アーキテクチャドキュメントではありません。複雑なスタックがC4モデルでどのようにreadableになり得るかを示すために、公開されている内容をモデリングしています。詳細がStripeの主張ではなく推論である場合はその旨を明記します。

Chargeの解剖学:StripeをC4でArchylにモデル化する

POSTリクエストがブラックフライデーの午前3時太平洋時間にStripeに到達します。20秒後、マーチャントは入金され、cardholderの発行銀行はchargeを承認し、ファンドはsettlementのキューに入り、マーチャントのサーバーは署名付きwebhookを受け取り、Stripeのリスクエンジンは100ミリ秒未満でトランザクションをスコアしました。

その単一のリクエスト、BFCM 2024のピークで毎秒27,395回繰り返されるそれは、フレーム0がマーチャントのダッシュボードに届く前に14のStripeシステムと少なくとも4つの外部ネットワークを横断します。

2025年、Stripeはこのスタックを通じて1.9兆ドルを処理し、ブラックフライデー中に99.9999%のアップタイムを維持しました — シックスナイン、年間32秒のダウンタイムに相当します。これを約1500万行のRuby、自社製の型システムで型チェックされたもの、で実現しました。

インターネットの半分のクレジットカード決済を動かすスタックをどう理解するか?Netflixと同じく、一度には理解できません。それこそがC4モデルが解決するために発明された問題です。

この投稿では、1つのユーザーアクション(stripe.PaymentIntents.create()の呼び出し)を追って、それが4つのC4レベルにわたってStripeのアーキテクチャを横断するのを見ます。すべての製品をカバーするわけではありません。1つのchargeを追跡し、途中で出会う選択を説明するADRを書き、各ボックスを所有するチームのマップで終わります。

レベル1 — System Context:15の製品、1兆ドル

Stripe C4 System Context: 15システム、外部アクター

System ContextレベルではStripeは「決済API」ではありません。基盤を共有する15の異なる製品システムです:

  1. Payments — 歴史的なコア:charges、payment intents、refunds、payouts
  2. Connect — マルチパーティ決済、マーケットプレイス、プラットフォーム
  3. Billing — サブスクリプション、請求書、従量課金
  4. Atlas — Delaware C-Corp/LLCの法人化
  5. Capital — マーチャント向け融資
  6. Issuing — 仮想・物理カードの作成
  7. Treasury — banking-as-a-service(Goldman Sachsパートナーシップ)
  8. Identity — KYC/KYB検証
  9. Tax — 売上税、VAT、GST
  10. Climate — トランザクションごとのカーボンオフセット
  11. Radar — 機械学習による不正検知(100ms未満のスコアリング)
  12. Sigma — Stripeデータ上のSQL分析
  13. Terminal — POSハードウェア
  14. Financial Connections — 銀行口座リンク(Stripeなりのプラッド)
  15. Apps Marketplace — Dashboard上のサードパーティアプリ

その周りに:マーチャント、cardholders、4つのカードネットワーク(Visa、Mastercard、Amex、Discover)に加えて地域的なもの(JCB、UnionPay)、100以上の代替決済方法(Apple Pay、Klarna、ACH、SEPA、iDEAL...)、acquiring・issuing銀行、銀行パートナー(Goldman Sachs、Evolve、Cross River)、税務当局、ID検証プロバイダー、そして基盤クラウドのAWS(モノクラウド)。

15のシステム、8カテゴリの外部アクター。それ以外はすべて詳細です。

これがレベル1の贈り物です:System ContextではPaymentsが20のマイクロサービスであることを知る必要はありません。それが存在し、カードネットワークと話し、ConnectがTreasuryと連携し、AWSがすべてを支えていることを知る必要があるだけです。図は会話の起点であり、インベントリではありません。

ADR-001 · 1日目からAPIにIdempotency keysを組み込む

ステータス · Accepted (2011年、2026年も依然アクティブ)

コンテキスト · ネットワークは信頼できません。失敗したPOST /chargesを再試行するマーチャントは顧客に二重課金する可能性があります。2011年の業界の答えは*「マーチャントがそれを処理すべき」* — 分散システムの複雑さをすべてのAPIコンシューマーに押し付けるものでした。

決定 · ミューテーションを伴うすべてのAPI呼び出しにIdempotency-Keyを要求する。キー、リクエストハッシュ、レスポンスを保存する。再試行時、キーが一致すれば保存されたレスポンスをreplay。オプトインではなく、APIのファーストクラスの一部としてシップ。

結果 · Stripeのidempotencyモデルは事実上の業界標準になりました。IETFのIdempotency-Keyドラフトは直接これに触発されています。すべてのStripe APIユーザーは、知っていてもいなくても、POST /chargesを安全に再試行可能な操作に変える契約から恩恵を受けます。レベル3でその仕組みにズームインします。

これはStripeのAPI表面を最も強く形作る単一のアーキテクチャ選択です。それなしでは、C4モデルは各ミューテーションbouдanceに再試行ロジックを露出する必要があり — 分散システムの複雑さをすべてのコンシューマーにleakingします。

Archylではこのようにして、ADRがその場を獲得します:なぜboundaryがそう見えるかを説明するのです。

レベル2 — Container:Payments coreへのズーム

Stripe C4 Container: Payments core内部

マーチャントのstripe.PaymentIntents.create()はPaymentsの境界に到達します。箱を開けてみましょう。

Payments内部では、公開ソースが少なくとも以下のコンテナを明らかにしています:

  • Apiori — APIゲートウェイ。元はRuby + Rails、ホットパスのコードはauth・routing層でsub-150 µsレイテンシを達成するため段階的にGoに書き直された。
  • Idempotency layer — すべてのミューテーションエンドポイントの前に座るcross-cutting concern。row-level lockingを伴うPostgreSQLでバックアップ。
  • PaymentIntent service — ステートマシンをオーケストレート:requires_payment_methodrequires_confirmationrequires_action(3DSチャレンジ)→ processingsucceeded(またはrequires_capture)。
  • Card Data Vault — 物理的に隔離されたPCI環境、AES-256 at rest、メインサービスはPANを復号できない。すべてのカードデータはトークン化を経由する。
  • Radar — 100ms p99未満での不正スコアリング。2022年からピュアDNN、ResNeXtにインスパイアされたアーキテクチャ。
  • Network connectors — Visa、Mastercard、Amexなど用のアダプター。ワイヤー上でISO 8583とプロプライエタリプロトコルを話す。
  • Webhook delivery service — at-least-onceデリバリー、3日間で16リトライのexponential backoff、HMAC-SHA256署名。
  • Ledger — 不変イベントログ、~50億イベント/日、~100台帳エントリー/支払い。リコンシリエーション、監査、会計のsource of truth。
  • DocDB — Stripe独自のDatabase-as-a-Service、MongoDB上に構築。500万クエリ/秒、5,000以上のコレクション、2,000以上のシャード、ペタバイトの金融データ。

このレベルのテックスタック:支配的言語のSorbet型付きRuby(1500万行)、ホットパスにGo、リレーショナル関心(idempotency、accounts)にPostgreSQL、高ボリュームドキュメントワークロードにDocDB、イベントにApache Kafka、リアルタイム分析にApache Pinot、ストリーム処理にApache Flink。

典型的なchargeはApiori → Idempotency layer → PaymentIntent service → (トークン用Vault) → (リスク用Radarを並行) → Network connector → Ledger → Webhook fanoutを触れます。これらすべて、リトライ付きで、Veneur経由でend-to-endに計装され、外部egressにはSmokescreen経由で安全にルーティングされます。

ADR-002 · DocDB — 書き直しではなくMongoDB上に構築

ステータス · Accepted (~2018年、進行中の投資)

コンテキスト · 2018年までに、StripeのMongoDBデータ量は既製品を圧迫していました:ペタバイトコレクションのスキーマ移行は危険、シャーディングは運用負担、99.999%のアップタイム要件はメンテナンスウィンドウを許しませんでした。業界は*「リレーショナルストアに書き直せ」*と言ったでしょう。

決定 · データ層を別のエンジンに移行しない。代わりに、MongoDBの上にカスタムDatabase-as-a-Serviceを構築する:Database Proxy、Chunk Metadata Service、dual-write/backfill/dual-read/cleanupパターンをマネージドプリミティブとして実行するData Movement Platform、そしてアウトバウンドイベント用のCDCサービス。

結果 · StripeはMongoDBの柔軟なドキュメントモデルの良さに加えてマネージドプラットフォームの運用保証を得る:500万 QPS、99.999%のsteady-stateアップタイム、ルーチンとしてのゼロダウンタイム移行。インターネットの噂が時々主張する「Mongo → DynamoDB」移行?起こったことはありません。彼らは代わりに倍賭けしました。

このADRはpath-dependentアーキテクチャの素晴らしい例です:2018年の正しい答えは置き換えではなく拡張でした。

レベル3 — Component:Idempotency layer内部

Stripe C4 Component: idempotency layerとフェーズ

Stripeのスタックのすべてのコンポーネントの中で、Idempotency layerは最も公的に文書化されたものです — Brandur Leachの2017年の投稿は今なお分散システムエンジニアの正典的な参照です。

idempotency keyを伴う1つのPOST /chargesは、レイヤー内のこれらのコンポーネントを横断します:

  1. Request hasher — リクエストペイロードの決定論的ハッシュを計算。同じidempotency keyが異なるペイロードで到着した場合、APIは422を返す(クライアントがプログラミングミスをした)。
  2. Idempotency key store(account_id, idempotency_key)をキーとするPostgreSQLテーブル。request_hashresponse_coderesponse_bodyrecovery_pointlast_run_atlocked_atを含む。locked_atカラムは並行リトライのためのrow-level lockingを実装。
  3. Phase executor — 操作をforeign state mutationsで区切られた原子的なフェーズに分割。各フェーズは純粋にローカル(Postgres-only、idempotency rowとトランザクショナル)か、1つの外部side-effect(Vault tokenize、ネットワークcharge、webhook送信)のいずれか。
  4. Recovery point tracker — 現在のフェーズを永続化:startedran_chargewrote_ledgerenqueued_webhookfinished。リトライ時、executorはrecovery pointから再開。
  5. Job enqueuer — 非同期side-effect(emails、webhooks)用に、durableなjobをrecovery pointの更新と同じPostgresトランザクションにキューイング。構造的に原子的。
  6. Background runner — 独自のリトライセマンティクス、exponential backoff、dead-letter storeでjobキューを排出。

パターンは見れば残酷なほどシンプルです:すべてのローカルミューテーションはidempotency行更新と同じPostgresトランザクション内にあり、すべての外部ミューテーションは2つのrecovery point間にある。この形は、このプリミティブなしで構築された分散システムを悩ます二重書き込みバグの全クラスを排除します。

これがコンポーネントレベルのC4の見た目です:*「ここにコードがあります」ではなく、「ここにビジネス的に意味のあるプリミティブの連鎖があり、それぞれがowned、それぞれが置換可能、それぞれが計測可能」*なのです。

ADR-003 · Sorbet — 型チェッカーに投資、Rubyを書き直さない

ステータス · Accepted (~2017年、2019年にオープンソース化、依然デフォルト)

コンテキスト · 2017年までに、StripeのRuby + Railsモノリスは1000万行を超えていました。その規模のフィンテックの業界の支配的アドバイスは型付き言語に書き直せ — Java、Go、Scala — でした。書き直しのコストは数年と数百人のエンジニアと推定されました。Rubyの開発者体験は一方で、Stripeの素早く出荷する競争優位でした。

決定 · 書き直さない。Ruby用のgradual型チェッカーを構築する。マルチスレッド、IDEグレード、数百万行にスケールする型システムをshipするのに18ヶ月と小さなチームをかける。オープンソース化する。

結果 · Sorbetは現在、サブ秒インクリメンタルレイテンシで1500万行のStripe Rubyを型チェックします。Stripeは書き直し税を一度も払いませんでした。彼らは型チェッカー発明税を払いました — 一度だけ。SorbetはCoinbase、Shopify、GitHubなどに使われる重要なオープンソースプロジェクトになりました。

Archylモデルでは、このようなADRはアーキテクチャと一緒に旅をします。2026年にApiori containerをクリックして「Ruby + Sorbet」を見たとき、なぜJavaではないかを説明する2017年の決定も見ることになります。

Archylにレンダリングされた3つのStripe ADRカード

3つの決定。Archylの3つのカード、それぞれ形作るC4要素にリンク — Idempotency keysはすべてのミューテーションエンドポイントに、DocDBはデータ層に、Sorbetはすべてのrubyコンテナに。図は現在形;ADRはなぜ。

Ownership:モデルをaccountabilityに変える

Stripe Ownership Map: チームをシステムにマッピング

C4モデルは、チームをマッピングするまでは静的なアーティファクトです。

Stripeはエンジニアリング構造について公に発信しています:強力なFoundationsグループ(Infrastructure、Security、Data Platform、Developer Experience)、各主要システムに合わせた製品チーム(Payment Methods、Connect、Capital、Identity、Issuing、Treasury、Climate、Radar)、そしてMLとobservability用のクロスカット部門。

これらをC4モデルに落とすと:

  • FoundationsがApiori、Sorbet、Veneur、Smokescreen、Kubernetesプラットフォーム、DocDB、Card Data Vaultを所有 — すべての製品が構築する基盤
  • Payment MethodsがNetwork connectors、PaymentIntent state machine、メソッド別サービス(カード、ACH、SEPA、ウォレット)を所有
  • ConnectがAccount service、capability gating、マルチパーティファンドフロー、payoutsを所有
  • Capitalが貸付決定パイプラインとマーチャントのStripe Payments履歴との統合を所有
  • IdentityがKYC/KYBワークフローとConnectオンボーディングのコンプライアンスゲーティングを所有
  • Radar(MLチーム)が不正DNN、モデルサービング、トレーニングパイプラインを所有
  • Issuing & Treasuryが銀行パートナー統合とカードライフサイクルを所有
  • Climateがカーボンオフセットマーケットプレイス統合を所有

このマッピングは装飾ではありません。続くすべてのものの基盤です。

システム、コンテナ、またはコンポーネントがチーム所有者を持てば、driftの検出は責任のあるものになります:新しいサービスがコミットに現れて図にない場合、特定のチームが問われます。コンフォーマンスルールが違反されると(例えば、Foundations以外のサービスがCard Data Vaultから直接読み取ろうとしたり)、inboxに名前が入ります。

Archylでは、Ownership Mapはドキュメンテーションツールがガバナンスツールに変わる瞬間です。

Drift、コンフォーマンス、そして週次ダイジェスト

このサイズのモデルはdriftします。新製品が上陸 — 2022年にClimate、Treasury、Tax拡張、Apps Marketplace。スタックは変わる — ApioriパスはGoに移行、PinotがLove古い分析を置き換え、Sorbet strictnessは上がる。

Archylは週次のdriftスコアを計算します:ドキュメント化されたC4モデルとコードに現在あるものとのギャップ。コンフォーマンスルールはポリシー層を追加します — 「すべてのコンテナはownerチームが必要」「FoundationsサービスのみがCard Data Vaultを読み取り可能」「すべての公開API変更はバージョニングADRを参照する必要がある」

Stripeにとってそれは1500万行と毎秒27,000リクエストの規模でのdrift検出です。しかしルールは10サービスのときと同じです。

そして最近リリースしたチームアーキテクチャダイジェストは、Stripe風のセットアップでは:

  • Foundationsの月曜のダイジェストはApiori、Vault、DocDB、K8sプラットフォームをカバー
  • Payment MethodsのダイジェストはNetwork connectors、PaymentIntent service、各メソッド別統合をカバー
  • Radarのダイジェストは不正DNN、トレーニングパイプライン、モデルロールアウトをカバー
  • 各ダイジェストはチームが所有する境界にスコープされる

同じサーフェス。異なるスコープ。それがC4 + ownershipが解錠する対称性です。

1兆ドルを処理する必要はない

あなたはStripeではありません。ほとんどのエンジニアリング組織もそうではありません。

しかし学びは下方向にもスケールします。ContextをContainerからComponentから分ける規律、path-dependentな決定を説明するADRを書く規律(Mongoの上に構築したRubyを書き直す代わりに型チェックした)、すべてのボックスにownershipを付ける規律 — その規律こそが、50サービスのスタックを1500万行のように感じさせないものです。

C4 + ADRs + Ownership + Drift + コンフォーマンスはArchylがout of the boxで提供するものです。Stripeの例は金融システムドメインでのモデルの最大の妥当なストレステストにすぎません。

自分のアーキテクチャを開きましょう。15の製品をスケッチしましょう(3つしかないなら3つで)。最も驚くべき過去の決定を持つものを選んで、そのコンテナにズームインします。新人を困惑させるであろうことを説明する3つのADRを書きましょう。各コンテナにチームをマッピングしましょう。

ほとんどのエンジニアリング組織が1年で到達する場所より先にいるはずです。


自分のアーキテクチャをC4でモデリングしたいですか?Archylで始めましょうなぜADRとC4が一緒に機能するのか、またはArchitecture Change RequestsがC4モデルにpull requestの厳密さをもたらす方法も読んでみてください。前のケーススタディはNetflix in C4 — Anatomy of a Playをモデリングしました。