速度のための設計:スキーマレスなイベント取り込みの主張

SchemaBridge Team · 2025-12-08 · Event Ingestion, JSON, DX

イベント駆動システムにおける速度対厳格な型。なぜ私たちは厳格な型定義よりも生のJSONを選んだのか。

スキーマのパラドックス:味方か敵か?

従来のエンタープライズソフトウェアでは、厳格なスキーマ(SQL、Protobuf、WSDL)が信頼性の礎でした。契約はシンプルです。私がデータの形を定義し、あなたがそれに従い、コンパイラは私たちがクラッシュしないことを保証してくれます。このアプローチは、パイプの両端を私たち自身が所有する制御された環境において、何十年もの間うまく機能してきました。それはコンパイル時の安全性、効率的なバイナリシリアライゼーション、そして開発者にとって明確な「真実の情報源」を提供します。

しかし、現代の高速な連携環境――SaaSベンダーが毎週ペイロードを変更し、レガシーなERPが「柔軟な」CSVを吐き出し、社内のマイクロサービスが毎月のように生まれては引退していく環境――では、硬直したスキーマは拘束衣と化します。それらは慣性という代償と引き換えに安全性を提供します。あなたの周りの世界が流動的であるとき、硬直した契約は基盤ではなく、障害点になるのです。スキーマのパラドックスとはこういうことです。厳格な型でシステムを守ろうとすればするほど、外の世界が変化したときにあなたのシステムはより脆くなるのです。

歴史的進化:COBOLからJSONへ

スキーマレスシステムへの需要を理解するには、データ交換の進化を振り返る必要があります。メインフレームコンピューティングの初期、データは固定長レコード(COBOLのCOPYBOOK)に格納されていました。フィールドを追加したければ、そのレコードを読み込むすべてのプログラムを再コンパイルする必要がありました。それは究極の硬直したスキーマでした。これはデータストレージのコストが非常に高く、すべてのバイトを固定された位置で管理しなければならなかった「単一マシンの思考」の時代でした。階層構造の余地はなく、オプション性の余地もなく、そしてもちろん進化の余地もありませんでした。レコード内のすべての文字が貴重なリソースであり、あらゆる変更が何週間もの計画とテストを要する地殻変動的な出来事だったのです。

1980年代から90年代にかけて、私たちはリレーショナルデータベースとSQLへと移行しました。これは構造化された関係性という概念を導入した大きな前進でした。しかしそれは同時にデータベースマイグレーションをも導入しました。カラムを追加することは、ダウンタイム、テーブルのロック、そしてDBAと開発者間の慎重な調整を意味しました。スキーマは依然として、開発者がイノベーションを起こそうとするたびに乗り越えなければならない壁でした。Hibernateのような ORM の台頭があってさえ、テーブル構造の根底にある硬直性は、何が可能かを決める最終的な裁定者であり続けました。

そして90年代後半にXMLSOAPが登場しました。これは「タグ」という概念を導入し、ある程度の柔軟性を可能にしました。パーサーを壊すことなくXMLタグを追加できるようになったのです。しかし業界はすぐにXSD(XML Schema Definition)WSDLを追加し、硬直性を取り戻してしまいました。私たちは何年もの間、名前空間や、たった一文字でも位置がずれるとメッセージを拒否する複雑なエンタープライズサービスバスと格闘して過ごしました。それは「XMLの暗黒時代」であり、スキーマのオーバーヘッドが実際のデータよりも多くの帯域を消費していました。

現在、私たちはJSONRESTを手にしています。JSONは本質的に柔軟です。それはキーと値の単なるマップです。しかし、私たちのエンジニアリング的な本能は、いまだにその柔軟性を厳格な型(TypeScriptのインターフェース、JavaのDTO、Avroのスキーマ)で包み込もうとします。私たちは1970年代のメインフレームの硬直性を、2020年代のクラウドイベントに押し付けようとしているのです。なぜでしょうか? 未知のものを恐れているからです。フィールドの欠落がサービスをクラッシュさせることを恐れているのです。しかしこれから見ていくように、この恐怖は間違ったツールによって対処されようとしています。

財務分析:連携保守の「隠れた税金」

