スキーマ進化と互換性

Looking for Schema Management Confluent Cloud docs? You are currently viewing Confluent Platform documentation. If you are looking for Confluent Cloud docs, check out Schema Management on Confluent Cloud.

スキーマ進化

データ管理の重要な側面の 1 つにスキーマ進化があります。最初のスキーマが定義された後、アプリケーションは時間の経過に応じてスキーマを進化させる必要がある場合があります。その場合、下流のコンシューマーが古いスキーマと新しいスキーマの両方でエンコードされたデータをシームレスに処理できることが重要です。しかし実際には、本稼働で最初の問題が発生するまで、この点が見逃されている傾向があります。データ管理とスキーマ進化について慎重に検討しない場合、後になって高い代償を支払わなければならないことも珍しくありません。

Avro またはその他のスキーマ形式を使用する場合は、スキーマを管理し、それらのスキーマをどのように進化させるべきかを検討することが最も重要な点の 1 つです。Confluent Schema Registry の目的はまさにこれです。スキーマの互換性チェックは Schema Registry に実装されており、すべてのスキーマをバージョン管理します。特定のサブジェクトについて Schema Registry が新しいスキーマを前のバージョンのスキーマと比較する方法は、互換性タイプによって決まります。サブジェクトのスキーマが最初に作成されるときに、一意の ID とバージョン番号(バージョン 1 など)が割り当てられます。そのスキーマが更新されると(互換性チェックに合格した場合)、新しい一意の ID と大きくなったバージョン番号(バージョン 2 など)が割り当てられます。

互換性タイプ

まとめ

以下の表に、特定のサブジェクトについて、さまざまな互換性タイプに許可されているスキーマ変更のタイプの概要を示します。Confluent Schema Registry のデフォルトの互換性タイプは BACKWARD です。すべての互換性タイプについて、以降のセクションで詳細に説明します。また、互換性要件をさらに細かく制御できる、Schema Registry へのコネクターの 構成オプション も参照してください。

互換性タイプ 許可される変更 チェック対象のスキーマ 最初にアップグレード
BACKWARD
  • フィールドの削除
  • オプションのフィールドの追加
最新バージョン コンシューマー
BACKWARD_TRANSITIVE
  • フィールドの削除
  • オプションのフィールドの追加
以前の全バージョン コンシューマー
FORWARD
  • フィールドの追加
  • オプションのフィールドの削除
最新バージョン プロデューサー
FORWARD_TRANSITIVE
  • フィールドの追加
  • オプションのフィールドの削除
以前の全バージョン プロデューサー
FULL
  • オプションのフィールドの追加
  • オプションのフィールドの削除
最新バージョン 任意の順序
FULL_TRANSITIVE
  • オプションのフィールドの追加
  • オプションのフィールドの削除
以前の全バージョン 任意の順序
NONE
  • すべての変更を許可
互換性チェックは無効 状況によって異なる

注釈

互換性モードへの REST API 呼び出しは グローバル であるため、スキーマレジストリのプロパティファイルで設定した互換性パラメーターがすべてオーバーライドされます。これについては後述の「互換性タイプの使用方法」で説明します。API の使用例は「互換性の要件をグローバルにアップデートする」に示されています。

後方互換性

BACKWARD は、新しいスキーマを使用するコンシューマーが、その直前のスキーマで生成されたデータを読み取ることができることを意味します。たとえば、あるサブジェクトに X-2X-1X の順序で変化する 3 つのスキーマがあり、互換性が BACKWARD である場合、新しいスキーマ X を使用するコンシューマーはスキーマ X または X-1 を使用するプロデューサーによって書き込まれたデータを確実に処理できますが、X-2 については必ずしも処理できません。新しいスキーマを使用するコンシューマーが、直近の 2 つのスキーマだけでなく、すべての登録済みスキーマによって書き込まれたデータを処理できるようにするには、 BACKWARD ではなく BACKWARD_TRANSITIVE を使用します。たとえば、あるサブジェクトに X-2X-1X の順序で変化する 3 つのスキーマがあり、互換性が BACKWARD_TRANSITIVE である場合、新しいスキーマ X を使用するコンシューマーはスキーマ XX-1、または X-2 を使用するプロデューサーによって書き込まれたデータを確実に処理できます。

  • BACKWARD: スキーマ X を使用するコンシューマーは、スキーマ X または X-1 で生成されたデータを処理できます
  • BACKWARD_TRANSITIVE: スキーマ X を使用するコンシューマーは、スキーマ XX-1、または X-2 で生成されたデータを処理できます

