3.5. クラスター化されたキャッシュとの非同期通信

3.5.1. 非同期通信

すべてのクラスター化キャッシュモードは、<replicated-cache/><distributed-cache>、または <invalidation-cache/> 要素上で mode="ASYNC" 属性と非同期通信を使用するように設定できます。

非同期通信では、送信元ノードは操作のステータスについて他のノードから確認応答を受け取ることはありません。そのため、他のノードで成功したかどうかを確認する方法はありません。

非同期通信はデータに不整合を引き起こす可能性があり、結果を推論するのが難しいため、一般的に非同期通信はお勧めしません。ただし、速度が一貫性よりも重要であり、このようなケースでオプションが利用できる場合があります。

3.5.2. Asynchronous API

非同期 API を使用すると、ユーザースレッドをブロックしなくても同期通信を使用できます。

注意点が 1 つあります。非同期操作はプログラムの順序を保持しません。スレッドが cache.putAsync(k, v1); cache.putAsync(k, v2) を呼び出す場合の k の最終的な値は v1 または v2 のいずれかになります。非同期通信を使用する場合の利点は、最終的な値をあるノードで v1 にして別のノードで v2 にすることができないことです。

3.5.3. 非同期通信で値を返す

Cache インターフェイスは java.util.Map を拡張するため、put(key, value)remove(key) などの書き込みメソッドはデフォルトで以前の値を返します。

戻り値が正しくないことがあります。

  1. Flag.IGNORE_RETURN_VALUEFlag.SKIP_REMOTE_LOOKUP、または Flag.SKIP_CACHE_LOADAdvancedCache.withFlags() を使用する場合。
  2. キャッシュに unreliable-return-values="true" が設定されている場合。
  3. 非同期通信を使用する場合。
  4. 同じキーへの同時書き込みが複数あり、キャッシュトポロジーが変更された場合。トポロジーの変更により、Data Grid は書き込み操作を再試行します。また、再試行操作の戻り値は信頼性がありません。

トランザクションキャッシュは、3 と 4 の場合、正しい以前の値を返します。しかし、トランザクションキャッシュには gotcha: in distributed モードもあり、read-committed 分離レベルは、繰り返し可能な読み取りとして実装されます。つまり、この"double-checked locking"例は機能しません。

Cache cache = ...
TransactionManager tm = ...

tm.begin();
try {
   Integer v1 = cache.get(k);
   // Increment the value
   Integer v2 = cache.put(k, v1 + 1);
   if (Objects.equals(v1, v2) {
      // success
   } else {
      // retry
   }
} finally {
  tm.commit();
}

これを実装する適切な方法として、cache.getAdvancedCache().withFlags(Flag.FORCE_WRITE_LOCK).get(k) を使用します。

最適化されたロックを持つキャッシュでは、書き込みは古い以前の値を返すことができます。書き込み skew チェックでは、古い値を回避できます。