前方互換性
転送互換性とは
前方互換性は、システムが最初に設計されたものよりも新しいクライアントまたはデータと正しく動作する能力です。より簡単:新しいクライアントがそれに来るとき古いサーバーは壊れません;古い消費者は、彼らが新しいメッセージに遭遇したときに落ちることはありません。
フォワードは、(新しいシステムが古いクライアントをサポートしている場合)後方互換性と責任の方向性が異なります。私たちは、エコシステム全体を完全にアップグレードすることなく、将来の拡張を「生き残る」ような方法でプロトコルとクライアントを設計します。
基本原則
1.寛容な読者及び寛容な作家
Readerは未知のフィールド/ヘッダーを無視し、正しいフォールバックで新しい列挙値を許可します。
Writerは、サーバーが明示的にサポートされていない(機能)と宣言したものを送信しません。
2.機能ネゴシエーション
ハンドシェイクステージでの機能(機能/バージョン/メディアタイプ)の明示的な交換。クライアントはその動作をサーバーの応答に合わせます。
3.デフォルトの劣化
サーバ/コンシューマーがサポートしていない場合でも、スクリプトは有用な最小(MGC)で終了します。
4.安定した中心(MGC)
最低保証契約は変更されません。革新は拡張として生きています。
5.プロトコルの一部としてのエラー契約
予測可能なコード/理由("feature not supported"、 "media type unknown')により、クライアントは自動的にサポートされているモードにロールバックできます。
6.驚きのないバージョン
主要なラインは分けました;マイナーな拡張機能は、サーバ/コンシューマーのアップグレードを必要としません。
重要な点
長寿命の統合を備えたパブリックAPI(パートナー、モバイルアプリケーションのSDK)。
多くの独立した消費者を持つイベントプラットフォーム。
バックエンドよりも遅く更新されるモバイルクライアント。
デバイスの艦隊の一部がほとんど点滅しないエッジ/IoT。
スタイル別の実装パターン
REST/HTTP
ネゴシエーション:- 'Accept'/パラメータ付きメディアタイプ('application/vnd。例を示します。order+json;v=1;profile=risk')。
- '好み:include=……'オプションのブロックの場合。
- タイトル'X-Capabilities: risk_score,item_details_v2'。
- サーバが(OPTIONS/desc/leadエンドポイントを介して)機能を確認した場合にのみ、基本的な形式の拡張でリクエストを送信します。
- '415/406/501'が自動的にサポートされているフォーマット/メソッドにロールバックされるとき。
- サーバー応答:不明なパラメータ-無視;余分なフィールドが許可されています。安定したエラー形式('type/code/detail/trace_id')。
gRPC/Protobuf
安定したサービス:新しいメソッド/フィールド-添加剤;古いサーバーは、未知のリクエストフィールドを静かに無視します。
フィーチャー検出:'GetCapabilities()'メソッドは、フィーチャー/限界のリストを返します。サーバーが宣言しない限り、クライアントはv2メソッドを呼び出しません。
ストリーミング:メッセージの最小セットの順序を修正します。古いクライアントが無視する拡張/型で新しい「フレーム」をマークします。
GraphQL
Forward-friendly:新しいフィールド/タイプがサーバーに表示されます。古いクライアントはリクエストしません。
推測は禁止されています:クライアントはスキーム(introspection/codogen)を保持し、未知のディレクティブ/変数を送信しない必要があります。
劣化:サーバがカスタム/フィーチャーディレクティブを知らない場合、クライアントはリクエストをビルドします。
イベント駆動(Kafka/NATS/Pulsar、 Avro/JSON/Proto)
FORWARDレジストリ内のスキームの互換性:古い消費者は新しいスキームによって書かれたメッセージを読むことができます。
デフォルトの添加フィールド:新しい生産者は古い消費者を壊すことはありません。
Core vs Enriched:カーネルは変わりません。新しい情報は'。enriched'またはオプションのフィールドとして公開されます。
デザインプラクティス
1.最低要求契約(MGC)
操作には、すべてのサーバーが長年サポートする「狭い首」が必要です。
2.コントラクトレベルのフィーチャーフラグ
名前付きの機能として、'risk_score'、 'pricing_v2'、 'strong_idempotency'を記述します。クライアントは明示的にそれらを含みます。
3.「サポートされていない」の明示的なエラーコード"
HTTP: '501 Not Implemented'、 '415 Unsupported Media Type'、 детальные 'problem+json'。
gRPC: 'UNIMPLEMENTED'/'FAILED_PRECONDITION'。
イベント:'reason=unsupported_feature'でDLQのルート。
4.順序/完全なリストに頼らないで下さい
クライアントは、新しい列挙値、新しいフィールド、および「追加」プロパティの準備ができている必要があります。
5.安定した識別子とフォーマット
行内のID/パーティションキーの形式を変更しないでください-これは読者の側で前方に分割されます。
6.「機械読み取り可能」ドキュメント
ホスト記述子:OpenAPI/AsyncAPI/Proto 記述子/GraphQL SDL。お客様は、この機能のサポートを確認することができます。
前方互換性テスト
FORWARD/FULLモードのスキーマ差分:新しいスキーマは古いコンシューマ/サーバを検証します。
クライアント契約テスト:新しいクライアントは、機能が有効/無効になっている古いサーバーに対して実行されます。
ゴールデンリクエスト:「新しい」リクエストのセットは「古い」サーバーを介して実行されます。重大な間違いなしで予想される低下。
カオス/レイテンシ:タイムアウト/リトレイチェック-新しいクライアントは古いサーバの最悪のSLAを正しく生き残らなければなりません。
Canary:新しいクライアントの一部は以前のサーババージョンで動作します-エラー/劣化のテレメトリーを収集します。
観測可能性と運用基準
サポートされていない機能と自動ロールバックを持つリクエスト/メッセージの割合。
クライアントバージョンによる配布(ユーザーエージェント/メタデータ/クレーム)。
'UNIMPLEMENTED/501/415''サポートされていない_フィーチャー'を持つDLQのエラーとルート。
劣化時間:MGC対「拡張」応答のp95/p99。
スキーマレジストリの互換モード
FORWARD:新しいエントリは古いリーダーと互換性があります(デフォルトは必要です、オプション)。
フル:前方へ、後方へ;公共の契約のために便利。
推奨事項:イベントの場合-生産者の場合はBACKWARD、消費者の場合はFORWARD(寛容なリーダー経由)、外部APIの場合はFULL。
例
REST(機能+劣化)
1.クライアントは'GET/meta/capabilities'→'{"risk_score": false、 "price_v2": true}'を作ります。
2.'POST/orders'ではベースフィールドが送信されます。'risk_score'は要求しません。なぜならサーバはそれを実行できないからです。
3.誤って'Prefer: include=risk_score'を送信した場合、サーバーは'risk_score'フィールド(または'Preference-Applied: none')なしで200で応答します-クライアントはクラッシュしません。
gRPC(発見)
'GetCapabilities()'が返されました。クライアントは'CaptureV2'が存在しない場合、'CaptureV2'を呼び出しません。代わりに'Capture'を使用し、入力をローカルにサポートされているビューに変換します。
イベント(FORWARD in registry)
プロデューサーは'risk_score'フィールドを追加しました(デフォルトでは無効)。古い消費者は彼を無視します。ロジックは安定したカーネルフィールドのみを使用します。
アンチパターン
ハードクライアント:ホワイトリストのフィールドで応答をフィルタし、慣れないプロパティに該当します。
暗黙的な機能:クライアントは機能をチェックせずに新しいパラメータの送信を開始します。
行内のID/キーフォーマットの変更→古いサーバー/消費者は、新しいリクエスト/メッセージを理解しなくなりました。
完全な列挙リストに関するハードウェア配線の仮定(デフォルトなしのスイッチ)。
フロー制御としてのロギング:コントラクトコードの代わりにエラー文字列を解析します。
実装チェックリスト
- MGC定義;新しい機能はオプションとしてマークされます。
- 機能ネゴシエーション(エンドポイント/メタデータ/ハンドシェイク)を記述し実装します。
- クライアントは慣れないフィールドを無視し、新しい列挙(フォールバック)を正しく処理します。
- エラー契約は「サポートされていません」を予測可能にキャプチャします(HTTP/gRPC/Event)。
- スキーマレジストリは、対応するアーティファクトのFORWARD/FULLに設定されています。
- Autotests: schema-diff (FORWARD)、クライアントと古いサーバ契約テスト、カナリア。
- メトリクス:クライアントバージョン、機能障害、劣化率、p95 MGC。
- ドキュメント/SDKは、機能のリストと劣化の例を公開します。
よくあるご質問
実際には前進と後進はどのように異なりますか?
後方:新しいサーバーは古いクライアントを壊しません。前方:古いサーバーは新しいクライアント(または新しいメッセージからの古い消費者)から壊れません。理想的には、あなたは完全に達します。
常に機能を入力する必要がありますか?
同期リリースなしでアクティブな進化が期待される場合は、はい。それは何十もの主要なラインを握るより安いです。
セキュリティについてはどうですか?
新しい機能には、別々のスコープ/クレームが必要です。サーバーがサポートしていない場合、クライアントはセキュリティを低下させるべきではありませんが、機能を放棄する必要があります。
サーババージョンによる「推測」サポートは可能ですか?
望ましくない。明示的に(機能)を尋ねるか、メディアタイプ/スキームを見てください。
合計
前方相互運用性は、機会を交渉し、安全に劣化させることの規律です。安定したコア、機能ネゴシエーション、アディティブ拡張、予測可能なバグにより、新しいクライアントやデータを古いサーバや消費者と連携させることができます。