日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Guava Cache 过期回源

發布時間:2023/12/20 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Guava Cache 过期回源 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

緩存的更新有兩種方法:

  • 被動更新:先從緩存獲取,沒有則回源獲取,再更新緩存;
  • 主動更新:發現數據改變后直接更新緩存(在分布式場景下,不容易實現)

在高并發環境,被動回源是需要注意的。 問題:高并發場景下,大量請求在同一時間回源,大量的請求同一時間穿透到后端,容易引起后端服務崩潰(也容易引起并發問題)。

guava cache解決辦法: guava cache保證單線程回源,對于同一個key,只讓一個請求回源load,其他線程阻塞等待結果。同時,在Guava里可以通過配置expireAfterAccess/expireAfterWrite設定key的過期時間,key過期后就單線程回源加載并放回緩存。

這樣通過Guava Cache簡簡單單就較為安全地實現了緩存的被動更新操作。

但是如果對于同一時間大量不同的key同時過期,造成大量不同的key同時回源,這種怎么解決呢?

guava cache實現類似ConcurrentHashMap,維護segment數組,每個segment獨享一個鎖,ConcurrentHashMap是通過這種機制來實現分段鎖,ConcurrentHashMap默認分了16個segment; guava Cache默認是4個segment,故guava cache的并發級別默認是4個,也就是說默認情況下,即便是大量不同的key同時過期,最多只也有4個線程并發回源,理論上不會給后端造成過大的壓力。

guava refresh和expire刷新機制

  • expireAfterAccess: 當緩存項在指定的時間段內沒有被讀或寫就會被回收。
  • expireAfterWrite:當緩存項在指定的時間段內沒有更新就會被回收。
  • refreshAfterWrite:當緩存項上一次更新操作之后的多久會被刷新。

僅僅使用 expireAfterWrite或者expireAfterAccess就可以實現緩存定時過期,但是頻繁的過期會造成頻繁的單線程回源,然而guava cache回源的時候會獨占一個segment的鎖,對于同一個segment的其他的讀操作 處于loading狀態的則會繼續等待,value expire或者為null的key則會阻塞等待segment的鎖。

expireAfterWrite或者expireAfterAccess的實現在數據回源的時候會讓請求block住,以獲取最新的值。數據實時性保證的較好,但是阻塞住請求對于一些響應要求嚴苛的業務可能是沒辦法接受的。那有沒有解決的辦法呢?

我們且看refreshAfterWrite:

refreshAfterWrite通過定時刷新可以讓緩存項保持可用。緩存項只有在被檢索時才會真正刷新(如果CacheLoader.refresh實現為異步,那么檢索不會被刷新拖慢)。也是保證同一個segment的單線程回源,但是與expireAfterWrite不同的是:其他線程訪問loading狀態的key時,僅僅稍微等一會,沒有等到就返回舊值,整個請求就比較平滑。 與此同時,也引入了一個問題,refreshAfterWrite策略下,如果一個key長期沒有被訪問,就有可能會訪問到很久之前的舊值。例如refreshAfterWrite(5),5s刷新一次,如果1min內,這個key都沒有被訪問,那么1min之后訪問這個key,仍然有可能訪問到舊數據,盡管我們設置了5s刷新一次。(guava cache并沒單獨的線程來處理刷新的邏輯,而是通過讀操作來觸發清理工作)

對于這個問題有沒有這種的辦法呢? guava cache支持我們同時使用expireAfterWrite&refreshAfterWrite,我們既可以通過組合的策略既保證性能,又保證不要讀取到太舊的數據。 比如我們有需求:要求請求必須平滑,而且不能讀到5s之前的舊數據。

我們可以如下設置來滿足需求:

1 2 3 4 5 LoadingCache<String, String> cache = CacheBuilder.newBuilder().refreshAfterWrite(4L, TimeUnit.SECONDS).expireAfterWrite(5L, TimeUnit.SECONDS).build(loader);

expireAfterWrite(5L, TimeUnit.SECONDS)能保證不會讀到5s之前的舊數據,refreshAfterWrite(4L, TimeUnit.SECONDS)能保證大部分請求都在4s左右被刷新,小部分訪問量較少的在5s的時候通過expireAfterWrite策略重新被回源。

guava后臺異步刷新

refreshAfterWrite的刷新調用的是reload,reload的默認實現是在當前線程里面reload,也會造成一些卡頓,如果希望異步reload,需要重載這個方法。

1 2 3 4 5 6 public ListenableFuture<V> (K key, V oldValue) throws Exception {checkNotNull(key);checkNotNull(oldValue);return Futures.immediateFuture(load(key));//當前線程調用load,會造成當前線程的卡頓,如果不接受卡頓,需要重載這個方法}?

?轉載:https://www.dazhuanlan.com/2019/10/06/5d99928eb6380/

總結

以上是生活随笔為你收集整理的Guava Cache 过期回源的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。