スキーマの硬直性のコストを定量化してみましょう。典型的な中〜大規模のエンジニアリング組織において、連携の保守は「静かな危機」です。それは貸借対照表の項目としては現れませんが、生産性への莫大な足かせとなっています。

保守の算数

ある組織が100件の外部SaaS連携を持っていると仮定します。

給与換算すると、これは「配管の修理」だけに毎年15万米ドル以上を費やしていることになります。しかし本当のコストは機会損失です。あなたのシニアエンジニアがStripeのv2025アップデートに合わせてDTOを更新している間、彼らは会社に数百万ドルをもたらすかもしれない新しい自動不正検知機能を構築していません。5年間で、この税金は累積的な速度の損失をもたらし、より俊敏な競合他社に対して何年もの遅れを取ることになりかねません。

データ流動性の哲学:Schema-on-Read

SchemaBridgeでは、根本的な発想の転換を提唱しています。Schema-on-Readです。

データをエントリの瞬間に検証する(Schema-on-Write)代わりに、まずイベントの生の階層的な真実を取り込みます。JSONペイロードのすべてのバイトを、耐久性のあるストアに保存します。スキーマ――より正確には変換(Transformation)――は、特定のビジネスプロセスがそのデータを必要とする瞬間にのみ適用します。

なぜデータ流動性が勝つのか

1. ゼロタッチな取り込み: 新しいプロバイダーからのイベント受信を数秒で開始できます。webhookをSchemaBridgeゲートウェイへ向ければ、データは直ちに耐久性のあるストアへ流れ込み始めます。データが何を意味するのかは後で理解すればよいのです。

2. 未知への保険: プロバイダーが今日、あなたが必要としないフィールドを追加したとしても、それは依然として生のJSONにキャプチャされています。6ヶ月後にそのフィールドが必要だと気づいても、過去のデータはすでにそこにあります。プロバイダーに古いデータを再度依頼する必要はありません。

3. 分離された進化: 取り込み層と変換層は、それぞれ異なる速度で進化できます。取り込みゲートウェイに一切触れることなく、ビジネスロジックを1日に10回更新できます。

レイトバインディングの数学的根拠

コンピュータサイエンスにおいて、レイトバインディング(Late-Binding)とは、IDや型の解決を実行の瞬間まで遅延させる手法です。これがRubyやPythonのような動的言語を特定のタスクにおいて強力にしている理由です。

Schema-on-Readは、レイトバインディングをデータインフラストラクチャに適用したものです。マッピングを遅延させることで、あらゆる変更が完全な再構築を必要とする硬直したグラフから、経路が地形に合わせて適応できる柔軟なパスへと移行できます。

数学的に言えば、$N$個のプロデューサーと$M$個のコンシューマーの間で考えられるマッピングの数は$N \times M$です。すべてのプロデューサーとコンシューマーが厳格なスキーマに合意しなければならないなら、莫大な調整問題を抱えることになります。レイトバインディングを備えたスキーマレスなブリッジを使えば、この問題を$N + M$個のマッピングに縮小でき、それぞれのマッピングはローカルで独立したものになります。これが真の水平方向のエンジニアリングスケールを実現する方法です。

JSONata:関数型イベント処理のマスタークラス

Schema-on-Readを実用的なものにするには、発見のために設計された言語が必要です。私たちはJSONataを選びました。JSONataは単なるクエリ言語ではなく、生のJSON階層に直接作用する関数型変換エンジンです。

JSONata式の解剖

注文のリストを返すレガシーERPからのペイロードを考えてみましょう。各注文は複雑なネストされた構造を持っています。$500を超え、現在「SHIPPING」状態にある注文のすべての部品番号を抽出したいとします。

従来のコード(Javascript):

const parts = payload.orders
  .filter(o => o.total > 500 && o.status === 'SHIPPING')
  .flatMap(o => o.items)
  .map(i => i.partNumber);

このコードは壊れやすいです。ordersがnullであったり、ある注文でitemsが欠けていたりすると、クラッシュしてしまいます。

JSONataの真髄:

orders[total > 500][status = 'SHIPPING'].items.partNumber

この式はNull安全です。ordersが欠けている場合、結果は単に空の配列になります。決して例外を投げません。データを「主張する」のではなく「発見する」のです。

