1 背景
假如有一個(gè)服務(wù)的各項(xiàng) JVM 的配置都比較合理的情況下颤专,它的 GC 情況還是不容樂(lè)觀募逞。
然后 dump 了一把內(nèi)存弓摘,一頓分析之后發(fā)現(xiàn)有 2 個(gè)對(duì)象特別巨大娜膘,占了總存活堆內(nèi)存的 76.8%。
其中第 1 大對(duì)象是本地緩存级乍, 使用 caffine 緩存組件舌劳,緩存自動(dòng)刷新周期設(shè)定 1 小時(shí),目的是盡量減少 IO 查詢(xún)次數(shù)玫荣;
由于占用空間很大甚淡,會(huì)導(dǎo)致頻繁GC,影響系統(tǒng)性能捅厂。
如何能盡量緩存較多的數(shù)據(jù)贯卦,同時(shí)避免過(guò)大的 GC 壓力呢底挫?
可以把緩存對(duì)象移到堆外,這樣可以不受堆內(nèi)內(nèi)存大小的限制脸侥;并且堆外內(nèi)存建邓,并不受 JVM GC 的管控,避免了緩存過(guò)大對(duì) GC 的影響睁枕。
堆外內(nèi)存不受堆內(nèi)內(nèi)存大小的限制官边,只受服務(wù)器物理內(nèi)存的大小限制。這三者之間的關(guān)系是這樣的:物理內(nèi)存=堆外內(nèi)存+堆內(nèi)內(nèi)存外遇。
2 堆外緩存
為了緩解在高并發(fā)注簿,高寫(xiě)入操作下,堆內(nèi)緩存組件造成的頻繁GC問(wèn)題跳仿,堆外緩存應(yīng)運(yùn)而生诡渴。堆內(nèi)緩存是受JVM管控的,所以我們不必?fù)?dān)心垃圾回收的問(wèn)題菲语。但是堆外緩存是不受JVM管控的妄辩,所以也不受GC的影響導(dǎo)致的應(yīng)用暫停問(wèn)題。但是由于堆外緩存的使用山上,是以byte數(shù)組來(lái)進(jìn)行的眼耀,所以需要自己進(jìn)行序列化反序列化操作。目前已知的知名開(kāi)源項(xiàng)目中佩憾,netty4的buffer pool采用了堆外緩存實(shí)現(xiàn)哮伟,具體的比對(duì)信息截圖如下:
帶有Direct字眼的即為offheap堆外Buffer,x軸為分配的內(nèi)存大小妄帘,Y軸為耗時(shí)楞黄。從上面可以看出,小塊內(nèi)存分配抡驼,JVM要稍微優(yōu)秀一點(diǎn)鬼廓;但是大塊內(nèi)存分配,明顯的堆外緩存要優(yōu)秀一些婶恼。由于堆外Buffer操作不受GC影響桑阶,實(shí)際上性能更好一些。但是需要的垃圾回收管控也需要自己去做勾邦,要麻煩很多。
2 開(kāi)源堆外緩存組件 OHC
2.1 OHC 介紹
OHC 全稱(chēng)為 off-heap-cache割择,即堆外緩存眷篇,是 2015 年針對(duì) Apache Cassandra 開(kāi)發(fā)的緩存框架,后來(lái)從 Cassandra 項(xiàng)目中獨(dú)立出來(lái)荔泳,成為單獨(dú)的類(lèi)庫(kù)蕉饼,其項(xiàng)目地址為:https://github.com/snazy/ohc
其特性如下:
數(shù)據(jù)存儲(chǔ)在堆外虐杯,只有少量元數(shù)據(jù)存儲(chǔ)堆內(nèi),不影響 GC
支持為每個(gè)緩存項(xiàng)設(shè)置過(guò)期時(shí)間
支持配置 LRU昧港、W_TinyLFU 驅(qū)逐策略
能夠維護(hù)大量的緩存條目
支持異步加載緩存
讀寫(xiě)速度在微秒級(jí)別
OHC具有低延遲擎椰、容量大、不影響GC的特性创肥,并且支持使用方根據(jù)自身業(yè)務(wù)需求進(jìn)行靈活配置达舒。
2.2 OHC 用法
快速開(kāi)始:
OHCache ohCache = OHCacheBuilder.newBuilder().
keySerializer(yourKeySerializer)
.valueSerializer(yourValueSerializer)
.build();
可選配置項(xiàng):
在我們的服務(wù)中,設(shè)置 capacity 容量 12G叹侄,segmentCount 分段數(shù) 1024巩搏,序列化協(xié)議使用 kryo。
2.3 優(yōu)化效果
切換到堆外緩存后趾代,服務(wù) YGC 降低到了 800ms / 每分鐘贯底,端到端的整體吞吐量上漲了約 20%。
2.4 缺點(diǎn)
缺點(diǎn)主要是序列化撒强、反序列化禽捆,如果數(shù)據(jù)查詢(xún)特別高頻,那反序列化的成本就不可忽略了飘哨。
3 應(yīng)用場(chǎng)景
OHC適合將離線(xiàn)數(shù)據(jù)進(jìn)行本地緩存睦擂,從而節(jié)省訪(fǎng)問(wèn)遠(yuǎn)程數(shù)據(jù)庫(kù)的時(shí)間。
網(wǎng)上看到的具體應(yīng)用場(chǎng)景杖玲,主要是在推薦服務(wù)中用到顿仇,比如 Java堆外緩存OHC在馬蜂窩推薦引擎的應(yīng)用 , vivo的推薦服務(wù)計(jì)算中也有用到摆马。