缓存击穿/穿透/雪崩
緩存擊穿/穿透/雪崩
Intro
使用緩存需要了解幾個(gè)緩存問題,緩存擊穿、緩存穿透以及緩存雪崩,需要了解它們產(chǎn)生的原因以及怎么避免,尤其是當(dāng)你打算設(shè)計(jì)自己的緩存框架的時(shí)候需要考慮如何處理這些問題。
緩存擊穿
一般的緩存系統(tǒng),都是按照 key 去緩存查詢,如果不存在對(duì)應(yīng)的 value ,就應(yīng)該去后端系統(tǒng)查找(比如數(shù)據(jù)庫)。如果 key 對(duì)應(yīng)的 value 是一定不存在的,并且對(duì)該 key 并發(fā)請(qǐng)求量很大,就會(huì)對(duì)后端系統(tǒng)就會(huì)造成很大的壓力。
在高并發(fā)下,多線程同時(shí)查詢同一個(gè)資源,如果緩存中沒有這個(gè)資源,那么這些線程都會(huì)去后端服務(wù)或數(shù)據(jù)庫查找,對(duì)數(shù)據(jù)庫造成極大壓力,緩存也就失去存在的意義。
緩存擊穿解決方案
導(dǎo)致緩存擊穿的問題在于高并發(fā)多線程情景下,許多請(qǐng)求一下子都到后端服務(wù)和數(shù)據(jù)庫,導(dǎo)致后端服務(wù)與數(shù)據(jù)庫的壓力驟增。
處理這個(gè)問題,在多線程請(qǐng)求同一個(gè) key 的時(shí)候,進(jìn)行排隊(duì),這樣第一次請(qǐng)求后端服務(wù)和數(shù)據(jù)庫之后更新緩存的值,下一個(gè)請(qǐng)求從緩存中取數(shù)據(jù)的時(shí)候就會(huì)拿到緩存數(shù)據(jù),不會(huì)再請(qǐng)求后端服務(wù)和數(shù)據(jù)庫。
緩存穿透
緩存穿透是指用戶查詢數(shù)據(jù),在數(shù)據(jù)庫沒有,自然在緩存中也不會(huì)有。這樣就導(dǎo)致用戶查詢的時(shí)候,在緩存中找不到,每次都要去數(shù)據(jù)庫中查詢,從而失去了緩存的意義而且相比直接查詢數(shù)據(jù)庫還增加了每次都去查緩存。
緩存穿透解決方案
導(dǎo)致問題出現(xiàn)的原因在于請(qǐng)求一個(gè)不存在的數(shù)據(jù)從而使得緩存始終不存在進(jìn)而導(dǎo)致后端系統(tǒng)(主要是數(shù)據(jù)庫)要承受很大的壓力,所以想要解決這個(gè)問題,就勢(shì)必就在緩存這里攔截住大量的請(qǐng)求,使得最終走到后端系統(tǒng),查詢數(shù)據(jù)庫的請(qǐng)求盡可能的少。
一般處理這個(gè)問題,緩存不存在的時(shí)候會(huì)在緩存中設(shè)置一個(gè)時(shí)間較短的內(nèi)容為空的緩存,從而減少實(shí)際請(qǐng)求到后端和進(jìn)行數(shù)據(jù)庫查詢的次數(shù)。
復(fù)雜一些的解決方案有 布隆過濾器,基本原理是設(shè)置一個(gè) list,查詢緩存的時(shí)候從 list 里進(jìn)行判斷,這里不做多介紹。
布隆過濾器(Bloom Filter)是1970年由布隆提出的。它實(shí)際上是一個(gè)很長的二進(jìn)制向量和一系列隨機(jī)映射函數(shù)。布隆過濾器可以用于檢索一個(gè)元素是否在一個(gè)集合中。它的優(yōu)點(diǎn)是空間效率和查詢時(shí)間都遠(yuǎn)遠(yuǎn)超過一般的算法,缺點(diǎn)是有一定的誤識(shí)別率和刪除困難 如果想要判斷一個(gè)元素是不是在一個(gè)集合里,一般想到的是將所有元素保存起來,然后通過比較確定。鏈表,樹等等數(shù)據(jù)結(jié)構(gòu)都是這種思路. 但是隨著集合中元素的增加,我們需要的存儲(chǔ)空間越來越大,檢索速度也越來越慢(O(n),O(logn))。不過世界上還有一種叫作散列表(又叫哈希表,Hash table)的數(shù)據(jù)結(jié)構(gòu)。它可以通過一個(gè)Hash函數(shù)將一個(gè)元素映射成一個(gè)位陣列(Bit array)中的一個(gè)點(diǎn)。這樣一來,我們只要看看這個(gè)點(diǎn)是不是1就可以知道集合中有沒有它了。這就是布隆過濾器的基本思想。
緩存雪崩
當(dāng)緩存服務(wù)器重啟或者大量緩存集中在某一個(gè)時(shí)間失效,這樣在失效的時(shí)候,也會(huì)給后端系統(tǒng)和數(shù)據(jù)庫帶來很大壓力.
緩存雪崩解決方案
導(dǎo)致出現(xiàn)緩存雪崩的根本原因在于緩存大量失效,從而導(dǎo)致大量請(qǐng)求沒有命中緩存,大量請(qǐng)求走到后端服務(wù)和數(shù)據(jù)庫,造成壓力。
如果系統(tǒng)啟動(dòng)就依賴很多緩存,那可以通過其它服務(wù)進(jìn)行緩存預(yù)熱,提前把需要的數(shù)據(jù)放到緩存中,避免系統(tǒng)啟動(dòng)大量請(qǐng)求直接請(qǐng)求到后端服務(wù)和數(shù)據(jù)庫。
既然是由于同一時(shí)間緩存大量失效,我們也可以著手從緩存的失效時(shí)間上,做一些優(yōu)化,讓緩存不要在同一時(shí)間點(diǎn)失效。具體的實(shí)施辦法,你可以在設(shè)置失效時(shí)間的時(shí)候隨機(jī)加幾秒過期時(shí)間,避免同一時(shí)間點(diǎn)緩存大量失效。
Reference
https://github.com/WeihanLi/WeihanLi.Redis/issues/2
https://www.cnblogs.com/jinjiangongzuoshi/archive/2016/03/03/5240280.html
https://blog.csdn.net/zeb_perfect/article/details/54135506
https://blog.csdn.net/bushanyantanzhe/article/details/79459095
https://baike.baidu.com/item/%E5%B8%83%E9%9A%86%E8%BF%87%E6%BB%A4%E5%99%A8/5384697?fr=aladdin
Contact
Contact me: weihanli@outlook.com
總結(jié)
以上是生活随笔為你收集整理的缓存击穿/穿透/雪崩的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Orleans 3.0 为我们带来了什么
- 下一篇: 扎心了,程序员2017到2019经历了什