www.久久久久|狼友网站av天堂|精品国产无码a片|一级av色欲av|91在线播放视频|亚洲无码主播在线|国产精品草久在线|明星AV网站在线|污污内射久久一区|婷婷综合视频网站

當(dāng)前位置:首頁 > 公眾號精選 > 架構(gòu)師社區(qū)
[導(dǎo)讀]一、簡介Caffeine是基于Java8開發(fā)的、提供了近乎最佳命中率的高性能本地緩存組件,Spring5開始不再支持GuavaCache,改為使用Caffeine。下面是Caffeine官方測試報告。由上面三幅圖可見:不管在并發(fā)讀、并發(fā)寫還是并發(fā)讀寫的場景下,Caffeine的性...

一、簡介


Caffeine 是基于Java 8 開發(fā)的、提供了近乎最佳命中率的高性能本地緩存組件,Spring5 開始不再支持 Guava Cache,改為使用 Caffeine。


下面是 Caffeine 官方測試報告。


高性能緩存?Caffeine?原理及實戰(zhàn)

高性能緩存?Caffeine?原理及實戰(zhàn)

高性能緩存?Caffeine?原理及實戰(zhàn)


由上面三幅圖可見:不管在并發(fā)讀、并發(fā)寫還是并發(fā)讀寫的場景下,Caffeine 的性能都大幅領(lǐng)先于其他本地開源緩存組件。


本文先介紹 Caffeine 實現(xiàn)原理,再講解如何在項目中使用 Caffeine 。



?二、Caffeine 原理


2.1 淘汰算法


2.1.1 常見算法


對于 Java 進程內(nèi)緩存我們可以通過 HashMap 來實現(xiàn)。不過,Java 進程內(nèi)存是有限的,不可能無限地往里面放緩存對象。這就需要有合適的算法輔助我們淘汰掉使用價值相對不高的對象,為新進的對象留有空間。常見的緩存淘汰算法有 FIFO、LRU、LFU。


FIFO(First In First Out):先進先出。它是優(yōu)先淘汰掉最先緩存的數(shù)據(jù)、是最簡單的淘汰算法。缺點是如果先緩存的數(shù)據(jù)使用頻率比較高的話,那么該數(shù)據(jù)就不停地進進出出,因此它的緩存命中率比較低。


LRU(Least Recently Used):最近最久未使用。它是優(yōu)先淘汰掉最久未訪問到的數(shù)據(jù)。缺點是不能很好地應(yīng)對偶然的突發(fā)流量。比如一個數(shù)據(jù)在一分鐘內(nèi)的前59秒訪問很多次,而在最后1秒沒有訪問,但是有一批冷門數(shù)據(jù)在最后一秒進入緩存,那么熱點數(shù)據(jù)就會被沖刷掉。


LFU(Least Frequently Used):最近最少頻率使用。它是優(yōu)先淘汰掉最不經(jīng)常使用的數(shù)據(jù),需要維護一個表示使用頻率的字段。

主要有兩個缺點:

一、如果訪問頻率比較高的話,頻率字段會占據(jù)一定的空間;

二、無法合理更新新上的熱點數(shù)據(jù),比如某個歌手的老歌播放歷史較多,新出的歌如果和老歌一起排序的話,就永無出頭之日。


2.1.2 W-TinyLFU 算法


Caffeine 使用了 W-TinyLFU 算法,解決了 LRU 和LFU上述的缺點。W-TinyLFU 算法由論文《TinyLFU: A Highly Efficient Cache Admission Policy》提出。


它主要干了兩件事:

一、采用 Count–Min Sketch 算法降低頻率信息帶來的內(nèi)存消耗;

二、維護一個PK機制保障新上的熱點數(shù)據(jù)能夠緩存。


