第14章 クラスター化カウンター


クラスター化カウンターは、Red Hat JBoss Data Grid クラスターのノードすべてで分散および共有されます。クラスター化カウンターを使用するとオブジェクトの数を記録することができます。

クラスター化カウンターは名前で識別され、値 (デフォルトは 0) で初期化されます。クラスター化カウンターを永続化して、クラスターの再起動後に値を保持することもできます。

クラスター化カウンターには次の 2 種類があります。

  • Strong はカウンターの値を単一のキーに保存して一貫性を保ちます。カウンターの更新中でも値は認識できます。カウンター値の更新は、キーロック下で実行されます。しかし、カウンターの現在値を読み取るのに必要なロックはありません。Strong カウンターでは、カウンター値をバインドでき、compareAndSetcompareAndSwap などのアトミック操作を提供します。
  • 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 カウンターへの変更が発生したときにイベントを返します。
  • HandleCounterListener インターフェースを拡張します。

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();
Red Hat logoGithubRedditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

Red Hat ドキュメントについて

Red Hat をお使いのお客様が、信頼できるコンテンツが含まれている製品やサービスを活用することで、イノベーションを行い、目標を達成できるようにします。

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

© 2024 Red Hat, Inc.