高度なパターン:深い子孫の選択

JSONataの最も強力な機能の一つが**演算子です。これにより、階層のどこにあってもキーを見つけることができます。

$**.tracking_number

下流のプロバイダーがそれぞれ異なるネスト構造でトラッキング番号を扱っている場合でも、この一つの式であらゆる異なるペイロードバージョンを横断してそれらすべてを見つけ出すことができます。これが構造的な耐障害性の定義です。特定のキーを探す脆い探索を、真実を求める柔軟な検索へと変えてくれるのです。

高度なパターン:その場でのデータ再構築

JSONataは、単一のパスでJSONオブジェクト全体を再構築できます。

orders.{ "order_id": ID, "summary": $join(items.name, ', ') }

従来のコードでは、これにはオブジェクトマッピング、文字列連結、配列反復が必要です。JSONataでは、これはあなたが望む状態の宣言的な射影にすぎません。これは、複雑なイベントの簡略化されたサマリーをSlack通知やモバイルアプリへ送信する必要があるときに特に強力です。

テーブルレスなデータの運用化:セキュリティと検証

批判的な意見としてよく聞かれるのは、「スキーマを使わないなら、どうやってゴミデータがシステムに入ってくるのを防ぐのか?」というものです。

答えは、スキーマレス ≠ 未検証だということです。私たちは単に検証を頂点レベルへ移すだけです。

ケーススタディ:50リージョンのデータ取り込みメッシュ

私たちは最近、50の異なるリージョンからテレメトリを取り込んでいたグローバルIoT企業と協働しました。各リージョンはセンサーファームウェアのわずかに異なるバージョンを使用していました。各リージョンは独自の「JSON方言」を持っていました。

課題

彼らは厳格なテーブルスキーマを持つ従来のSQLベースの取り込みシステムを使おうとしていました。ある国でファームウェアの更新がロールアウトされるたびに、その国全体の取り込みパイプラインが壊れていました。なぜなら、新しいファームウェアがデータベースにカラムのないbattery_health_v2フィールドを追加していたからです。データチームは常に「消火活動」モードにあり、50の本番データベースにまたがってALTER TABLEコマンドを実行していました。彼らはこのメンテナンスウィンドウの間に何百万件ものイベントを失っていました。

SchemaBridgeによる解決策

彼らはスキーマレスな戦略へ移行しました。

1. ユニバーサルキャプチャ: 50のリージョンすべてが、単一のSchemaBridgeゲートウェイクラスタへデータを送るようになりました。ゲートウェイはスキーマを気にせず、単に生のイベントを永続化するだけでした。

2. 読み取り時のマッピング: 彼らは(ファームウェアバージョンごとに1つずつ)50種類の「正規化頂点」を作成しました。ワークフローはヘッダーからファームウェアバージョンを識別し、生のJSONを正しい頂点へルーティングします。

3. ノーコードなアップグレード: 新しいファームウェアバージョンがリリースされると、彼らはデータベースを更新する必要がありませんでした。既存の頂点を複製し、新しいフィールドを含めるようにJSONataマッピングを更新し、デプロイするだけでした。

結果

まとめ:速度は設計上の選択である

厳格なスキーマは選択です。それは、動的な速度よりも静的な安全性を優先するという選択です。閉じたシステムにおいては、それは妥当な選択です。しかし、つながった分散型のエコシステムにおいては、それは失敗につながる選択です。

システムを、あるがままの世界――予測不可能で、進化し続け、階層的な世界――のために設計してください。速度のために設計してください。SchemaBridgeで設計してください。データの流動性を受け入れることで、硬直したDTOとデータベースマイグレーションに縛られたままの競合他社が夢見ることしかできないスピードで、構築し、スケールし、イノベーションを起こす力を手に入れることができます。

Part 3では、取り込みから実行へと移り、「Spawner」頂点と1万件以上の規模で分散ファンアウトを極める方法を探ります。サーバーをクラッシュさせることなく、あるいは一つのトランザクションも失うことなく、数百万件のイベントを処理する方法を見ていきましょう。分散環境の中でループの力を取り戻すのです。

詳しく見る