注釈

Confluent Schema Registry のデフォルトの互換性タイプは BACKWARD であり、 BACKWARD_TRANSITIVE ではありません。

後方互換の変更の一例は、フィールドの削除です。このフィールドなしでイベントを処理するように開発されたコンシューマーは、古いスキーマで書き込まれたイベントを処理し、そのフィールドを含めることができます。コンシューマーは、単にそのフィールドを無視します。

たとえば、Kafka のすべてのデータが HDFS にも読み込まれている場合に、すべてのデータに対して SQL クエリを実行するとします(例: Apache Hive を使用)。この場合、データが時間の経過に伴って変化する場合も、同じ SQL クエリが機能し続けることが重要です。こうした使用事例に対応するには、スキーマを後方互換に対応するように進化させます。すべての サポート対象スキーマ形式 には、後方互換に対応するために、新しいスキーマで許可される変更に関するルールがあります。たとえば、Avro の互換性ルール があります。すべてのスキーマが後方互換に対応するように進化する場合、常に最新のスキーマを使用してすべてのデータに対して均一にクエリを実行できます。

たとえば、新しいフィールド favorite_color を追加することで、アプリケーションが 前のセクションのユーザースキーマ を以下に進化させることができます。

{"namespace": "example.avro",
 "type": "record",
 "name": "user",
 "fields": [
     {"name": "name", "type": "string"},
     {"name": "favorite_number",  "type": "int"},
     {"name": "favorite_color", "type": "string", "default": "green"}
 ]
}

新しいフィールド favorite_color のデフォルト値は "green" です。これにより、古いスキーマでエンコードされたデータを新しいスキーマで読み取ることができます。古いスキーマでエンコードされたデータのシリアル化を解除するときに、新しいスキーマで指定されているデフォルト値が不明のフィールドに使用されます。デフォルト値が新しいフィールドで省略されている場合、新しいスキーマは古いスキーマに対する後方互換に対応できません。これは、古いデータで不明になっている新しいフィールドに割り当てるべき値が明確でないためです。

注釈

Avro 実装の詳細 : 古いスキーマでエンコードされたデータについて、Avro が新しい後方互換に対応したスキーマでそのデータをどのようにデコードするか、Apache Avro プロジェクトの ResolvingDecoder を確認してください。

前方互換性

FORWARD は、新しいスキーマで生成されたデータを、直前のスキーマを使用するコンシューマーが読み取ることができるものの、そのコンシューマーは新しいスキーマのすべての機能を使用できない場合があることを意味します。たとえば、あるサブジェクトに X-2X-1X の順序で変化する 3 つのスキーマがあり、互換性が FORWARD である場合、新しいスキーマ X を使用するプロデューサーによって書き込まれたデータを、スキーマ X または X-1 を使用するコンシューマーが確実に処理できますが、X-2 については必ずしも処理できません。新しいスキーマで生成されたデータを、直近の 2 つのスキーマだけでなく、すべての登録済みスキーマを使用するコンシューマーが読み取ることができるようにするには、 FORWARD ではなく FORWARD_TRANSITIVE を使用します。たとえば、あるサブジェクトに X-2X-1X の順序で変化する 3 つのスキーマがあり、互換性が FORWARD_TRANSITIVE である場合、新しいスキーマ X を使用するプロデューサーによって書き込まれたデータを、スキーマ XX-1、または X-2 を使用するコンシューマーが確実に処理できます。

  • FORWARD: スキーマ X を使用して生成されたデータは、スキーマ X または X-1 のコンシューマーが読み取ることができます
  • FORWARD_TRANSITIVE: スキーマ X を使用して生成されたデータは、スキーマ XX-1、または X-2 のコンシューマーが読み取ることができます

