スキーマは、あらゆるデータ プラットフォームにとって不可欠な部分です。これらは、データの形状とプロパティの名前とデータ型を定義するメタデータです。スキーマは 2 つの点で役に立ちます。まず、データ形式の固定青写真を提供するため、スキーマのコンテキスト内で不適切な形式のデータが使用されるのを防ぐことができます。次に、スキーマにより、ユーザーはデータの解析方法とそのプロパティから何を期待できるかを理解できるようになります。
Apache Pulsar は、サーバー間のデータ転送を可能にするオープンソースの分散型パブリッシュ/サブスクライブ (pub-sub) メッセージング システムです。
時間の経過とともに、アプリケーションが進化するにつれて、アプリケーションによって生成されるデータも変化する可能性があります。ただし、スキーマの変更は、特定の形式のデータを必要とするデータのダウンストリーム コンシューマーに影響を与える可能性があります。プロデューサーとコンシューマー間のスキーマを管理する方法がなければ、ダウンストリーム アプリケーションを中断する危険を冒さずに、メッセージまたはイベントに書き込まれるデータを変更することは困難です。この種の問題を回避するには、新しいプロパティが追加されるにつれてメッセージのスキーマも進化し、消費者が新旧両方の形式のデータを理解できるようにする必要があります。この概念はスキーマ進化として知られており、Pulsar はそれをサポートしています。
この記事では、Pulsar がスキーマの進化を実装およびサポートする方法を説明する前に、スキーマが進化する理由について説明します。
スキーマは生データに関するコンテキストを提供します。多くの場合、それらはシステム内の特定のエンティティを記述し、そのエンティティのすべてのプロパティを網羅します。たとえば、ユーザーをサインアップするアプリケーションがあるとします。名前、電子メールアドレス、年齢などのユーザーの詳細が保存されます。基礎となるデータを記述し、フィールドの名前やその中のデータのタイプなどのコンテキストを提供するユーザー スキーマが存在します。スキーマは次のようになります。
ここで、キャプチャしたデータを拡張して住所データを含め、ユーザーへのダイレクト メールをサポートしたいとします。次に、スキーマを拡張して、住所の最初の行、市区町村、郵便番号など、住所を取得するための新しいフィールドを含める必要があります。これらの新しいフィールドを含めると、スキーマは次のようになります。
元のフィールドは変更されておらず、新しいフィールドのみが追加されているため、これはスキーマ進化の単純な形式です。ほとんどの場合、消費者は新しいフィールドが存在しないかのように続行できるため、これは下流の消費者にとって重大な変更にはなりません。コンシューマは、新しいプロパティを消費して使用するために更新するだけで済みます。
ただし、新しい機能をサポートするために既存のフィールドを修正する必要がある場合があります。たとえば、ユーザーが正確な年齢を指定することに抵抗があり、代わりに 18 ~ 24 歳、25 ~ 39 歳、40 ~ 49 歳、60 歳以上などの年齢範囲を取得するようにアプリケーションを変更したとします。 age 列のデータ型を整数から文字列に修正する必要があります。
これは、より複雑なスキーマの進化です。これにより、age プロパティを処理し、それが数値であることを期待している、または Java のような厳密に型指定された言語を使用して数値を解析している下流のコンシューマーが機能しなくなる可能性があります。また、プロパティに対して数値計算を実行することもできましたが、新しい形式では機能しなくなります。
この課題を克服するために、データ プラットフォームは、このようなシナリオを処理するためのスキーマの進化をサポートできます。 Pulsar は、データ処理に対するスキーマの重要性を認識しています。実際、組み込みのスキーマ進化サポートを組み込むことで、それを第一級市民のように扱います。 Pulsar がこれをどのように行うかを見てみましょう。
Pulsar は、「SchemaInfo」と呼ばれるデータ構造でスキーマを定義します。これは Pulsar 固有のデータ構造であり、それ自体がスキーマであり、Pulsar を介して転送されるメッセージのスキーマを記述します。各 `SchemaInfo` はトピック (メッセージ チャネル) に属し、そのトピックを使用して生成および消費されるメッセージを記述します。
各 `SchemaInfo` には、使用されているスキーマのタイプを詳細に示すタイプがあります。これには、整数、文字列、または Avro や Protobuf などの複雑なスキーマを使用できます。
サポートする
Pulsar は 8 つの異なるタイプをサポートしています。
前の例に戻って、Pulsar の互換性戦略を使用してスキーマの変更を実装してみましょう。まず、初期ユーザー スキーマ (アドレスなし) から始めます。
これはスキーマの V1 になります。そのため、Pulsar のプロデューサーまたはコンシューマーを初めて実装すると、このバージョンの `SchemaInfo` が保存され、プロデューサーとコンシューマーは期待どおりに動作します。
次に、新しいアドレス フィールドをユーザー スキーマに追加します。最初のステップは、スキーマ互換性戦略を調べて、この変更に最適な戦略を決定することです。ドキュメントの「許可される変更」列を使用して、新しいフィールドの追加を許可する戦略を探します。これにより、BACKWARD、BACKWARD_TRANSITIVE、FORWARD、および FORWARD_TRANSITIVE が得られます。
BACKWARD は、古いバージョンを使用しているコンシューマが新しいスキーマを理解できるという保証がない場合に使用する必要があります。 FORWARD は、最新のスキーマ バージョンのコンシューマが古いバージョン内のデータを読み取れない可能性がある場合に使用されます。新しいスキーマを使用するために最初にすべてのコンシューマーを更新する場合は、BACKWARD 戦略を使用します。それ以外の場合は、FORWARD が最適です。
全体像を見ると、Pulsar はトピックのスキーマを進化させる行為全体を次のように指します。
スキーマが永久に同じままであることはまれです。新しい機能がアプリケーションに導入されると、多くの場合、これらの機能をサポートするためにスキーマを進化させる必要があります。ただし、スキーマが変更されると、データのプロデューサーとコンシューマーの同期を維持することが困難になることがよくあります。
Pulsar に組み込まれたスキーマ進化の概念は、これらの変化に対処するのに役立ちます。スキーマ互換性戦略を使用すると、スキーマのさまざまなバージョンにどのような互換性があるかのルールを定義できます。 Pulsar はこれをスキーマ検証プロセスと組み合わせて使用し、その後、これらのルールを使用して、特定のトピックに接続するときにコンシューマがどのスキーマを使用できるかを決定します。