キャッシュのエンコードとマーシャリング
Data Grid キャッシュのエンコードと Java オブジェクトのマーシャリング
概要
Red Hat Data Grid
Data Grid は、高性能の分散型インメモリーデータストアです。
- スキーマレスデータ構造
- さまざまなオブジェクトをキーと値のペアとして格納する柔軟性があります。
- グリッドベースのデータストレージ
- クラスター間でデータを分散および複製するように設計されています。
- エラスティックスケーリング
- サービスを中断することなく、ノードの数を動的に調整して要件を満たします。
- データの相互運用性
- さまざまなエンドポイントからグリッド内のデータを保存、取得、およびクエリーします。
Data Grid のドキュメント
Data Grid のドキュメントは、Red Hat カスタマーポータルで入手できます。
Data Grid のダウンロード
Red Hat カスタマーポータルで Data Grid Software Downloads にアクセスします。
Data Grid ソフトウェアにアクセスしてダウンロードするには、Red Hat アカウントが必要です。
多様性を受け入れるオープンソースの強化
Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。まずは、マスター (master)、スレーブ (slave)、ブラックリスト (blacklist)、ホワイトリスト (whitelist) の 4 つの用語の置き換えから始めます。この取り組みは膨大な作業を要するため、用語の置き換えは、今後の複数のリリースにわたって段階的に実施されます。詳細は、Red Hat CTO である Chris Wright のメッセージ をご覧ください。
第1章 キャッシュエンコーディングの設定
さまざまなメディアタイプで Data Grid キャッシュを設定する方法と、エンコーディングが Data Grid を使用する方法に与える影響を説明します。
1.1. キャッシュエンコーディング
エンコーディングは、メディアタイプで識別される形式です。これは、Data Grid がエントリー (キー/値のペア) をキャッシュに格納するために使用する形式です。
リモートキャッシュ
Data Grid Server は、キャッシュ設定に設定されるエンコーディングを使用してリモートキャッシュにエントリーを保存します。
Hot Rod および REST クライアントには、Data Grid Server に対して行う各要求を持つメディアタイプが含まれます。異なるメディアタイプで読み書き要求を行う複数のクライアントを処理するには、Data Grid Server は、データをオンデマンドで、キャッシュ設定で設定されているメディアタイプとの間で変換します。
リモートキャッシュにエンコーディング設定がない場合、Data Grid Server はメディアタイプの情報なしにキーおよび値を汎用 byte[]
として保存します。これにより、異なる形式を要求するクライアントのデータを変換する際に予期せぬ結果が生じる可能性があります。
ProtoStream エンコーディングの使用
Data Grid Server は、クライアントの要求に、キャッシュ設定で設定されるメディアタイプとの間で変換できないメディアタイプが含まれる場合に、エラーを返します。
Data Grid は、Data Grid Console、CLI、Hot Rod、REST などの複数のクライアントを使用する場合は、application/x-protostream
メディアタイプでキャッシュエンコーディングを常に設定することを推奨しています。ProtoStream エンコーディングでは、サーバー側のタスクを使用し、リモートキャッシュでインデックス化されたクエリーを実行することもできます。
組み込みキャッシュ
Data Grid は、デフォルトで Plain Old Java Objects(POJO) として組み込みキャッシュにエントリーを保存します。
クラスター化された組み込みキャッシュの場合、Data Grid はすべての POJO をノード間で複製し、その後に POJO にアンマーシャリングできるバイトアレイにマーシャリングする必要があります。つまり、別のマーシャラーを設定しない場合は、Data Grid が ProtoStream マーシャラーで POJO をシリアライズできるようにする必要があります。
ミュータブルな POJO を組み込みキャッシュに保存する場合は、常に新しい POJO インスタンスを使用して値を更新する必要があります。たとえば、HashMap
をキー/値のペアとして保存すると、Data Grid クラスターの他のメンバーには、マップへのローカル変更は表示されません。さらに、Data Grid がオブジェクトをマーシャリングするのと当時にマップインスタンスが更新されると、ConcurrentModificationException
が発生する可能性があります。
1.2. Protobuf キャッシュエンコーディング
Protocol Buffers(Protobuf) は、構造化されたデータの軽量バイナリーメディアタイプです。キャッシュエンコーディングとして、Protobuf は Hot Rod および REST エンドポイントの両方について、異なるプログラミング言語でのクライアントアプリケーション間で優れたパフォーマンスと相互運用性を提供します。
Data Grid は ProtoStream ライブラリーを使用して、キャッシュを application/x-protostream
メディアタイプで Protobuf としてエンコードします。
以下の例は、Person
オブジェクトを記述する Protobuf メッセージを示しています。
message Person { optional int32 id = 1; optional string name = 2; optional string surname = 3; optional Address address = 4; repeated PhoneNumber phoneNumbers = 5; optional uint32 age = 6; enum Gender { MALE = 0; FEMALE = 1; } }
Protobuf は循環オブジェクトをサポートしていません。Java シリアライゼーションまたは JBoss Marshalling を使用して循環オブジェクトをマーシャリングします。
相互運用性
Protobuf エンコーディングは言語に依存しないことから、Data Grid は Java、C++、C#、Python、Go などで書かれたクライアントアプリケーションからのリクエストを処理できます。
Protobuf を使用すると、異なるリモートエンドポイントのクライアント (Hot Rod または REST) が同じデータで操作できます。REST API を使用するため、Data Grid Console を使用して Protobuf でエンコードされたキャッシュにアクセスして作業できます。
application/x-protostream
以外のバイナリーエンコーディングで Data Grid Console を使用することはできません。
アプリケーションとサービス間の通信を可能にするため、すべての Red Hat テクノロジーとの統合には、常に Protobuf キャッシュエンコーディングを application/x-protostream
メディアタイプと共に使用する必要があります。
クエリー
Data Grid には、高速で信頼できるクエリーのために、キャッシュ内のデータの構造化表現が必要です。Ickle クエリー言語でキャッシュを検索するには、オブジェクトを記述する Protobuf スキーマを登録します。
カスタムタイプ
Data Grid には、String
および Integer
を含む頻繁に使用されるタイプに対するネイティブサポートを持つ ProtoStream API の実装が含まれています。カスタムタイプをキャッシュに保存する場合は、ProtoStream マーシャリングを使用して、シリアル化コンテキストを生成して Data Grid で登録し、オブジェクトをマーシャリングできるようにします。
1.2.1. ProtoStream としてのキャッシュのエンコード
ProtoStream ライブラリーを使用して、キャッシュエントリーを Protocol Buffers(Protobuf) として保存するように Data Grid を設定します。
手順
-
キーおよび値の
application/x-protostream
メディアタイプを指定します。
宣言的
<distributed-cache> <encoding> <key media-type="application/x-protostream"/> <value media-type="application/x-protostream"/> </encoding> </distributed-cache>
プログラマティック
//Create cache configuration that encodes keys and values as ProtoStream ConfigurationBuilder builder = new ConfigurationBuilder(); builder.clustering().cacheMode(CacheMode.DIST_SYNC) .encoding().key().mediaType("application/x-protostream") .encoding().value().mediaType("application/x-protostream");
または、キーと値に同じエンコーディングを使用できます。
宣言的
<encoding media-type="application/x-protostream"/>
プログラマティック
.encoding().mediaType("application/x-protostream");
1.3. テキストベースのキャッシュエンコーディング
テキストベースのエンコーディングは、プレーンテキストなどの人間が判読できるコンテンツです。従来の "Hello World" のサンプルエントリーは、以下のようにキャッシュに保存できます。
key=hello value=world
text/plain
メディアタイプでキャッシュをエンコードする場合、Data Grid は以下のメディアタイプ間で変換できます。
-
application/xml
-
application/json
-
application/x-protostream
以下の設定例では、text/plain; charset=UTF-8
メディアタイプでキーと値をエンコードします。
<distributed-cache> <encoding> <key media-type="text/plain; charset=UTF-8"/> <value media-type="text/plain; charset=UTF-8"/> </encoding> </distributed-cache>
1.3.1. クライアントおよびテキストベースのエンコーディング
テキストベースのメディアタイプで鍵と値を格納するようにエンコーディングを設定する場合、これらのキャッシュで動作するようにクライアントを設定する必要もあります。
Hot Rod クライアント
Data Grid は ProtoStream ライブラリーを使用して、String
および byte[]
タイプをネイティブに処理します。text/plain
メディアタイプでキャッシュエンコーディングを設定する場合、Hot Rod クライアントはキャッシュ操作を実行するためのマーシャラー設定を必要とするとは限りません。
JSON や XML などの他のテキストベースのメディアタイプでは、Hot Rod クライアントは、text/plain
メディアタイプで変換する org.infinispan.commons.marshall.UTF8StringMarshaller
マーシャラーを使用できます。
REST クライアント
REST クライアントには、要求ヘッダーにキャッシュのメディアタイプを含める必要があります。
たとえば、キャッシュエンコーディングを text/plain; charset=UTF-8
として設定した場合、REST クライアントは以下のヘッダーを送信します。
-
Accept: text/plain; charset=UTF-8
(読み取り操作の場合) -
Content-Type: text/plain; charset=UTF-8
またはKey-Content-Type: text/plain; charset=UTF-8
(書き込み操作の場合)
1.4. マーシャリングされた Java オブジェクト
Data Grid は、マーシャリングされた Java オブジェクトをバイトアレイとしてキャッシュに保存します。たとえば、以下は、メモリーに値として保存される Person
オブジェクトの単純な表現です。
value=[61 6c 61 6e 0a 70 61 72 74 72 69 64 67 65]
キャッシュにマーシャリングされたオブジェクトを保存するには、厳密な要件がない限り、ProtoStream マーシャラーを使用する必要があります。たとえば、クライアントアプリケーションを古いバージョンの Data Grid から移行する場合は、Hot Rod Java クライアントで JBoss マーシャリングを一時的に使用する必要がある場合があります。
Data Grid は、以下のメディアタイプでマーシャリングされた Java オブジェクトをバイトアレイとして保存します。
-
application/x-protostream
-
application/x-jboss-marshalling
-
application/x-java-serialized-object
アンマーシャリングされた Java オブジェクトを保存する場合、Data Grid は equals()
および hashCode()
のオブジェクト実装を使用します。マーシャリングされたオブジェクトを保存する場合、マーシャリングされたバイトは等価性について比較され、代わりにハッシュ化されます。
1.4.1. クライアントおよびマーシャリングされたオブジェクト
Hot Rod Java クライアントをマーシャラーを使用するように設定する場合は、そのマーシャラーのエンコーディングでキャッシュを設定する必要があります。
それぞれのマーシャラーは異なるメディアタイプを使用して、クライアントが Data Grid Server に送信できる byte[]
コンテンツを生成します。サーバーから読み取る場合、クライアントマーシャラーは逆の操作を行います。メディアタイプを使用して byte[]
コンテンツからデータを生成します。
キャッシュエンコーディングは Hot Rod クライアントマーシャラーと互換性がある必要があります。たとえば、キャッシュエンコーディングを application/x-protostream
として設定している場合、クライアント上で ProtoStream マーシャラーを使用して、そのキャッシュ上で動作させることができます。ただし、クライアントマーシャラーが、Data Grid が application/x-protostream
との間で変換できないエンコーディングを使用する場合、Data Grid はエラーメッセージを出力します。
JavaSerializationMarshaller
または GenericJBossMarshaller
を使用する場合は、キャッシュを application/x-java-serialized-object
または application/x-jboss-marshalling
メディアタイプでエンコードする必要があります。
ProtoStream から JSON への変換
Data Grid は、application/x-protostream
メディアタイプでエンコードされたキーと値を application/json
に変換します。
これにより、REST クライアントは要求ヘッダーに JSON メディアタイプを追加し、ProtoStream エンコーディングを使用するキャッシュで操作を実行することができます。
-
Accept: application/json
(読み取り操作の場合) -
Content-Type: application/json
(書き込み操作の場合)
1.5. Plain Old Java Objects (POJO)
最適なパフォーマンスを得るには、Data Grid は、組み込みキャッシュにのみアンマーシャリングされた POJO を保存することを推奨します。ただし、以下のメディアタイプを使用してキーと値を設定できます。
-
application/x-java-object
1.5.1. クライアントおよび POJO
Data Grid はこれを推奨しませんが、クライアントは application/x-java-object
メディアタイプでアンマーシャリングされた POJO を格納するキャッシュで操作できます。
Hot Rod クライアント
Hot Rod クライアントマーシャラーは、Java オブジェクトをデシリアライズできるように Data Grid Server で利用できる必要があります。デフォルトでは、ProtoStream および Java Serialization マーシャラーはサーバー上で利用できます。
REST クライアント
REST クライアントは、キーと値に JSON または XML を使用し、Data Grid が POJO との間で変換できるようにします。
Data Grid では、XML を POJO との間で変換するためにデシリアライズ許可リストに Java クラスを追加する必要があります。
1.6. JAR の Data Grid Server のインストールへの追加
カスタム JAR ファイルをクラスパスに追加して、Data Grid Server でカスタム JAR ファイルを利用できるようにします。
Data Grid は、起動時にのみ JAR ファイルをロードします。
クラスターのすべてのノードを正常に停止し、クラスターを起動する前に、各ノードで JAR ファイルを利用できるようにする必要があります。
カスタム JAR ファイルは
$RHDG_HOME/server/lib
ディレクトリーにのみ追加する必要があります。$RHDG_HOME/lib
ディレクトリーは、Data Grid JAR ファイル用に予約されています。
手順
- Data Grid Server が実行している場合は停止します。
JAR ファイルを
server/lib
ディレクトリーに追加します。以下に例を示します。├── server │ └── lib │ └── UserObjects.jar
第2章 ProtoStream を使用したカスタムオブジェクトのマーシャリング
マーシャリングは、Java オブジェクトをバイナリー形式に変換して、ネットワーク全体で転送したり、ディスクに格納したりできるプロセスです。逆プロセスのアンマーシャリングは、データをバイナリー形式から Java オブジェクトに変換します。
Data Grid は、マーシャリングとアンマーシャリングを実行し、以下を行います。
- クラスターの他の Data Grid ノードにデータを送信します。
- データを永続キャッシュストアに保存します。
- クライアントとリモートキャッシュ間でオブジェクトを送信します。
- JVM ヒープ外にあるネイティブメモリーにオブジェクトを保存します。
-
キャッシュエンコーディングが
application/x-java-object
ではない場合に、オブジェクトを JVM ヒープメモリーに保存します。
Data Grid キャッシュにカスタムオブジェクトを保存する場合は、ProtoStream マーシャラーで Protobuf ベースのマーシャリングを使用する必要があります。
2.1. ProtoStream マーシャリング
Data Grid は ProtoStream API を提供するため、Java オブジェクトを Protocol Buffers(Protobuf) としてマーシャリングできます。
ProtoStream は、多くの異なる Java データ型をネイティブにサポートします。つまり、これらのタイプに ProtoStream マーシャリングを設定する必要はありません。カスタムまたはユーザータイプの場合、Data Grid が、これらのオブジェクトをキャッシュとの間でマーシャリングできるように情報を提供する必要があります。
SerializationContext
-
Protobuf スキーマ (
.proto
ファイル) から読み込まれる Protobuf タイプの定義が含まれるリポジトリー、および付随マーシャラー。 SerializationContextInitializer
-
SerializationContext
を初期化するインターフェイス。
関連情報
2.1.1. ProtoStream タイプ
Data Grid は、キーと値の以下の型、およびプリミティブタイプの場合にボックスのない同等を処理できる ProtoStream ライブラリーを使用します。
-
byte[]
-
Byte
-
文字列
-
整数
-
ロング
-
Double
-
Float
-
ブール値
-
Short
-
Character
-
java.util.Date
-
java.time.Instant
追加のタイプコレクション
ProtoStream ライブラリーには、一般的な Java タイプ用のアダプタークラスが複数含まれます。以下に例を示します。
-
java.math.BigDecimal
-
java.math.BigInteger
-
java.util.UUID
-
java.util.BitSet
Data Grid は、protostream-types
アーティファクトにある一部の一般的な JDK クラスのすべてのアダプタークラスを提供します。これは、infinispan-core
および infinispan-client-hotrod
依存関係に含まれます。アダプタークラスをキーまたは値として保存する設定は必要ありません。
しかし、アダプタークラスを ProtoStream-annotated POJO でマーシャリング可能なフィールドとして使用する場合は、以下の方法で実行できます。
-
ProtoSchema
アノテーションのdependsOn
要素を使用して、CommonTypesSchema
クラスとCommonContainerTypesSchema
クラスを指定します。
@ProtoSchema(dependsOn = {org.infinispan.protostream.types.java.CommonTypes, org.infinispan.protostream.types.java.CommonContainerTypes}, schemaFileName = "library.proto", schemaFilePath = "proto", schemaPackageName = "example") public interface LibraryInitalizer extends SerializationContextInitializer { }
-
ProtoSchema
アノテーションのincludeClasses
要素を使用して、必要なアダプタークラスを指定します。
@ProtoSchema(includeClasses = { Author.class, Book.class, UUIDAdapter.class, java.math.BigInteger }, schemaFileName = "library.proto", schemaFilePath = "proto", schemaPackageName = "library") public interface LibraryInitalizer extends SerializationContextInitializer { }
2.1.2. ProtoStream アノテーション
ProtoStream API には、Protobuf スキーマを定義するために Java アプリケーションに追加できるアノテーションが含まれます。これにより、オブジェクトに構造化された形式が提供されます。
このトピックでは、ProtoStream アノテーションに関する追加情報を提供します。詳細は、org.infinispan.protostream.annotations パッケージのドキュメントを参照してください。
Proto
@Proto
は、すべてのフィールドに @ProtoField
アノテーションを付ける必要なく、Protocol Buffers メッセージを定義します。
- このアノテーションを使用すると、パブリックフィールドを持つレコードまたはクラスから、メッセージをすばやく生成できます。
- フィールドはパブリックである必要があり、宣言順序に基づいて増分番号が割り当てられます。
-
ProtoField
アノテーションを使用して、フィールドの自動デフォルトをオーバーライドすることができます。
自動 Protobuf フィールド番号付けは、迅速なプロトタイピングにのみ使用してください。実稼働環境の場合、スキーマとの将来的互換性/下位互換性を保証するために、Protocol Buffers のベストプラクティス に従う必要があります。
ProtoField
@ProtoField
は Protobuf message フィールドを定義します。
このアノテーションは、フィールドだけでなく、getter メソッドと setter メソッドにも適用されます。@Proto
アノテーションを使用していない限り、Data Grid が Protobuf としてマーシャリングする前に、クラスに @ProtoField
アノテーションが付けられたフィールドを 1 つ以上設定する必要があります。
パラメーター | 値 | 任意または必須 | 説明 |
---|---|---|---|
| 整数 | 必須 | タグ番号はクラス内で一意である必要があります。 |
| タイプ | 任意 | フィールドの Protobuf タイプを宣言します。タイプを指定しない場合は、Java プロパティーから推測されます。
Java |
| クラス | 任意 | プロパティータイプがインターフェイスまたは抽象クラスである場合に、実際のコレクションタイプを示します。 |
| クラス | 任意 | プロパティータイプが抽象クラスまたはインターフェイスである場合に、実際の Java タイプを示します。この値は、プロパティータイプに対して割り当て可能なインスタンス化可能な Java タイプである必要があります。
|
| 文字列 | 任意 | Protobuf スキーマの名前を指定します。 |
| 文字列 | 任意 | キャッシュからの読み取り時に利用できない場合は、フィールドのデフォルト値を指定します。値は、Java フィールドタイプの正しい構文に従う必要があります。 |
ProtoFactory
@ProtoFactory
は、メッセージクラスのインスタンスを作成するための単一のコンストラクターまたは静的ファクトリーメソッドをマークします。
このアノテーションを使用してイミュータブルメッセージクラスをサポートすることができます。@ProtoField
アノテーションが付けられたフィールドはすべてパラメーターに追加する必要があります。
-
@ProtoFactory
コンストラクターまたはメソッドのフィールド名およびパラメーターは、対応する Protobuf メッセージと一致する必要がありますが、順番は重要ではありません。 -
@ProtoFactory
アノテーションが付けられたコンストラクターをクラスに追加しないと、そのクラスにはデフォルトの no-argument コンストラクターが必要です。そうしないと、コンパイル中にエラーが発生します。
ProtoSchema
@ProtoSchema
は、SerializationContextInitializer
を拡張するクラスまたはインターフェイスの実装を生成します。
アクティブの場合、ProtoStream プロセッサーは、Impl
接尾辞または className
パラメーターで指定した名前と同じパッケージで、コンパイル時に実装を生成します。
includeClasses
または basePackages
パラメーターは、ProtoStream プロセッサーがスキャンして Protobuf スキーマおよびマーシャラーに含める必要があるクラスを参照します。これらのパラメーターのいずれかを設定しないと、ProtoStream プロセッサーはソースパス全体をスキャンします。これにより、予期しない結果が発生する可能性があり、推奨されません。basePackages
パラメーターと excludeClasses
パラメーターを使用して、クラスを除外することもできます。
schemaFileName
パラメーターおよび schemaPackageName
パラメーターは、この名前で生成された Protobuf スキーマを登録します。これらのパラメーターを設定しないと、アノテーション付きの単純なクラス名が名前なしのパッケージ、またはデフォルトパッケージで使用されます。スキーマ名は、.proto
ファイル拡張子で終了する必要があります。marshallersOnly
を使用してマーシャラーのみを生成し、Protobuf スキーマの生成を抑制することもできます。
ProtoStream プロセスは、META-INF/services
サービスメタデータファイルを自動的に生成します。このファイルを使用すると、Data Grid Server が JAR を自動的に検出して Protobuf スキーマを登録します。
dependsOn
パラメーターは、最初に実行するように SerializedContextInitializer
を実装するアノテーション付きクラスをリスト表示します。クラスが SerializedContextInitializer
を実装していない場合、または ProtoSchema
でアノテーションが付けられていない場合は、コンパイル時エラーが発生します。
ProtoAdapter
@ProtoAdapter
は、直接アノテーションを付けることができないクラスまたは列挙のマーシャリングアダプターです。
以下の項目に、このアノテーションを使用する場合、
-
クラス: アノテーションが付けられたクラスには、マーシャリングされたクラス用に
@ProtoFactory
アノテーションが付けられたファクトリーメソッド、および各フィールド用にアノテーション付きアクセサーメソッドが必要です。これらのメソッドはインスタンスまたは静的なメソッドにすることができます。また、最初の引数はマーシャリングされたクラスである必要があります。 - 列挙: 同じ名前の列挙値が、ターゲット列挙に存在している必要があります。
ProtoName
@ProtoName
は、Protobuf メッセージまたは列挙型の名前を指定するオプションのアノテーションです。クラス、レコード、列挙で使用できます。
ProtoEnumValue
@ProtoEnumValue
は Protobuf 列挙値を定義します。このアノテーションは、Java enum のメンバーにのみ適用できます。
ProtoReserved および ProtoReservedStatements
@ProtoReserved
および @ProtoReservedStatements
は、生成されたメッセージまたは列挙定義に reserved
ステートメントを追加し、番号、範囲、および名前の使用を防ぎます。
ProtoTypeId
@ProtoTypeId
は任意で、Protobuf メッセージまたは enum タイプのグローバル一意の数値型識別子を指定します。
Data Grid は内部的にこのアノテーションを使用し、識別子は通知なしに変更できるため、このアノテーションをクラスに追加しないでください。
ProtoUnknownFieldSet
@ProtoUnknownFieldSet
はオプションで、未知のフィールドを保存するタイプ {@link org.infinispan.protostream.UnknownFieldSet}
のフィールドまたは JavaBean プロパティーを示します。
]Data Grid は、Google でサポートされなくなり、今後削除される可能性があるため、このアノテーションの使用は推奨していません。
その他の注釈
Data Grid は、クラス、フィールド、およびメソッドのその他の注釈を、生成された Protobuf スキーマにコメントとしてコピーします。これには、@Indexed
や @Basic
などの索引付けアノテーションが含まれます。
2.2. シリアル化のコンテキストイニシャライザーの作成
シリアル化コンテキストイニシャライザーを使用すると、Data Grid で以下を登録することができます。
- ユーザータイプを記述する Protobuf スキーマ。
- シリアル化およびデシリアライズ機能を提供するマーシャラー。
概略としては、以下の操作を行いシリアル化コンテキストイニシャライザーを作成する必要があります。
- ProtoStream アノテーションを Java クラスに追加します。
-
Data Grid が提供する ProtoStream プロセッサーを使用して、
SerializationContextInitializer
実装をコンパイルします。
org.infinispan.protostream.MessageMarshaller
インターフェイスは非推奨となり、ProtoStream の今後のバージョンで削除される予定です。完全に削除されるまで MessageMarshaller
の使用方法を示すコード例またはドキュメントは無視する必要があります。
2.2.1. ProtoStream プロセッサーの追加
Data Grid は、コンパイル時にクラスの Java アノテーションを処理する ProtoStream プロセッサーアーティファクトを提供し、Protobuf スキーマ、付随マーシャラー、および SerializationContextInitializer
インターフェイスの具体的な実装を生成します。
手順
pom.xml
のmaven-compiler-plugin
のアノテーションプロセッサー設定にprotostream-processor
を追加します。<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>...</version> <configuration> <annotationProcessorPaths> <annotationProcessorPath> <groupId>org.infinispan.protostream</groupId> <artifactId>protostream-processor</artifactId> <version>...</version> </annotationProcessorPath> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build>
2.2.2. ProtoStream アノテーションの Java クラスへの追加
Java クラスとそのメンバーにアノテーションを追加して ProtoStream メタデータを宣言します。次に、Data Grid は ProtoStream プロセッサーを使用して Protobuf スキーマと、それらのアノテーションから関連するマーシャラーを生成します。
手順
フィールドで直接、または getter メソッドまたは setter メソッドのいずれかで、
@ProtoField
でマーシャリングする Java フィールドにアノテーションを付けます。Java クラスのアノテーションが付けられていないフィールドは一時的です。たとえば、Java クラスに 15 つのフィールドがあり、それらのうち 5 つにアノテーションを付けるとします。作成されるスキーマにはこれらの 5 つのフィールドのみが含まれ、これらの 5 つのフィールドのみが Data Grid にクラスインスタンスを保存するときにマーシャリングされます。
-
@ProtoFactory
を使用して、イミュータブルオブジェクトのコンストラクターにアノテーションを付けます。アノテーションが付けられたコンストラクターは@ProtoField
アノテーションが付けられたフィールドをすべて初期化する必要があります。 -
@ProtoEnumValue
で Java 列挙型のメンバーにアノテーションを付けます。
以下の Author.java
および Book.java
の例は、@ProtoField
および @ProtoFactory
のアノテーションが付けられた Java クラスを示しています。
Author.java
import org.infinispan.protostream.annotations.ProtoFactory; import org.infinispan.protostream.annotations.ProtoField; public class Author { @ProtoField(1) final String name; @ProtoField(2) final String surname; @ProtoFactory Author(String name, String surname) { this.name = name; this.surname = surname; } // public Getter methods omitted for brevity }
Book.java
import org.infinispan.protostream.annotations.ProtoFactory; import org.infinispan.protostream.annotations.ProtoField; public class Book { @ProtoField(number = 1) public final UUID id; @ProtoField(number = 2) final String title; @ProtoField(number = 3) final String description; @ProtoField(number = 4, defaultValue = "0") final int publicationYear; @ProtoField(number = 5, collectionImplementation = ArrayList.class) final List<Author> authors; @ProtoField(number = 6) public Language language; @ProtoFactory Book(UUID id, String title, String description, int publicationYear, List<Author> authors, Language language) { this.id = id; this.title = title; this.description = description; this.publicationYear = publicationYear; this.authors = authors; this.language = language; } // public Getter methods not included for brevity }
以下の Language.java
の例は、対応する Protobuf スキーマとともに @ProtoEnumValue
アノテーションが付けられた Java 列挙を示しています。
Language.java
import org.infinispan.protostream.annotations.ProtoEnumValue; public enum Language { @ProtoEnumValue(number = 0, name = "EN") ENGLISH, @ProtoEnumValue(number = 1, name = "DE") GERMAN, @ProtoEnumValue(number = 2, name = "IT") ITALIAN, @ProtoEnumValue(number = 3, name = "ES") SPANISH, @ProtoEnumValue(number = 4, name = "FR") FRENCH; }
Language.proto
enum Language { EN = 0; DE = 1; IT = 2; ES = 3; FR = 4; }
2.2.3. ProtoStream アダプタークラスの作成
ProtoStream は @ProtoAdapter
アノテーションを提供し、これを使用して、直接アノテーションを付けることができない外部のサードパーティーの Java オブジェクトクラスをマーシャリングすることができます。
手順
Adapter
クラスを作成し、以下の例のように@ProtoAdapter
アノテーションを追加します。import java.util.UUID; import org.infinispan.protostream.annotations.ProtoAdapter; import org.infinispan.protostream.annotations.ProtoFactory; import org.infinispan.protostream.annotations.ProtoField; import org.infinispan.protostream.descriptors.Type; /** * Human readable UUID adapter for UUID marshalling */ @ProtoAdapter(UUID.class) public class UUIDAdapter { @ProtoFactory UUID create(String stringUUID) { return UUID.fromString(stringUUID); } @ProtoField(1) String getStringUUID(UUID uuid) { return uuid.toString(); } }
2.2.4. シリアル化コンテキストイニシャライザーの生成
ProtoStream プロセッサーを追加して Java クラスにアノテーションを付けると、Data Grid が Protobuf スキーマ、付随するマーシャラー、および SerializationContextInitializer
の具体的な実装を生成するように、@ProtoSchema
アノテーションをインターフェイスに追加できます。
デフォルトでは、生成された実装名は "Impl" 接尾辞が付いたアノテーション付きクラス名です。
手順
GeneratedSchema
を拡張するインターフェイスまたはそのスーパーインターフェイスSerializationContextInitializer
を定義します。注記GeneratedSchema
インターフェイスには Protobuf スキーマにアクセスするためのメソッドが含まれていますが、SerializationContextInitializer
インターフェイスは登録メソッドのみをサポートします。-
インターフェイスに
@ProtoSchema
アノテーションを付けます。 -
includeClasses
パラメーターには、生成されたSerializationContextInitializer
実装のすべてのクラスが含まれることを確認します。 -
schemaFileName
パラメーターで、生成された.proto
スキーマの名前を指定します。 -
schemaFilePath
パラメーターで、スキーマファイルが生成されるtarget/classes
の下にパスを設定します。 -
schemaPackageName
パラメーターで、生成された.proto
スキーマのパッケージ名を指定します。
次の例は、@ProtoSchema
でアノテーションが付けられた GeneratedSchema
インターフェイスを示しています。
@ProtoSchema( includeClasses = { Book.class, Author.class, UUIDAdapter.class, Language.class }, schemaFileName = "library.proto", schemaFilePath = "proto/", schemaPackageName = "book_sample") interface LibraryInitializer extends GeneratedSchema { }
次のステップ
組み込みキャッシュを使用する場合は、Data Grid は SerializationContextInitializer
実装を自動的に登録します。
リモートキャッシュを使用する場合は、SerializationContextInitializer
実装を Data Grid Server に登録する必要があります。
2.2.5. Protocol Buffers のベストプラクティス
Protocol Buffers のドキュメントには、下位互換性を維持するためにメッセージを設計する方法とスキーマを 進化させる 方法に関する ベストプラクティス のリストが記載されています。
Data Grid は、スキーマが更新されたときに自動的に互換性チェックを実行し、非互換性が検出された場合は更新を拒否できます。チェックの種類は、グローバル serialization
設定の schema-compatibility
属性を介して設定できます。利用可能なレベルは次のとおりです。
-
UNRESTRICTED
: チェックは実行されない -
LENIENT
: ルールのサブセットが適用される -
STRICT
: すべてのルールが適用される (デフォルト)
次の表は、各レベルで有効になっている互換性チェックルールを示しています。
ルール | 説明 | レベル |
---|---|---|
予約フィールドを使用しない | 現在の定義と更新された定義を比較し、メッセージの以前に予約されたフィールドまたは ID が同じメッセージの一部として使用されている場合は、警告のリストを返します。 |
|
フィールド ID の変更なし | 現在の定義と更新された定義を比較し、フィールド ID 番号が変更されている場合は、警告のリストを返します。 |
|
フィールドタイプを変更なし | 現在の定義と更新された定義を比較し、フィールドタイプが変更されている場合は、警告のリストを返します。 |
|
予約なしでフィールドを削除しない | 現在の定義と更新された定義を比較し、フィールド名または ID の対応する予約なしにフィールドが削除された場合は、警告のリストを返します。 |
|
予約フィールドを削除しない | 現在の定義と更新された定義を比較し、予約済みフィールドが削除されている場合は、警告のリストを返します。 |
|
フィールド名を変更しない | 現在の定義と更新された定義を比較し、メッセージの以前のフィールドの名前が変更されている場合は、警告のリストを返します。 |
|
2.2.6. シリアル化コンテキストイニシャライザーの登録
組み込みキャッシュの場合、Data Grid は java.util.ServiceLoader
を使用してアノテーションが付けられた SerializationContextInitializer
実装にシリアル化コンテキストおよびマーシャラーを自動的に登録します。
必要に応じて、SerializationContextInitializer
実装の自動登録を無効にして、手動で登録することができます。
1 つの SerializationContextInitializer
実装を手動で登録する場合は、自動登録が無効になります。その後、他のすべての実装を手動で登録する必要があります。
手順
ProtoSchema.service
アノテーションの値をfalse
に設定します。@ProtoSchema( includeClasses = SomeClass.class, ... service = false )
-
以下の例のように、プログラムまたは宣言的に
SerializationContextInitializer
実装を手動で登録します。
宣言的
<serialization> <context-initializer class="org.infinispan.example.LibraryInitializerImpl"/> <context-initializer class="org.infinispan.example.another.SCIImpl"/> </serialization>
プログラマティック
GlobalConfigurationBuilder builder = new GlobalConfigurationBuilder(); builder.serialization() .addContextInitializers(new LibraryInitializerImpl(), new SCIImpl());
2.2.7. Data Grid Server への Protobuf スキーマの登録
Ickle クエリーを実行する場合、または application/x-protostream
から application/json
などの他のメディアタイプに変換する場合は、Data Grid Server に Protobuf スキーマを登録する必要があります。
前提条件
ProtoStream プロセッサーで Protobuf スキーマを生成します。
生成された Protobuf スキーマは、
target/<schemaFilePath>/
ディレクトリーにあります。CREATE
権限を持つユーザーを用意します。注記セキュリティー認可には、スキーマを追加するための
CREATE
権限が必要です。デフォルト設定では、少なくともdeployer
のロールが必要です。
手順
次のいずれかの方法で、Protobuf スキーマを Data Grid サーバーに追加します。
- 任意のブラウザーで Data Grid コンソールを開き、Schema タブを選択してから Add Protobuf schema を選択します。
Data Grid コマンドラインインターフェイス (CLI) から
--upload=
引数を指定してschema
コマンドを使用します。schema --upload=person.proto person
REST API を使用して、
POST
要求のペイロードに Protobuf スキーマを含めます。POST/rest/v2/schemas/<schema_name>
以下の例のように、Hot Rod クライアントで生成された
SerializationContextInitializer
実装を使用して、Protobuf スキーマを登録します。/** * Register generated Protobuf schema with Data Grid Server. * This requires the RemoteCacheManager to be initialized. * * @param initializer The serialization context initializer for the schema. */ private void registerSchemas(SerializationContextInitializer initializer) { // Store schemas in the '___protobuf_metadata' cache to register them. // Using ProtobufMetadataManagerConstants might require the query dependency. final RemoteCache<String, String> protoMetadataCache = remoteCacheManager.getCache(ProtobufMetadataManagerConstants.PROTOBUF_METADATA_CACHE_NAME); // Add the generated schema to the cache. protoMetadataCache.put(initializer.getProtoFileName(), initializer.getProtoFile()); // Ensure the registered Protobuf schemas do not contain errors. // Throw an exception if errors exist. String errors = protoMetadataCache.get(ProtobufMetadataManagerConstants.ERRORS_KEY_SUFFIX); if (errors != null) { throw new IllegalStateException("Some Protobuf schema files contain errors: " + errors + "\nSchema :\n" + initializer.getProtoFileName()); } }
SerializationContextInitializer
実装およびカスタムクラスを持つ JAR ファイルを$RHDG_HOME/server/lib
ディレクトリーに追加します。これを実行すると、Data Grid Server は起動時に Protobuf スキーマを登録します。ただし、スキーマは
___protobuf_metadata
キャッシュに保存されたり、クラスター全体で自動的に分散されたりしないため、アーカイブを各サーバーインストールに追加する必要があります。注記Data Grid Server が
application/x-protostream
からapplication/x-java-object
への変換を実施する必要がある場合、これを実行する必要があります。この場合、POJO 用の JAR ファイルも追加する必要があります。
次のステップ
以下の例のように、SerializationContextInitializer
を Hot Rod クライアントに登録します。
ConfigurationBuilder remoteBuilder = new ConfigurationBuilder(); remoteBuilder.addServer().host(host).port(Integer.parseInt(port)); // Add your generated SerializationContextInitializer implementation. LibraryInitalizer initializer = new LibraryInitalizerImpl(); remoteBuilder.addContextInitializer(initializer);
2.2.8. 手動によるシリアル化コンテキストイニシャライザーの実装
Data Grid は、SerializationContextInitializer
または GeneratedSchema
インターフェイスを手動で実装しないことを強く推奨します。
ProtobufTagMarshaller
および RawProtobufMarshaller
アノテーションを使用して SerializationContextInitializer
または GeneratedSchema
インターフェイスを手動で実装できます。
ただし、手動の実装には多くの面倒なオーバーヘッドが必要で、エラーが発生する可能性が高くなります。protostream-processor
アーティファクトを使用して生成する実装は、ProtoStream マーシャリングを設定するより効率的で信頼できる方法です。
第3章 代替およびカスタムマーシャラー実装の使用
Data Grid は、ProtoStream マーシャラーで Protobuf ベースのマーシャリングを使用することを推奨します。これにより、Ickle クエリーを使用し、Data Grid CLI およびコンソールを使用できます。ただし、必要な場合は、代替マーシャラーまたはカスタムマーシャラー実装を使用できます。
3.1. Java クラスのデシリアライズの許可
セキュリティー上の理由から、Data Grid は任意の Java クラスのデシリアライズを許可しません。JavaSerializationMarshaller
または GenericJBossMarshaller
を使用する場合は、Java クラスをデシリアライズ許可リストに追加する必要があります。
デシリアライズ許可リストは Cache Manager に適用されるため、Java クラスはすべてのキャッシュによってデシリアライズされます。
手順
- Data Grid 設定またはシステムプロパティーのデシリアライズ許可リストに Java クラスを追加します。
宣言的
<infinispan> <cache-container> <serialization version="1.0" marshaller="org.infinispan.marshall.TestObjectStreamMarshaller"> <allow-list> <class>org.infinispan.test.data.Person</class> <regex>org.infinispan.test.data.*</regex> </allow-list> </serialization> </cache-container> </infinispan>
システムプロパティー
// Specify a comma-separated list of fully qualified class names -Dinfinispan.deserialization.allowlist.classes=java.time.Instant,com.myclass.Entity // Specify a regular expression to match classes -Dinfinispan.deserialization.allowlist.regexps=.*
3.2. JBoss Marshalling の使用
JBoss Marshalling はシリアル化ベースのマーシャリングライブラリーであり、以前の Data Grid バージョンではデフォルトのマーシャラーでした。
手順
-
infinispan-jboss-marshalling
依存関係をクラスパスに追加します。 -
GenericJBossMarshaller
を使用するように Data Grid を設定します。 - Java クラスをデシリアライズ許可リストに追加します。
宣言的
<serialization marshaller="org.infinispan.jboss.marshalling.commons.GenericJBossMarshaller"> <allow-list> <class>org.infinispan.concrete.SomeClass</class> <regex>org.infinispan.example.*</regex> </allow-list> </serialization>
プログラマティック
GlobalConfigurationBuilder builder = new GlobalConfigurationBuilder(); builder.serialization() .marshaller(new GenericJBossMarshaller()) .allowList() .addRegexps("org.infinispan.example.", "org.infinispan.concrete.SomeClass");
関連情報
3.3. Java シリアライゼーションの使用
Data Grid で Java シリアライゼーションを使用すると、Java Serializable
インターフェイスを実装するオブジェクトをマーシャリングできます。
Java シリアライゼーションは、ProtoStream マーシャリングよりもパフォーマンスが低下します。Java シリアライゼーションは、そうしなければならない厳密な要件がある場合にのみ使用してください。
手順
-
JavaSerializationMarshaller
を使用するように Data Grid を設定します。 - Java クラスをデシリアライズ許可リストに追加します。
宣言的
<serialization marshaller="org.infinispan.commons.marshall.JavaSerializationMarshaller"> <allow-list> <class>org.infinispan.concrete.SomeClass</class> <regex>org.infinispan.example.*</regex> </allow-list> </serialization>
プログラマティック
GlobalConfigurationBuilder builder = new GlobalConfigurationBuilder(); builder.serialization() .marshaller(new JavaSerializationMarshaller()) .allowList() .addRegexps("org.infinispan.example.", "org.infinispan.concrete.SomeClass");
3.4. カスタムマーシャラーの使用
Data Grid は、カスタムマーシャラー用に実装できる Marshaller
インターフェイスを提供します。
カスタムマーシャラーの実装は、起動時に呼び出される initialize() メソッドを使用して設定済みのアクセスリストにアクセスできます。
手順
-
Marshaller
インターフェイスを実装します。 - マーシャラーを使用するように Data Grid を設定します。
- Java クラスをデシリアライズ許可リストに追加します。
宣言的
<serialization marshaller="org.infinispan.example.marshall.CustomMarshaller"> <allow-list> <class>org.infinispan.concrete.SomeClass</class> <regex>org.infinispan.example.*</regex> </allow-list> </serialization>
プログラマティック
GlobalConfigurationBuilder builder = new GlobalConfigurationBuilder(); builder.serialization() .marshaller(new org.infinispan.example.marshall.CustomMarshaller()) .allowList().addRegexp("org.infinispan.example.*");
第4章 データ変換
Data Grid はトランスコーダーを使用して、メディアタイプで識別されるさまざまなエンコーディング間でデータを変換します。
4.1. Hot Rod DataFormat API
Hot Rod エンドポイントを使用したリモートキャッシュでの読み取り操作および書き込み操作は、デフォルトでクライアントマーシャラーを使用します。Hot Rod は、異なるメディアタイプエンコーディングやマーシャラーを使用してキャッシュ操作を実行するのに使用できる Java クライアントの DataFormat
API を提供します。
キーと値の異なるマーシャラー
実行時にキーと値のマーシャラーを上書きできます。
たとえば、Hot Rod クライアントのすべてのシリアル化をバイパスし、リモートキャッシュに保存されている byte[]
配列を読み取るには、以下を実行します。
// Existing RemoteCache instance RemoteCache<String, Pojo> remoteCache = ... // IdentityMarshaller is a no-op marshaller DataFormat rawKeyAndValues = DataFormat.builder() .keyMarshaller(IdentityMarshaller.INSTANCE) .valueMarshaller(IdentityMarshaller.INSTANCE) .build(); // Creates a new instance of RemoteCache with the supplied DataFormat RemoteCache<byte[], byte[]> rawResultsCache = remoteCache.withDataFormat(rawKeyAndValues);
keyMarshaller()
および keyType()
メソッドでキーに異なるマーシャラーとデータ形式を使用すると、クライアントインテリジェンスルーティングメカニズムに干渉する可能性があり、Data Grid クラスター内の追加のネットワークホップが発生する可能性があります。パフォーマンスが重要な場合は、クライアントとサーバーで鍵に同じエンコーディングを使用する必要があります。
異なるエンコーディングでのデータの読み取り
以下のように、org.infinispan.commons.dataconversion.MediaType
で指定された異なるエンコーディングでデータを要求および送信します。
// Existing remote cache using ProtostreamMarshaller RemoteCache<String, Pojo> protobufCache = ... // Request values returned as JSON // Use the UTF8StringMarshaller to convert UTF-8 to String DataFormat jsonString = DataFormat.builder() .valueType(MediaType.APPLICATION_JSON) .valueMarshaller(new UTF8StringMarshaller()) .build(); RemoteCache<byte[], byte[]> rawResultsCache = protobufCache.withDataFormat(jsonString);
カスタム値マーシャラーの使用
org.codehaus.jackson.JsonNode
オブジェクトとして値を返す以下の例のように、値にカスタムマーシャラーを使用できます。
この例では、Data Grid Server はデータ変換を処理し、指定したメディアタイプに対応していない場合は例外を出力します。
DataFormat jsonNode = DataFormat.builder() .valueType(MediaType.APPLICATION_JSON) .valueMarshaller(new CustomJacksonMarshaller() .build(); RemoteCache<String, JsonNode> jsonNodeCache = remoteCache.withDataFormat(jsonNode);
XML で値を返す
以下のコードスニペットは、値を XML として返します。
Object xmlValue = remoteCache .withDataFormat(DataFormat.builder() .valueType(MediaType.APPLICATION_XML) .valueMarshaller(new UTF8StringMarshaller()) .build()) .get(key);
たとえば、前述の get(key)
呼び出しは、以下のような値を返します。
<?xml version="1.0" ?><string>Hello!</string>
4.2. 組み込みキャッシュを使用したオンデマンドのデータ変換
組み込みキャッシュには、application/x-java-object
のデフォルトのリクエストエンコーディングと、キャッシュに設定したメディアタイプに対応するストレージエンコーディングがあります。つまり、Data Grid はアプリケーションからの POJO をキャッシュのストレージエンコーディングにマーシャルし、POJO をアプリケーションに返します。複雑なシナリオによっては、AdvancedCache
API を使用して POJO との間のデフォルト変換を他のエンコーディングに変更できます。
以下の例では、withMediaType()
メソッドを使用して、オンデマンドで application/json
として値を返します。
MediaType を使用した高度なキャッシュ
DefaultCacheManager cacheManager = new DefaultCacheManager(); // Encode keys and values as Protobuf ConfigurationBuilder cfg = new ConfigurationBuilder(); cfg.encoding().key().mediaType("application/x-protostream"); cfg.encoding().value().mediaType("application/x-protostream"); cacheManager.defineConfiguration("mycache", cfg.build()); Cache<Integer, Person> cache = cacheManager.getCache("mycache"); cache.put(1, new Person("John","Doe")); // Use Protobuf for keys and JSON for values Cache<Integer, byte[]> jsonValuesCache = (Cache<Integer, byte[]>) cache.getAdvancedCache().withMediaType("application/x-protostream", "application/json"); byte[] json = jsonValuesCache.get(1);
JSON 形式で返される値
{ "_type":"org.infinispan.sample.Person", "name":"John", "surname":"Doe" }