堆內緩存:
- LinkedHashMap:Java自帶類,內置LRU驅逐策略的實現(access-order);多線程訪問需要自己實現同步。
- Guava Cache:Google Guava工具包中的緩存實現,支持LRU驅逐策略;支持多線程併發訪問,支持按時間過期,但只有在訪問時才清除過期數據。
- Ehcache:支持多種驅逐策略:LFU、LRU、FIFO,支持持久化和集羣。性能跟Guava Cache比相當。
- Caffeine:支持W-TinyLFU驅逐策略,Benchmark測試讀寫性能是Guava Cache的6倍左右。
堆外緩存:
- OHCache:支持緩存驅逐和過期(Cassandra使用的緩存庫)
- ChronicleMap:支持Hash結構,性能好,不支持緩存驅逐
- MapDB:支持Tree結構,可順序掃描,不支持緩存驅逐
- Ehcache3:BigMemory收費
當緩存數據量非常大時,GC壓力過大會導致服務響應慢甚至崩潰,在HugeGraph圖數據庫中爲了緩解該問題,需引入堆外緩存,選擇了使用OHCache。
OHCache對外緩存總結
開源:https://github.com/snazy/ohc
特性:
- 底層有2種實現:linked實現,適用於中大entry場景,默認實現,大部分feature只在該實現中才支持;chunked實現,適用於小entry場景,通過設置chunkSize或者fixedEntrySize啓用。
- 通過eviction()來設置緩存驅逐策略,支持:LRU, W_TINY_LFU, NONE共3種,後兩種僅在linked實現中支持。
- 通過capacity()來指定緩存的容量,單位是字節,注意不是條數。
- 通過hashTableSize()來設置每個hash_table最大存放的entry個數數量(默認是0.75的factor)。
- 必須指定自定義的keySerializer、valueSerializer系列化器,重載實現系列化serialize()方法與反序列化deserialize()方法;需要注意的是還需要重載serializedSize()方法,且該方法返回值必須和實際寫入的內容大小完全一樣,否則會報錯或數據不對。
- 支持緩存條目過期機制,通過timeouts()開啓;允許通過defaultTTLmillis()設置一個默認過期時間,也可以在put()的時候單獨設置expireAt過期時間。注意:過期機制僅linked實現才支持,因爲chunked實現是以chunk爲單位進行緩存驅逐的,無法精確到entry粒度;而且並沒有獨立的線程來回收過期條目,只會在get或put操作時進行檢查(見get()或者ensureFreeSpaceForNewEntry()),若過期則刪除,詳細代碼見Timeouts.removeExpired()。
- 可以通過getWithLoader()來利用線程池異步加載數據。
- 建議使用jemalloc來減少內存碎片。
- 實際的內存佔用:daa_capacity + segment_count * hash_table_size * 8,一個cache包括segment_count個hash_table,segment_count默認是2 * CPUs;一個hash_table的存放8字節*表大小個的entry地址信息。每個entry都帶着頭部(linked實現佔64字節,chunked實現若定長KV則佔16字節否則佔24字節),頭部後面是鍵值數據,頭部包括:前/後指針、鍵/值大小、引用數等。
Configures and builds OHC instance:
Field | Meaning | Default |
---|---|---|
keySerializer | Serializer implementation used for keys | Must be configured |
valueSerializer | Serializer implementation used for values | Must be configured |
executorService | Executor service required for get operations using a cache loader. E.g. OHCache.getWithLoaderAsync(Object, CacheLoader) | (Not configured by default meaning get operations with cache loader not supported by default) |
segmentCount | Number of segments | 2 * number of CPUs (java.lang.Runtime.availableProcessors()) |
hashTableSize | Initial size of each segment’s hash table | 8192 |
loadFactor | Hash table load factor. I.e. determines when rehashing occurs. | .75f |
capacity | Capacity of the cache in bytes | 16 MB * number of CPUs (java.lang.Runtime.availableProcessors()), minimum 64 MB |
chunkSize | If set and positive, the chunked implementation will be used and each segment will be divided into this amount of chunks. | 0 - i.e. linked implementation will be used |
fixedEntrySize | If set and positive, the chunked implementation with fixed sized entries will be used. The parameter chunkSize must be set for fixed-sized entries. | 0 - i.e. linked implementation will be used, if chunkSize is also 0 |
maxEntrySize | Maximum size of a hash entry (including header, serialized key + serialized value) | (not set, defaults to capacity divided by number of segments) |
throwOOME | Throw OutOfMemoryError if off-heap allocation fails | false |
hashAlgorighm | Hash algorithm to use internally. Valid options are: XX for xx-hash, MURMUR3 or CRC32 Note: this setting does may only help to improve throughput in rare situations - i.e. if the key is very long and you’ve proven that it really improves performace | MURMUR3 |
unlocked | If set to true, implementations will not perform any locking. The calling code has to take care of synchronized access. In order to create an instance for a thread-per-core implementation, set segmentCount=1, too. | false |
defaultTTLmillis | If set to a value > 0, implementations supporting TTLs will tag all entries with the given TTL in milliseconds. | 0 |
timeoutsSlots | The number of timeouts slots for each segment - compare with hashed wheel timer. | 64 |
timeoutsPrecision | The amount of time in milliseconds for each timeouts-slot. | 128 |
ticker | Indirection for current time - used for unit tests. | Default ticker using System.nanoTime() and System.currentTimeMillis() |
Expected number of elements in the cache | No default value, recommended to provide a default value. | |
eviction | Choose the eviction algorithm to use. Available are:LRU: Plain LRU - least used entry is subject to evictionW-WinyLFU: Enable use of Window Tiny-LFU. The size of the frequency sketch (“admission filter”) is set to the value of hashTableSize. See this article for a description.None: No entries will be evicted - this effectively provides a capacity-bounded off-heap map. | LRU |
frequencySketchSize | Size of the frequency sketch used by W-WinyLFU | Defaults to hashTableSize. |
edenSize | Size of the eden generation used by W-WinyLFU relative to a segment’s size | 0.2 |
文檔地址:https://javadoc.io/static/org.caffinitas.ohc/ohc-core/0.7.0/org/caffinitas/ohc/OHCacheBuilder.html