2

最近、Terracotta で EHCache を使用して、アプリケーション データの分散データ キャッシュを実行し始めました。クライアント ノードにはヒープ用に約 2 GB があり、サーバー ノードには 8 GB があるとします。1日あたり約1.5GBの大量のデータを生成します。

通常、1 つのクライアントは特定の日のデータセット (約 1.5 GB) を使用しますが、サーバーは明らかにそれらすべてを保持する必要があります。

有効期限が機能する方法は、ヒープが大きくなったときの LRU ベースです。したがって、特定の L1 クライアント側のキャッシュが大きくなりすぎた場合 (たとえば、day1 から day2 に切り替えた場合)、L1 から day1 のすべてのデータを追い出すことが期待されます。6 番目のデータセットを取得するときに L2 が大きくなりすぎると、最も古いデータセットが完全に期限切れになります。Time-to-Live や Time-to-Idle の値がどうあるべきかについて、私は特に意見を持っていないので、未設定のままにしています。

それを数日見た後、これが期待どおりに機能しているとは思えません。たとえば、L2 の最大要素数を 4 にしてテストを実行しました。4 つの要素を入力しました。次に、5番目の要素を配置しました。Cache.put() は例外なく返されましたが、直後に同じキーを持つ Cache.get() が null を返しました!

私の質問は、どうすれば EHCache+Terracotta に自分のやりたいこと、または少なくともそれに近いことをさせることができるでしょうか?

4

1 に答える 1

1

いろいろいじった後、不思議な動作は、L1 キャッシュが L2 キャッシュの内容を知っているかどうかによって決定されることがわかりました。添付された単体テストはペアで実行されることを意図しており、ペアの各要素は個別の JVM で実行され、EHCache のシングルトン性を回避します。

行儀の良い L1->L2 関係が機能するはずだと私が考える方法は、エラーなしで .put() を実行すると、問題なく直後に同じキーの get() を実行できるはずです (同時に実行されている他のスレッドは何もいじっていません)。ただし、Terracotta EHCache では、その .put() で何かを削除する必要がある場合、L1 クライアントが削除できるキーを「認識」しない限り、削除は行われず、put() は黙って無視されます。*JVM2 テストでは、.getAllWithLoader() を使用してこれらの他のキーを検出し、*JVM2 テストは期待どおりに機能します。

オリジナルに対処するために行ったことは、定期的にクライアントが .getAllWithLoader() を実行するようにすることです。その後、すべてのエビクション ルールが守られていることを確認できます。

package com.mine;

import java.io.Serializable;

import junit.framework.TestCase;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.config.Configuration;
import net.sf.ehcache.config.TerracottaClientConfiguration;
import net.sf.ehcache.config.TerracottaConfiguration;

public class CacheEvictionTest extends TestCase {

    private static final String SERVER = "localhost:9510";
    private CacheManager cacheManager;
    private Cache cache;
    private final Serializable keyA = "a";
    private final Serializable keyB = "b";
    private final Serializable keyC = "c";

    @Override
    protected void setUp() throws Exception {
        Configuration configuration = new Configuration();
        TerracottaClientConfiguration terracottaConfig = new TerracottaClientConfiguration();
        terracottaConfig.setUrl(SERVER);
        configuration.addTerracottaConfig(terracottaConfig);

        int maxElementsInMemory = 1;
        int maxElementsOnDisk = 2;
        long timeToIdleSeconds = 15;
        long timeToLiveSeconds = 15;
        String cacheName = "TEST_CACHE";
        CacheConfiguration amoebaCache = new CacheConfiguration(cacheName, maxElementsInMemory).statistics(true)
                        .terracotta(new TerracottaConfiguration())
                        .logging(true)
                        .maxElementsOnDisk(maxElementsOnDisk)
                        .timeToIdleSeconds(timeToIdleSeconds)
                        .timeToLiveSeconds(timeToLiveSeconds);
        configuration.addCache(amoebaCache);
        configuration.addDefaultCache(new CacheConfiguration("default", 0));

        cacheManager = new CacheManager(configuration);
        cache = cacheManager.getCache(cacheName);
    }

    @Override
    protected void tearDown() throws Exception {
        if (cache != null) {
            cache.removeAll();
            cache.clearStatistics();
        }
    }

    public void testMaxElementOnDiskEvictionJVM1() throws Exception {
        cache.clearStatistics();

        cache.put(new Element(keyA, keyA));
        cache.put(new Element(keyB, keyB));

        cache = null;
    }

    public void testMaxElementOnDiskEvictionJVM2() throws Exception {
        assertEquals(2, cache.getSize());

        for (Object key : cache.getKeys()) {
            cache.get(key;
        }

        cache.put(new Element(keyC, keyC));

        assertEquals(2, cache.getSize());
        assertNotNull(cache.get(keyC));
    }

    public void testEvictsExpiredElementsFromDiskWhenNotInMemoryAndWeNeverKnewAboutItJVM1() throws Exception {
        cache.clearStatistics();
        cache.put(new Element(keyA, keyA));

        cache = null;
        cacheManager = null;
    }

    public void testEvictsExpiredElementsFromDiskWhenNotInMemoryAndWeNeverKnewAboutItJVM2() throws Exception {
        cache.clearStatistics();

        for (Object key : cache.getKeys()) {
            cache.get(key;
        }
        assertEquals(0, cache.getStatistics().getEvictionCount());

        Thread.sleep(20000);

        assertEquals(1, cache.getStatistics().getEvictionCount());
    }
}
于 2011-03-09T14:52:33.880 に答える