第14章 クラスター化カウンター
クラスター化カウンターは、Red Hat JBoss Data Grid クラスターのノードすべてで分散および共有されます。クラスター化カウンターを使用するとオブジェクトの数を記録することができます。
クラスター化カウンターは名前で識別され、値 (デフォルトは 0) で初期化されます。クラスター化カウンターを永続化して、クラスターの再起動後に値を保持することもできます。
クラスター化カウンターには次の 2 種類があります。
-
Strongはカウンターの値を単一のキーに保存して一貫性を保ちます。カウンターの更新中でも値は認識できます。カウンター値の更新は、キーロック下で実行されます。しかし、カウンターの現在値を読み取るのに必要なロックはありません。Strong カウンターでは、カウンター値をバインドでき、compareAndSetやcompareAndSwapなどのアトミック操作を提供します。 -
Weakはカウンター値を複数のキーに格納します。各キーはカウンター値の部分的な状態を保存します。キーは同時に更新することが可能です。カウンターの更新中、値は認識できません。カウンター値を取得しても、常に最新の値を返すとは限りません。
Strong および Weak クラスター化カウンターの両方は、カウンター値の更新をサポートし、カウンターの現在の値を返し、カウンター値の更新時にイベントを提供します。
14.1. Counter API
counter API は以下で構成されます。
-
EmbeddedCounterManagerFactoryは埋め込みのキャッシュマネージャーからカウンターマネージャーを初期化します。 -
RemoteCounterManagerFactoryはリモートキャッシュマネージャーからカウンターマネージャーを初期化します。 -
CounterManagerは、カウンターの作成、定義および返却を行うメソッドを提供します。 -
StrongCounterは strong カウンターを実装します。このインターフェースはカウンターのアトミックアップデートを提供します。操作はすべて非同期で実行され、完了ロジックにCompletableFutureクラスを使用します。 -
SyncStrongCounterは同期の strong カウンターを実装します。 -
WeakCounterは weak カウンターを実装します。すべての操作は非同期に実行され、完了ロジックにCompletableFutureクラスが使用されます。 -
SyncWeakCounterは同期の weak カウンターを実装します。 -
CounterListenerは、strong カウンターへの変更をリッスンします。 -
CounterEventは strong カウンターへの変更が発生したときにイベントを返します。 -
HandleはCounterListenerインターフェースを拡張します。
14.2. Maven 依存関係の追加
クラスター化カウンターの使用を開始するには、以下の依存関係を pom.xml に追加します。
pom.xml
<dependency> <groupId>org.infinispan</groupId> <artifactId>infinispan-clustered-counter</artifactId> <version>...</version> <!-- 7.2.0 or later --> </dependency>
14.3. CounterManager インターフェースの読み出し
Red Hat JBoss Data Grid 埋め込みモードでクラスター化カウンターを使用するには、以下を行います。
// Create or obtain an EmbeddedCacheManager. EmbeddedCacheManager manager = ...; // Retrieve the CounterManager interface. CounterManager counterManager = EmbeddedCounterManagerFactory.asCounterManager(manager);
Red Hat JBoss Data Grid リモートサーバーと対話する Hot Rod クライアントとクラスター化カウンターを使用するには、以下を行います。
// Create or obtain a RemoteCacheManager. RemoteCacheManager manager = ...; // Retrieve the CounterManager interface. CounterManager counterManager = RemoteCounterManagerFactory.asCounterManager(manager);
14.4. クラスター化カウンターの使用
クラスター化カウンターの定義および設定は、cache-container XML 設定またはプログラムで行います。
14.4.1. クラスター化カウンターの XML 設定
以下の XML スニペットは、クラスター化カウンターの設定例を表しています。
<?xml version="1.0" encoding="UTF-8"?>
<infinispan>
<cache-container>
<!-- cache container configuration goes here -->
<!-- cache configuration goes here -->
<counters>
<strong-counter name="counter-1" initial-value="1">
<upper-bound value="10"/>
</strong-counter>
<strong-counter name="counter-2" initial-value="2"/>
<weak-counter name="counter-3" initial-value="3"/>
</counters>
</cache-container>
</infinispan>14.4.1.1. XML 定義
counters 要素はクラスターのカウンターを設定し、以下の属性があります。
-
num-ownersは、クラスター全体で保存する各カウンターのコピー数を設定します。値が小さいと更新操作が速くなりますが、サポートするサーバーのクラッシュ数が少なくなります。値は正の整数である必要があります。デフォルトは2です。 reliabilityはネットワークパーティションでのカウンター更新動作を設定し、以下の値を取ります。-
AVAILABLE: すべてのパーティションがカウンターの値を読み取りおよび更新できます。これはデフォルト値です。 -
CONSISTENT: プライマリーパーティションがカウンターの値を読み取りおよび更新できます。残りのパーティションはカウンターの値の読み取りのみが可能です。
-
strong-counter 要素は、strong クラスター化カウンターを作成および定義します。weak-counter 要素は weak クラスター化カウンターを作成および定義します。以下は、両方の要素に共通する属性です。
-
initial-valueはカウンターの初期値を設定します。デフォルトの値は0です。 storageはカウンター値の保存方法を設定します。この属性は、クラスターのシャットダウン後および再起動後にカウンター値が保存されるかどうかを決定します。この属性は以下の値を取ります。-
VOLATILE: カウンターの値をメモリーに保存します。カウンターの値はクラスターのシャットダウン時に破棄されます。これがデフォルトの値になります。 -
PERSISTENT: カウンターの値はプライベートなローカル永続ストアに保存されます。カウンターの値は、クラスターのシャットダウン時および起動時に保存されます。
-
strong-counter 要素に固有する属性は次のとおりです。
-
lower-boundは strong カウンターの下限を設定します。デフォルトの値はLong.MIN_VALUEです。 -
upper-boundは strong カウンターの上限を設定します。デフォルトの値はLong.MAX_VALUEです。
initial-value 属性の値は、lower-bound の値と upper-bound の値の間である必要があります。strong カウンターの上限と下限を指定しないと、カウンターはバインドされません。
weak-counter 要素に固有する属性は次のとおりです。
-
concurrency-levelはカウンターの値の最大同時更新数を設定します。値は正の整数である必要があります。デフォルトの値は16です。
14.4.2. クラスター化カウンターのランタイム設定
以下の例のように、EmbeddedCacheManager の初期化後、クラスター化カウンターを起動時にオンデマンドで設定することができます。
CounterManager manager = ...;
// Create three counters.
// The first counter is a strong counter bounded to 10.
manager.defineCounter("counter-1", CounterConfiguration.builder(CounterType.BOUNDED_STRONG).initialValue(1).upperBound(10).build());
// The second counter is an unbounded strong counter.
manager.defineCounter("counter-2", CounterConfiguration.builder(CounterType.UNBOUNDED_STRONG).initialValue(2).build());
// The third counter is a weak counter.
manager.defineCounter("counter-3", CounterConfiguration.builder(CounterType.WEAK).initialValue(3).build());
カウンターが正常に定義された場合、defineCounter() メソッドは true を返し、そうでない場合は false を返します。カウンターの設定が有効でない場合は CounterConfigurationException 例外が発生します。
以下の例のように isDefined() メソッドを使用して、カウンターがすでに定義されているかどうかを判断します。
CounterManager manager = ...
if (!manager.isDefined("someCounter")) {
manager.define("someCounter", ...);
}14.4.3. クラスター化カウンターのプログラムによる設定
以下のコードサンプルは、GlobalConfigurationBuilder を使用してクラスター化カウンターをプログラミングで設定する方法を表しています。
// Set up a clustered cache manager.
GlobalConfigurationBuilder global = GlobalConfigurationBuilder.defaultClusteredBuilder();
// Create a counter configuration builder.
CounterManagerConfigurationBuilder builder = global.addModule(CounterManagerConfigurationBuilder.class);
// Create three counters.
// The first counter is a strong counter bounded to 10.
builder.addStrongCounter().name("counter-1").upperBound(10).initialValue(1);
// The second counter is an unbounded strong counter.
builder.addStrongCounter().name("counter-2").initialValue(2);
// The third counter is a weak counter.
builder.addWeakCounter().name("counter-3").initialValue(3);
// Initialize a new default cache manager.
DefaultCacheManager cacheManager = new DefaultCacheManager(global.build());14.4.3.1. クラスター化カウンターの使用
以下のコードサンプルは、プログラムで作成および定義したクラスター化カウンターを使用する方法を表しています。
// Retrieve the CounterManager interface from the cache manager.
CounterManager counterManager = EmbeddedCounterManagerFactory.asCounterManager(cacheManager);
// Strong counters provide greater consistency than weak counters.
// The value of a strong counter is known during an increment or decrement operation.
// The value of a strong counter can also be bounded in cases where a limit is required.
StrongCounter counter1 = counterManager.getStrongCounter("counter-1");
// All methods are asynchronous and return CompletableFuture objects so that you can perform other operations while the counter value is computed.
counter1.getValue().thenAccept(value -> System.out.println("Counter-1 initial value is " + value)).get();
// Attempt to add a value that exceeds the upper-bound value.
counter1.addAndGet(10).handle((value, throwable) -> {
// Value is null since the counter is bounded to a maximum of 10.
System.out.println("Counter-1 Exception is " + throwable.getMessage());
return 0;
}).get();
// Check the counter value. The value should be 10.
counter1.getValue().thenAccept(value -> System.out.println("Counter-1 value is " + value)).get();
//Decrement the counter value. The new value should be 9.
counter1.decrementAndGet().handle((value, throwable) -> {
// No exception is thrown.
System.out.println("Counter-1 new value is " + value);
return value;
}).get();
// The second counter, counter2, is a strong counter that is unbounded. It never throws the CounterOutOfBoundsException.
StrongCounter counter2 = counterManager.getStrongCounter("counter-2");
// All counters allow a listener to be registered.
// The handle interface can remove the listener.
counter2.addListener(event -> System.out
.println("Counter-2 event: oldValue=" + event.getOldValue() + " newValue=" + event.getNewValue()));
// Adding MAX_VALUE does not throw an exception.
// No increments take effect if the value exceeds the MAX_VALUE.
counter2.addAndGet(Long.MAX_VALUE).thenAccept(aLong -> System.out.println("Counter-2 value is " + aLong)).get();
// Conditional operations are allowed in strong counters.
counter2.compareAndSet(Long.MAX_VALUE, 0)
.thenAccept(aBoolean -> System.out.println("Counter-2 CAS result is " + aBoolean)).get();
counter2.getValue().thenAccept(value -> System.out.println("Counter-2 value is " + value)).get();
// Reset the value of the second counter to its initial value.
counter2.reset().get();
counter2.getValue().thenAccept(value -> System.out.println("Counter-2 initial value is " + value)).get();
// Retrieve the third counter, counter3.
WeakCounter counter3 = counterManager.getWeakCounter("counter-3");
// The value of weak counters is not available during update operations. As a result these counters can increment faster than strong counters.
// The counter value is computed lazily and stored locally.
counter3.add(5).thenAccept(aVoid -> System.out.println("Adding 5 to counter-3 completed!")).get();
// Check the counter value.
System.out.println("Counter-3 value is " + counter3.getValue());
// Stop the cache manager and release all resources.
cacheManager.stop();
Where did the comment section go?
Red Hat's documentation publication system recently went through an upgrade to enable speedier, more mobile-friendly content. We decided to re-evaluate our commenting platform to ensure that it meets your expectations and serves as an optimal feedback mechanism. During this redesign, we invite your input on providing feedback on Red Hat documentation via the discussion platform.