[Coherence] Throttling Cache Events

原文はこちら。
https://blogs.oracle.com/felcey/entry/throttling_cache_events

Oracle Coherenceのリアルタイムイベント機能は状態の変化を他システムやユーザに伝達する上ですばらしい機能ですが、全ての変更が必要なものであるとは限らず、全ての変更をコンシューマに送信できるわけではなかったりします。例えば…
  • 急速な変化を送信されるスピードに合わせて消費/解釈できない場合。株価の変化を見ている利用者は秒間1回の変更にしか解釈・対応できません。
  • クライアントが低帯域の接続を使っている可能性があるので、迅速にイベントを送信すると結果としてQueueにたまり遅延が発生するだけになってしまいます。
  • 非常に数多くのクライアントが状態変化の通知を必要とし、秒間100イベントを1000クライアントに送信することは利用可能なハードウェアではサポートできませんが、秒間10イベントを1000クライアントに送信することは叶です。この例では状態変化の多くは同じ値にしていることを前提にしていますので、ご注意下さい。
Coherenceのキャッシュイベントをスロットリング(絞り込み)への一つの簡単な方法として、キャッシュストアを使ってあるキャッシュ(データキャッシュ)への変化を捕まえ、その変化を定期的に別のキャッシュ(イベントキャッシュ)に挿入するという方法があります。最初のキャッシュの状態変化に関心があるコンシューマは関心(イベントリスナ)を第2のイベントキャッシュに対して登録します。キャッシュストアのwrite-behind機能を使って同一のキャッシュエントリの高速な更新をまとめて更新をマージし、設定した時間間隔でイベントキャッシュに書き込みます。変化をイベントキャッシュに書き込む時間間隔は、キャッシュ構成ファイルのwrite-behindの遅延時間を使って容易に設定可能です。以下の構成ファイルでは、<write-delay>要素の値がそれに相当します。

    
      CustomDistributedCacheScheme
      CustomDistributedCacheService
      1
      
        
          CustomRWBackingMapScheme
          
            
          
          
            
              CustomCacheStoreScheme
              com.oracle.coherence.test.CustomCacheStore
              
                
                  java.lang.String{cache-name}
                
                  java.lang.Stringcqc-test
              
            
          
          1s
          0
        
      
      true
    
  
このスロットリングを実現するキャッシュストアの実装はそれほど難しいものではなく、基本的なキャッシュストアの機能をオーバーライドするだけです。
public class CustomCacheStore implements CacheStore {
 private String publishingCacheName;
 private String sourceCacheName;

 public CustomCacheStore(String sourceCacheStore, String publishingCacheName) {
  this.publishingCacheName = publishingCacheName;
  this.sourceCacheName = sourceCacheName;
 }

 @Override
 public Object load(Object key) {
  return null;
 }

 @Override
 public Map loadAll(Collection keyCollection) {
  return null;
 }

 @Override
 public void erase(Object key) {
  if (sourceCacheName != publishingCacheName) {
   CacheFactory.getCache(publishingCacheName).remove(key);
   CacheFactory.log("Erasing entry: " + key, CacheFactory.LOG_DEBUG);
  }
 }

 @Override
 public void eraseAll(Collection keyCollection) {
  if (sourceCacheName != publishingCacheName) {
   for (Object key : keyCollection) {
    CacheFactory.getCache(publishingCacheName).remove(key);
    CacheFactory.log("Erasing collection entry: " + key,
      CacheFactory.LOG_DEBUG);
   }
  }
 }

 @Override
 public void store(Object key, Object value) {
  if (sourceCacheName != publishingCacheName) {
   CacheFactory.getCache(publishingCacheName).put(key, value);
   CacheFactory.log("Storing entry (key=value): " + key + "=" + value,
     CacheFactory.LOG_DEBUG);
  }
 }

 @Override
 public void storeAll(Map entryMap) {
  if (sourceCacheName != publishingCacheName) {
   CacheFactory.getCache(publishingCacheName).putAll(entryMap);
   CacheFactory.log("Storing entries: " + entryMap,
     CacheFactory.LOG_DEBUG);
  }
 }
} 
おわかりのように、各キャッシュストアのデータキャッシュへの操作の結果、イベントキャッシュへの類似した操作になります。これはたくさんの可能性がある非常に単純なパターンですが、いくつかの欠点に注意しておく必要があります。
  • このイベントスロットリングの実装では、データキャッシュに保持するエントリの複製コピーはイベントキャッシュにも保持する必要があるので、余分にメモリを使います。イベントキャッシュにバックアップを持つ場合、2倍必要です。
  • データキャッシュは既にキャッシュストアを使っている可能性があるので、「多重化キャッシュストアパターン」を使って変更を既存のキャッシュストアやスロットリング対象のキャッシュストアに送信する必要があります。 
このスロットリングのサンプルを試したいということでしたら、こちらからサンプルをダウンロードできます。お役に立てば光栄です。さらなる最適化の目星がついたら是非教えて下さい。
[参考]
Oracle® Coherence Developer's Guide Release 3.7.1
Oracle® Coherence開発者ガイド リリース3.7.1

0 件のコメント:

コメントを投稿