前方互換に対応したスキーマ変更の一例は、新しいフィールドの追加です。大部分のデータ形式では、新しいフィールドなしでイベントを処理するように記述されたコンシューマーは、新しいフィールドを含む新しいイベントを受け取っても、その動作を継続できます。

たとえば、コンシューマーがアプリケーションロジックをスキーマの特定のバージョンに結び付けているとします。このスキーマが進化すると、アプリケーションロジックが即座に更新されない場合があります。このため、新しいスキーマのデータを、アプリケーションが理解できる(古い)スキーマに投影できなければなりません。こうした使用事例に対応するには、スキーマを前方互換に対応するように進化させます。これで、新しいスキーマでエンコードされたデータを古いスキーマで読み取ることができます。たとえば、 後方互換性 に関する前のセクションで紹介した新しいユーザースキーマは、古いスキーマとの前方互換に対応することもできます。新しいスキーマで書き込まれたデータを古いスキーマに投影すると、単純に新しいフィールドがドロップされます。新しいスキーマで元のフィールド favorite_number (color ではなく number)がドロップされた場合、元のユーザースキーマとの前方互換には対応できません。なぜなら、元のスキーマでこのフィールドのデフォルト値が指定されていなかったことが原因で、コンシューマーが新しいデータの favorite_number の値を入力する方法を把握できないためです。

完全互換性

FULL は、スキーマが後方互換と前方互換の 両方 に対応していることを意味します。スキーマが完全互換で進化した場合、古いデータを新しいスキーマで読み取ることも、新しいデータを直前のスキーマで読み取ることもできます。たとえば、あるサブジェクトに X-2X-1X の順序で変化する 3 つのスキーマがあり、互換性が FULL である場合、新しいスキーマ X を使用するコンシューマーはスキーマ X または X-1 を使用するプロデューサーによって書き込まれたデータを確実に処理できますが、X-2 については必ずしも処理できず、新しいスキーマ X を使用するプロデューサーによって書き込まれたデータはスキーマ X または X-1 を使用するコンシューマーが処理できますが、X-2 については必ずしも処理できません。新しいスキーマを、直近の 2 つのスキーマだけでなく、すべての登録済みスキーマとの前方互換と後方互換の両方に対応させるには、 FULL ではなく FULL_TRANSITIVE を使用します。たとえば、あるサブジェクトに X-2X-1X の順序で変化する 3 つのスキーマがあり、互換性が FULL_TRANSITIVE である場合、新しいスキーマ X を使用するコンシューマーはスキーマ XX-1、または X-2 を使用するプロデューサーによって書き込まれたデータを確実に処理でき、新しいスキーマ X を使用するプロデューサーによって書き込まれたデータはスキーマ XX-1、または X-2 を使用するコンシューマーが確実に処理できます。

  • FULL: スキーマ X および X-1 の間で後方互換と前方互換の両方に対応できます
  • FULL_TRANSITIVE: スキーマ XX-1X-2 の間で後方互換と前方互換の両方に対応できます

Avro および Protobuf では、デフォルト値を持つフィールドを定義できます。その場合、デフォルト値を持つフィールドの追加または削除は完全互換の変更です。

サポート対象のスキーマタイプ向けの互換性ルールについては、「フォーマット、シリアライザー、逆シリアライザー」の「互換性チェック」で説明しています。

JSON Schema には、互換性ルールが明示的に定義されていないため、ブログ記事で JSON スキーマの互換性の動作概念 をさらに詳しく説明しています。完全互換性についても取り上げています。

互換性チェックなし

互換性タイプ NONE は、スキーマの互換性チェックが無効になっていることを意味します。

場合によっては、互換性のない変更を行うこともあります。たとえば、フィールドタイプを Number から String へ変更する場合などです。この場合、すべてのプロデューサーとコンシューマーを同時に新しいスキーマバージョンにアップグレードするか、(より可能性の高い方法としては)トピックを新規に作成してアプリケーションの移行を開始し、新しいトピックと新しいスキーマを使用できるようにして、同じトピックでの 2 つの互換性のないバージョンの処理が不要になるようにする必要があります。

