3.5. 組み込みキャッシュの作成
Data Grid は、プログラムを使用して Cache Manager と組み込みキャッシュライフサイクルの両方を制御できる EmbeddedCacheManager
API を提供します。
3.5.1. Data Grid のプロジェクトへの追加
Data Grid をプロジェクトに追加して、アプリケーションで組み込みキャッシュを作成します。
前提条件
- Maven リポジトリーから Data Grid アーティファクトを取得するようにプロジェクトを設定します。
手順
-
以下のように、
infinispan-core
アーティファクトをpom.xml
の依存関係として追加します。
<dependencies> <dependency> <groupId>org.infinispan</groupId> <artifactId>infinispan-core</artifactId> </dependency> </dependencies>
3.5.2. 組み込みキャッシュの作成と使用
Data Grid は、Cache Manager を制御する GlobalConfigurationBuilder
API と、キャッシュを設定する ConfigurationBuilder
API を提供します。
前提条件
-
infinispan-core
アーティファクトをpom.xml
の依存関係として追加します。
手順
CacheManager
を初期化します。注記キャッシュを作成する前に、必ず
cacheManager.start()
メソッドを呼び出してCacheManager
を初期化する必要があります。デフォルトのコンストラクターはこれを行いますが、オーバーロードされたバージョンのコンストラクターはこれを行いません。Cache Manager も重量のあるオブジェクトであり、Data Grid では、JVM ごとに 1 つのインスタンスのみをインスタンス化することを推奨します。
-
ConfigurationBuilder
API を使用して、キャッシュ設定を定義します。 getCache()
、createCache()
、またはgetOrCreateCache()
メソッドで、キャッシュを取得します。Data Grid では、
getOrCreateCache()
メソッドを使用することを推奨します。これは、すべてのノードでキャッシュを作成するか、既存のキャッシュを返すためです。-
必要であれば、キャッシュが再起動しても大丈夫なように、
PERMANENT
フラグを使用します。 -
cacheManager.stop()
メソッドを呼び出してCacheManager
を停止し、JVM リソースを解放してキャッシュを正常にシャットダウンします。
// Set up a clustered Cache Manager. GlobalConfigurationBuilder global = GlobalConfigurationBuilder.defaultClusteredBuilder(); // Initialize the default Cache Manager. DefaultCacheManager cacheManager = new DefaultCacheManager(global.build()); // Create a distributed cache with synchronous replication. ConfigurationBuilder builder = new ConfigurationBuilder(); builder.clustering().cacheMode(CacheMode.DIST_SYNC); // Obtain a volatile cache. Cache<String, String> cache = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache("myCache", builder.build()); // Stop the Cache Manager. cacheManager.stop();
getCache()
メソッド
以下のように、キャッシュを取得するために getCache(String)
メソッドを呼び出します。
Cache<String, String> myCache = manager.getCache("myCache");
上記の操作は、myCache
という名前のキャッシュがまだ存在しない場合は作成し、それを返します。
getCache()
メソッドを使用すると、メソッドを呼び出すノードにのみキャッシュが作成されます。つまり、クラスター全体の各ノードで呼び出す必要のあるローカル操作を実行します。通常、複数のノードにまたがってデプロイされたアプリケーションは、初期化中にキャッシュを取得して、キャッシュが対称であり、各ノードに存在することを確認します。
createCache()
メソッド
createCache()
メソッドを呼び出して、クラスター全体でキャッシュを動的に作成します。
Cache<String, String> myCache = manager.administration().createCache("myCache", "myTemplate");
上記の操作では、後でクラスターに参加するすべてのノードにキャッシュが自動的に作成されます。
createCache()
メソッドを使用して作成するキャッシュは、デフォルトでは一時的です。クラスター全体がシャットダウンした場合、再起動時にキャッシュが自動的に再作成されることはありません。
PERMANENT
フラグ
PERMANENT フラグを使用して、キャッシュが再起動後も存続できるようにします。
Cache<String, String> myCache = manager.administration().withFlags(AdminFlag.PERMANENT).createCache("myCache", "myTemplate");
PERMANENT フラグを有効にするには、グローバルの状態を有効にし、設定ストレージプロバイダーを設定する必要があります。
設定ストレージプロバイダーの詳細は、GlobalStateConfigurationBuilder#configurationStorage() を参照してください。
3.5.3. Cache API
Data Grid は、JDK の ConcurrentMap インターフェイスによって公開されるアトミックメカニズムを含む、エントリーを追加、取得、および削除するための簡単なメソッドを公開する Cache インターフェイスを提供します。使用されるキャッシュモードに基づいて、これらのメソッドを呼び出すと、リモートノードにエントリーを複製したり、リモートノードからエントリーを検索することやキャッシュストアからエントリーを検索することなど、数多くのことが発生します。
単純な使用の場合、Cache API の使用は JDK Map API の使用と違いがないはずです。したがって、マップに基づく単純なインメモリーキャッシュから Data Grid のキャッシュへの移行は簡単になります。
特定のマップメソッドのパフォーマンスに関する懸念
size()、values()、keySet()、および entrySet() など、マップで公開される特定のメソッドは、Data Grid と使用すると特定のパフォーマンスに影響します。keySet
の特定のメソッドである values
および entrySet
を使用できます。詳細は、Javadoc を参照してください。
これらの操作をグローバルに実行しようとすると、パフォーマンスに大きな影響を及ぼし、スケーラビリティーのボトルネックにもなります。そのため、これらの方法は情報またはデバッグの目的でのみ使用してください。
withFlags() メソッドで特定のフラグを使用すると、これらの問題の一部を軽減できる点に留意してください。詳細は、各メソッドのドキュメントを参照してください
Mortal および Immortal データ
単にエントリーを格納するだけでなく、Data Grid のキャッシュ API を使用すると、期限付き情報をデータに添付できます。たとえば、単に put(key, value) を使用すると、immortal エントリーが作成されます。このエントリーは削除されるまで (またはメモリー不足にならないようにメモリーからエビクトされるまで)、いつまでもキャッシュに存在します。ただし、put(key, value, lifespan, timeunit) を使用してデータをキャッシュに格納すると、有効期限が固定され、その有効期限が過ぎると期限切れになるエントリーである、mortal エントリーが作成されます。
Data Grid は、lifespanの他に、有効期限を決定する追加のメトリックとしてmaxIdleもサポートします。lifespans または maxIdles の任意の組み合わせを使用できます。
putForExternalRead
操作
Data Grid の Cache クラスには、putForExternalRead と呼ばれる異なる 'put' 操作が含まれます。この操作は、他の場所で保持されるデータの一時キャッシュとして Data Grid が使用される場合に特に便利です。読み取りが非常に多い場合、キャッシュは単に最適化のために行われ、妨害するものではないため、キャッシュの競合によって実際のトランザクションが遅延してはなりません。
これを実現するため、キーがキャッシュ内に存在しない場合にのみ動作する put 呼び出しとしてputForExternalRead()
が動作し、別のスレッドが同じキーを同時に格納しようとすると、通知なしに即座に失敗します。このシナリオでは、データのキャッシュはシステムを最適化する方法で、キャッシングの失敗が実行中のトランザクションに影響するのは望ましくないため、失敗の処理方法が異なります。成功したかどうかに関わらず、ロックを待たず、読み出し元に即座に返されるため、putForExternalRead()
は高速な操作とみなされます。
この操作の使用方法を理解するために、基本的な例を見てみましょう。PersonId によって入力される Person インスタンスのキャッシュを想像してください。このデータは個別のデータストアから入力されます。以下のコードは、この例のコンテキスト内で putForExternalRead を使用する最も一般的なパターンを示しています。
// Id of the person to look up, provided by the application PersonId id = ...; // Get a reference to the cache where person instances will be stored Cache<PersonId, Person> cache = ...; // First, check whether the cache contains the person instance // associated with with the given id Person cachedPerson = cache.get(id); if (cachedPerson == null) { // The person is not cached yet, so query the data store with the id Person person = dataStore.lookup(id); // Cache the person along with the id so that future requests can // retrieve it from memory rather than going to the data store cache.putForExternalRead(id, person); } else { // The person was found in the cache, so return it to the application return cachedPerson; }
putForExternalRead は、アプリケーションの実行元 (Person のアドレスを変更するトランザクションからなど) となる新しい Person インスタンスでキャッシュを更新するメカニズムとして使用しないでください。キャッシュされた値を更新する場合は、標準の put 操作を使用してください。使用しないと、破損したデータをキャッシュする可能性が高くなります。
3.5.3.1. AdvancedCache API
簡単な Cache インターフェイスの他に、Data Grid はエクステンション作成者向けに AdvancedCache インターフェイスを提供します。AdvancedCache は、特定の内部コンポーネントにアクセスし、フラグを適用して特定のキャッシュメソッドのデフォルト動作を変更する機能を提供します。次のコードスニペットは、AdvancedCache を取得する方法を示しています。
AdvancedCache advancedCache = cache.getAdvancedCache();
3.5.3.1.1. フラグ
フラグは通常のキャッシュメソッドに適用され、特定のメソッドの動作を変更します。利用可能なフラグの一覧と、その効果は、Flag 列挙を参照してください。フラグは、AdvancedCache.withFlags() を使用して適用されます。このビルダーメソッドを使用して、キャッシュ呼び出しに任意の数のフラグを適用できます。次に例を示します。
advancedCache.withFlags(Flag.CACHE_MODE_LOCAL, Flag.SKIP_LOCKING) .withFlags(Flag.FORCE_SYNCHRONOUS) .put("hello", "world");
3.5.3.2. Asynchronous API
Cache.put()、Cache.remove() などの同期 API メソッドの他に、Data Grid には非同期のノンブロッキング API も含まれ、同じ結果をノンブロッキング方式で達成できます。
これらのメソッドの名前は、ブロックメソッドと同様の名前が付けられ、"Async" が追加されます。 例: Cache.putAsync()、Cache.removeAsync() など。 これらの非同期のメソッドは、操作の実際の結果が含まれる CompletableFuture を返します。
たとえば、Cache<String, String>
としてパラメーター化されたキャッシュでは、Cache.put(String key, String value)
は String
を返し、Cache.putAsync(String key, String value)
は CompletableFuture<String>
を返します。
3.5.3.2.1. このような API を使用する理由
ノンブロッキング API は、通信の失敗や例外を処理する機能を備えており、同期通信の保証をすべて提供するという点で強力なもので、呼び出しが完了するまでブロックする必要がありません。 これにより、システムで並列処理をより有効に活用できます。 以下に例を示します。
Set<CompletableFuture<?>> futures = new HashSet<>(); futures.add(cache.putAsync(key1, value1)); // does not block futures.add(cache.putAsync(key2, value2)); // does not block futures.add(cache.putAsync(key3, value3)); // does not block // the remote calls for the 3 puts will effectively be executed // in parallel, particularly useful if running in distributed mode // and the 3 keys would typically be pushed to 3 different nodes // in the cluster // check that the puts completed successfully for (CompletableFuture<?> f: futures) f.get();
3.5.3.2.2. 実際に非同期で発生するプロセス
Data Grid には、通常の書き込み操作の重要なパスにあると見なされる 4 つの項目があります。これらの項目をコスト順に示します。
- ネットワークコール
- マーシャリング
- キャッシュストアへの書き込み (オプション)
- ロック
非同期メソッドを使用すると、ネットワーク呼び出しとマーシャリングがクリティカルパスから除外されます。 ただし、さまざまな技術的な理由により、キャッシュストアへの書き込みとロックの取得は、呼び出し元のスレッドで引き続き発生します。