如下圖所示,Count–Min Sketch 算法類似布隆過濾器 (Bloom filter)思想,對于頻率統(tǒng)計我們其實不需要一個精確值。存儲數(shù)據(jù)時,對key進行多次 hash 函數(shù)運算后,二維數(shù)組不同位置存儲頻率(Caffeine 實際實現(xiàn)的時候是用一維 long 型數(shù)組,每個 long 型數(shù)字切分成16份,每份4bit,默認(rèn)15次為最高訪問頻率,每個key實際 hash 了四次,落在不同 long 型數(shù)字的16份中某個位置)。讀取某個key的訪問次數(shù)時,會比較所有位置上的頻率值,取最小值返回。對于所有key的訪問頻率之和有個最大值,當(dāng)達到最大值時,會進行reset即對各個緩存key的頻率除以2。


高性能緩存?Caffeine?原理及實戰(zhàn)


如下圖緩存訪問頻率存儲主要分為兩大部分,即 LRU 和 Segmented LRU 。新訪問的數(shù)據(jù)會進入第一個 LRU,在 Caffeine 里叫 WindowDeque。當(dāng) WindowDeque 滿時,會進入 Segmented LRU 中的 ProbationDeque,在后續(xù)被訪問到時,它會被提升到 ProtectedDeque。當(dāng) ProtectedDeque 滿時,會有數(shù)據(jù)降級到 ProbationDeque 。數(shù)據(jù)需要淘汰的時候,對 ProbationDeque 中的數(shù)據(jù)進行淘汰。具體淘汰機制:取ProbationDeque 中的隊首和隊尾進行 PK,隊首數(shù)據(jù)是最先進入隊列的,稱為受害者,隊尾的數(shù)據(jù)稱為攻擊者,比較兩者 頻率大小,大勝小汰。


高性能緩存?Caffeine?原理及實戰(zhàn)


總的來說,通過 reset 衰減,避免歷史熱點數(shù)據(jù)由于頻率值比較高一直淘汰不掉,并且通過對訪問隊列分成三段,這樣避免了新加入的熱點數(shù)據(jù)早早地被淘汰掉。


2.2 高性能讀寫


Caffeine 認(rèn)為讀操作是頻繁的,寫操作是偶爾的,讀寫都是異步線程更新頻率信息。


2.2.1 讀緩沖


傳統(tǒng)的緩存實現(xiàn)將會為每個操作加鎖,以便能夠安全的對每個訪問隊列的元素進行排序。一種優(yōu)化方案是將每個操作按序加入到緩沖區(qū)中進行批處理操作。讀完把數(shù)據(jù)放到環(huán)形隊列 RingBuffer 中,為了減少讀并發(fā),采用多個 RingBuffer,每個線程都有對應(yīng)的 RingBuffer。環(huán)形隊列是一個定長數(shù)組,提供高性能的能力并最大程度上減少了 GC所帶來的性能開銷。數(shù)據(jù)丟到隊列之后就返回讀取結(jié)果,類似于數(shù)據(jù)庫的WAL機制,和ConcurrentHashMap 讀取數(shù)據(jù)相比,僅僅多了把數(shù)據(jù)放到隊列這一步。異步線程并發(fā)讀取 RingBuffer 數(shù)組,更新訪問信息,這邊的線程池使用的是下文實戰(zhàn)小節(jié)講的 Caffeine 配置參數(shù)中的 executor。


高性能緩存?Caffeine?原理及實戰(zhàn)

2.2.2 寫緩沖


與讀緩沖類似,寫緩沖是為了儲存寫事件。讀緩沖中的事件主要是為了優(yōu)化驅(qū)逐策略的命中率,因此讀緩沖中的事件完整程度允許一定程度的有損。但是寫緩沖并不允許數(shù)據(jù)的丟失,因此其必須實現(xiàn)為一個安全的隊列。Caffeine 寫是把數(shù)據(jù)放入MpscGrowableArrayQueue 阻塞隊列中,它參考了JCTools里的MpscGrowableArrayQueue ,是針對 MPSC- 多生產(chǎn)者單消費者(Multi-Producer
本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
關(guān)閉
關(guān)閉