推移的なプロパティ

推移的な互換性のチェックは、特定のサブジェクトに複数のバージョンのスキーマがある場合に重要です。互換性が推移的である場合、新しいスキーマの互換性が登録済みの全スキーマに対してチェックされます。互換性が推移的でない場合、新しいスキーマの互換性は最新のスキーマに対してのみチェックされます。

たとえば、あるサブジェクトに X-2X-1X の順序で変化する 3 つのスキーマがある場合:

  • 推移的 : X-2 <==> X-1X-1 <==> XX-2 <==> X のいずれについても互換性が確保されます。
  • 非推移的 : X-2 <==> X-1X-1 <==> X では互換性が確保されますが、X-2 <==> X については必ずしも互換性が確保されません。

漸進的には互換性を持ち、推移的には互換性を持たない スキーマ変更の例 を参照してください。

Confluent Schema Registry のデフォルトの互換性タイプ BACKWARD は非推移的です。つまり、BACKWARD_TRANSITIVE ではありません。このため、新しいスキーマの互換性は最新のスキーマに対してのみチェックされます。

クライアントのアップグレードの順序

設定されている互換性タイプは、クライアントアプリケーション(スキーマを使用して Kafka にイベントを書き込むプロデューサーとスキーマを使用して Kafka からイベントを読み込むコンシューマー)のアップグレードの順序に影響します。互換性タイプに応じて、以下のようになります。

  • BACKWARD または BACKWARD_TRANSITIVE: 古いスキーマを使用するコンシューマーが新しいスキーマを使用して生成されたデータを読み取ることができる保証はありません。このため、新しいイベントの生成を開始する前にすべてのコンシューマーをアップグレードします。
  • FORWARD または FORWARD_TRANSITIVE: 新しいスキーマを使用するコンシューマーが古いスキーマを使用して生成されたデータを読み取ることができる保証はありません。このため、まず新しいスキーマを使用するプロデューサーをすべてアップグレードし、古いスキーマを使用して既に生成されているデータをコンシューマーが利用できないようにしてから、コンシューマーをアップグレードします。
  • FULL または FULL_TRANSITIVE: 古いスキーマを使用するコンシューマーが新しいスキーマを使用して生成されたデータを確実に読み取ることができ、新しいスキーマを使用するコンシューマーが古いスキーマを使用して生成されたデータを確実に読み取ることができます。このため、プロデューサーとコンシューマーを任意の順序でアップグレードできます。
  • NONE: 互換性チェックが無効になっています。このため、クライアントのアプグレードのタイミングについては注意が必要です。

上述した各セクションに互換性タイプの例があります。Avro 向けには Avro 互換性テストスイート というリファレンスもあります。これは、2 つのスキーマを使用した複数のテストケースと、それらの間の互換性テストの結果それぞれを示すものです。

互換性タイプの使用方法

サポート対象の全スキーマタイプ向けの互換性ルールおよびリファレンスについては、 フォーマット、シリアライザー、逆シリアライザー互換性チェック で説明しています。

Schema Registry を使用して Avro スキーマを格納し、スキーマ進化において特定の互換性ルールを適用する方法の詳細については、 Schema Registry API リファレンス を参照してください。ここでは、基本的なヒントをいくつかご紹介します。

現在の互換性タイプをチェックするには、設定を確認します。

  1. Schema Registry REST API を使用します

互換性レベルを設定するには、以下の方法に従います。

  1. クライアントアプリケーションに移動します
  2. Schema Registry REST API を使用します
  3. Control Center Edit Schema 機能を使用します。トピックのスキーマを管理する を参照してください。

注釈

互換性モードへの REST API 呼び出しは グローバル であるため、スキーマレジストリのプロパティファイルで設定した互換性パラメーターがすべてオーバーライドされます。API の使用例は「互換性の要件をグローバルにアップデートする」に示されています。

特定のスキーマの互換性を検証するには、以下のいずれかの方法でテストします。

  1. Schema Registry Maven プラグインを使用します
  2. Schema Registry REST API を使用します

スキーマの互換性チェック の例が記載されている Confluent Schema Registry のチュートリアルを参照してください。