Hibernate専用キャッシュを自作してみる(その2)

前回は、限定された要件を満たす最低限のシンプルな実装を作成してみました。今回は、OSCache と EhCache とのベンチマークをしてみます。

自作キャッシュは、とりあえず OfCache という名前にしておきます。

要件

前回の要件を適用します。

環境

・おいらのノートPC
・シングルCPU、シングルコア

設定

EhCache
<ehcache>
  <!-- Cache configuration -->
  <defaultCache
    maxElementsInMemory="10000000"
    eternal="true"
    overflowToDisk="false"
    timeToIdleSeconds="0"
    timeToLiveSeconds="0"
    diskPersistent="false"
    memoryStoreEvictionPolicy="LRU"
  />
  <cache
    name="simpleGetTest"
    maxElementsInMemory="10000000"
    eternal="true"
    overflowToDisk="false"
    timeToIdleSeconds="0"
    timeToLiveSeconds="0"
    diskPersistent="false"
    memoryStoreEvictionPolicy="LRU"
  />
  <cache
    name="concurrentGetTestWithNoEntryLevelConcurrency"
    maxElementsInMemory="10000000"
    eternal="true"
    overflowToDisk="false"
    timeToIdleSeconds="0"
    timeToLiveSeconds="0"
    diskPersistent="false"
    memoryStoreEvictionPolicy="LRU"
  />
  <cache
    name="concurrentRandomGetTest"
    maxElementsInMemory="10000000"
    eternal="true"
    overflowToDisk="false"
    timeToIdleSeconds="0"
    timeToLiveSeconds="0"
    diskPersistent="false"
    memoryStoreEvictionPolicy="LRU"
  />
</ehcache>
OSCache
cache.memory=true
cache.capacity=-1
cache.algorithm=com.opensymphony.oscache.base.algorithm.UnlimitedCache
cache.blocking=false
OfCache
デフォルト

ベンチマーキング

メモリ消費量(100万件put。key=Integer, value=new Object())
キャッシュ種別 使用メモリ
EhCache 143,658,232 Bytes
OSCache 327,277,872 Bytes
OfCache 56,386,816 Bytes
  • EhCacheは、今回のユーザー要件に必要ない多くのメタ情報をエントリに持たせるため、メモリを浪費していると考えられます。メタ情報が必要ない要件にはそれに応じた実装が使えるといいのですが。
  • OSCacheは、キーをStringに変換して持つ仕様であることが、オンメモリキャッシュとして致命的なメモリの浪費を引き起こしています。
  • OfCacheは、シンプルなキャッシュなので、必要最低限のメモリしか消費していません。
get100万回
EhCache OSCache OfCache
938 ms 2,469 ms 688 ms
  • EhCache と OfCache の速度はそれほど変わりません。OfCache にも統計情報その他の処理を追加すると、差は縮まると考えられます。
  • OSCacheは、かなり遅いです。キーを文字列にしていることが大きく影響していそうです。
get100万回、10スレッド並行、並行アクセスされるエントリなし
EhCache OSCache OfCache
11,328 ms 64,657 ms 3,844 ms
  • OfCache はダントツに速いです。EhCache は、getメソッドそのものをsynchronizedにしているため、複数スレッドの同時アクセスができないというのが大きな理由でしょう。
  • OSCache はダントツに遅いです。OfCacheの15倍以上遅いです。
get100万回、10スレッド並行、keyは100種類でランダムアクセス
EhCache OSCache OfCache
12,235 ms 18,110 ms 2,719 ms
  • ここでも OfCache はダントツに速いです。OfCache は、同一エントリへのgetでも並行アクセスが可能なので高速です。
  • OSCache は、キーの種類が少ないほうが高速に動作するようです。(ソースは追ってませんので確証はありませんが)
get/put100万回、10スレッド並行、keyは100種類でランダムアクセス
EhCache OSCache OfCache
11,766 ms 33,610 ms 3,329 ms
  • ここでも OfCache はダントツに速いです。OfCache は、put時もある程度の並行アクセスが可能なので、put が混ざっても大きな性能低下がありません。
  • EhCache は、getもputも並行動作ができないので、putが混在しても性能に変化はありません。
  • OSCache は、ダントツに遅いです。OfCacheの10倍以上遅いです。ヒープは1GBあるし、使用メモリを監視して、容量の限界に近づいたことによるGCの頻発でないことは確認しました。ここまで差があると、実験方法自体を疑ってかかりたくなりますが、、、。