2009-10-05 8 views
13

私はトラフィックの多いWebサイトを持っており、私は休止状態を使用しています。また、ehcacheを使用して、ページを生成するために必要なエンティティとクエリをキャッシュします。同じキャッシュ領域の複数の再作成を避ける(並行性のため)

問題は「並列キャッシュミス」であり、長い説明は、アプリケーションが起動してキャッシュ領域が冷たくなったときに、各キャッシュ領域がサイトが存在するために異なるスレッドによって何回も(1回ではなく)同時に多くのユーザーにヒットします。さらに、キャッシュ領域が無効になると、同じ理由で何回も再投入されます。 どうすればこの問題を回避できますか?

私は自分の実装をhibernate.cache.provider_classに提供することによってconvert 1 entity and 1 query cache to a BlockingCacheに管理しましたが、BlockingCacheのセマンティクスは機能していないようです。最悪の場合でも、BlockingCacheデッドロック(ブロック)が発生し、アプリケーションが完全にハングします。スレッドダンプは、get操作でBlockingCacheのmutexで処理がブロックされていることを示します。

したがって、Hibernateはこの種の使用をサポートしていますか?

もしそうでなければ、本番環境でこの問題をどのように解決しますか?

編集hibernate.cache.provider_classポイントSingletonEhCacheProviderからコピーペーストである私のカスタムキャッシュ・プロバイダーへとstart()メソッド(ライン136の後に)私がやるの終わりに:

Ehcache cache = manager.getEhcache("foo"); 
if (!(cache instanceof BlockingCache)) { 
    manager.replaceCacheWithDecoratedCache(cache, new BlockingCache(cache)); 
} 

初期化時に、誰かが "foo"という名前のキャッシュにアクセスする前に、私はそれをBlockingCacheで飾ります。 "foo"はクエリキャッシュであり、 "bar"(同じコードが省略されている)はpojoのエンティティキャッシュです。

編集2:「動作していない」とは、最初の問題がまだ存在することを意味します。キャッシュ "foo"は、並行性のために同じデータで何度も再配置されています。 10個のスレッドでJMeterを使ってサイトにストレスをかけて検証します。私は9つのスレッドが "foo"からデータを要求して(クエリを実行し、キャッシュにデータを格納する)、データをキャッシュから直接取得するまで、ブロックすることを期待しています。

編集3:この問題の別の説明はhttps://forum.hibernate.org/viewtopic.php?f=1&t=964391&start=0ですが、明確な回答はありません。

+0

アン興味深い開発は、今ではehcacheを次のとおりです。http://stackoverflow.com/questions/3472613/does-ehcache-2-1-support -the-transactional-cache-concurrency-in-hibernat/3474011#3474011 – cherouvim

答えて

1

この問題に関する最も大きな改善がsupports the transactional hibernate cache policy(2.1以降)になりましたことにehcacheです。これにより、この問題で説明されている問題が大幅に緩和されます。

さらに進んで(同じクエリキャッシュ領域にアクセスしている間にスレッドをロックする)、QueryTranslatorFactoryを実装して、クエリおよびパラメータを検査し、必要に応じてブロックするカスタム(拡張)QueryTranslatorImplインスタンスを返す必要があります方法。これはもちろん、多くのエンティティをフェッチするhqlを使用するクエリキャッシュの特定のユースケースを考慮しています。休止状態のトランザクションキャッシュ同時方式をサポートしています(2.1以降)この問題を軽減するのに役立つかもしれ

5

私はかなりわからないんだけど、:

それがすでにキャッシュ内 要素への同時読み取りアクセスを許可します。 要素がnullの場合、同じ キーを持つ要素がキャッシュに格納されるまで、他の読み取りは ブロックになります。

これは、他のスレッドがオブジェクトをキャッシュに入れるまでHibernateが待機することを意味しませんか?それはあなたが観察するものです、そうですか?

のHibとキャッシュは次のように機能します。

  1. のHibオブジェクトがキャッシュ内にある場合、オブジェクト
  2. のHibチェックの要求を取得します - キャッシュ。get()
  3. いいえ? HibはDBからオブジェクトをロードしてcache-put()に入れます。

オブジェクトがキャッシュに存在しない場合(以前の更新操作によってそこに配置されていない場合)、Hibは1)永遠に待機します。

私はあなたのスレッドが短時間だけのためのオブジェクトを待ちキャッシュバリアントが必要だと思います。例えば。 100ms。オブジェクトが到着していなければ、スレッドはヌルになります(したがって、HibernateはDBからオブジェクトをロードしてキャッシュに配置します)。

実際には、より良いロジックは次のようになります。trueの場合、別のスレッドが

  • 同じオブジェクトを要求して、長い(500ミリ秒)を待つこと

    1. チェック真実ではない場合
    2. に到着するオブジェクトについてすぐにnullを返す

    (例外のために、スレッドがオブジェクトをキャッシュに入れることができないため、永遠に2を待つことはできません)。

    BlockingCacheがこの動作をサポートしていない場合は、自分でキャッシュを実装する必要があります。私は過去にそれをしました、それは難しいことではありません - 主なメソッドはget()とput()です(APIはそれ以降明らかに成長しましたが)。

    UPDATE

    実は、私はちょうどBlockingCacheのソースを読んで。それは私が言ったことを正確に行います - ロックしてタイムアウトを待ちます。したがって、何もする必要はありません。ただ使用してください。

    public Element get(final Object key) throws RuntimeException, LockTimeoutException { 
        Sync lock = getLockForKey(key); 
        Element element; 
         acquiredLockForKey(key, lock, LockType.WRITE); 
         element = cache.get(key); 
         if (element != null) { 
          lock.unlock(LockType.WRITE); 
         } 
        return element; 
    } 
    
    public void put(Element element) { 
        if (element == null) { 
         return; 
        } 
        Object key = element.getObjectKey(); 
        Object value = element.getObjectValue(); 
    
        getLockForKey(key).lock(LockType.WRITE); 
        try { 
         if (value != null) { 
          cache.put(element); 
         } else { 
          cache.remove(key); 
         } 
        } finally { 
         getLockForKey(key).unlock(LockType.WRITE); 
        } 
    } 
    

    それはあなたのためにはうんざりです。教えてください:あなたのコードでこのスポット:

    Ehcache cache = manager.getEhcache("foo"); 
    

    は同期していますか?複数のリクエストが同時に発生した場合、キャッシュのインスタンスは1つだけになりますか?

  • +0

    あなたの答えをありがとう。私はこの問題を解決するために、冬眠とehcacheで低レベルにする必要があると考えるのは難しいです。 – cherouvim

    +0

    同期されていませんが、一度だけ呼び出されています。何かが始まる前に一度だけ呼び出されているBlockingCacheProviderのpublic final void startの下にあります。 – cherouvim

    関連する問題