緩存雪崩
緩存雪崩我們可以簡單的理解為:由于原有緩存失效,新緩存未到期間(例如:我們設(shè)置緩存時采用了相同的過期時間耘子,在同一時刻出現(xiàn)大面積的緩存過期),所有原本應(yīng)該訪問緩存的請求都去查詢數(shù)據(jù)庫了贾陷,而對數(shù)據(jù)庫CPU和內(nèi)存造成巨大壓力疮绷,嚴重的會造成數(shù)據(jù)庫宕機。從而形成一系列連鎖反應(yīng)盅安,造成整個系統(tǒng)崩潰唤锉。
緩存雪崩的解決方案
(1)碰到這種情況,一般并發(fā)量不是特別多的時候宽堆,使用最多的解決方案是加鎖排隊腌紧。
加鎖排隊只是為了減輕數(shù)據(jù)庫的壓力,并沒有提高系統(tǒng)吞吐量畜隶。假設(shè)在高并發(fā)下壁肋,緩存重建期間key是鎖著的,這是過來1000個請求999個都在阻塞的籽慢。同樣會導(dǎo)致用戶等待超時浸遗,這是個治標不治本的方法!
注意:加鎖排隊的解決方式分布式環(huán)境的并發(fā)問題箱亿,有可能還要解決分布式鎖的問題跛锌;線程還會被阻塞,用戶體驗很差届惋!因此髓帽,在真正的高并發(fā)場景下很少使用!
(2)給每一個緩存數(shù)據(jù)增加相應(yīng)的緩存標記脑豹,記錄緩存的是否失效郑藏,如果緩存標記失效,則更新數(shù)據(jù)緩存瘩欺。
解釋說明:
1必盖、緩存標記:記錄緩存數(shù)據(jù)是否過期拌牲,如果過期會觸發(fā)通知另外的線程在后臺去更新實際key的緩存;
2歌粥、緩存數(shù)據(jù):它的過期時間比緩存標記的時間延長1倍塌忽,例:標記緩存時間30分鐘,數(shù)據(jù)緩存設(shè)置為60分鐘失驶。 這樣土居,當緩存標記key過期后,實際緩存還能把舊數(shù)據(jù)返回給調(diào)用端突勇,直到另外的線程在后臺更新完成后装盯,才會返回新緩存。
關(guān)于緩存崩潰的解決方法甲馋,這里提出了三種方案:使用鎖或隊列埂奈、設(shè)置過期標志更新緩存、為key設(shè)置不同的緩存失效時間定躏,還有一各被稱為“二級緩存”的解決方法账磺。
緩存穿透
緩存穿透是指用戶查詢數(shù)據(jù),在數(shù)據(jù)庫沒有痊远,自然在緩存中也不會有垮抗。這樣就導(dǎo)致用戶查詢的時候,在緩存中找不到碧聪,每次都要去數(shù)據(jù)庫再查詢一遍冒版,然后返回空(相當于進行了兩次無用的查詢)。這樣請求就繞過緩存直接查數(shù)據(jù)庫逞姿,這也是經(jīng)常提的緩存命中率問題辞嗡。
緩存穿透解決方案
(1)采用布隆過濾器,將所有可能存在的數(shù)據(jù)哈希到一個足夠大的bitmap中滞造,一個一定不存在的數(shù)據(jù)會被這個bitmap攔截掉续室,從而避免了對底層存儲系統(tǒng)的查詢壓力。
(2)如果一個查詢返回的數(shù)據(jù)為空(不管是數(shù)據(jù)不存在谒养,還是系統(tǒng)故障)挺狰,我們?nèi)匀话堰@個空結(jié)果進行緩存,但它的過期時間會很短买窟,最長不超過五分鐘丰泊。通過這個直接設(shè)置的默認值存放到緩存,這樣第二次到緩存中獲取就有值了始绍,而不會繼續(xù)訪問數(shù)據(jù)庫趁耗,這種辦法最簡單粗暴!
把空結(jié)果也給緩存起來疆虚,這樣下次同樣的請求就可以直接返回空了,即可以避免當查詢的值為空時引起的緩存穿透。同時也可以單獨設(shè)置個緩存區(qū)域存儲空值径簿,對要查詢的key進行預(yù)先校驗罢屈,然后再放行給后面的正常緩存處理邏輯。
緩存擊穿
緩存擊穿是指一個Key非常熱點篇亭,在不停的扛著大并發(fā)缠捌,大并發(fā)集中對這一個點進行訪問,當這個Key在失效的瞬間译蒂,持續(xù)的大并發(fā)就穿破緩存曼月,直接請求數(shù)據(jù)庫,就像在一個完好無損的桶上鑿開了一個洞柔昼。
解決方案
設(shè)置熱點數(shù)據(jù)永遠不過期哑芹。或者加上互斥鎖就能搞定了捕透。
緩存預(yù)熱
緩存預(yù)熱就是系統(tǒng)上線后聪姿,提前將相關(guān)的緩存數(shù)據(jù)直接加載到緩存系統(tǒng)。避免在用戶請求的時候乙嘀,先查詢數(shù)據(jù)庫末购,然后再將數(shù)據(jù)緩存的問題!用戶直接查詢事先被預(yù)熱的緩存數(shù)據(jù)虎谢!
緩存預(yù)熱解決方案
(1)直接寫個緩存刷新頁面盟榴,上線時手工操作下;
(2)數(shù)據(jù)量不大婴噩,可以在項目啟動的時候自動進行加載擎场;
(3)定時刷新緩存;
熱點數(shù)據(jù)和冷數(shù)據(jù)
施行數(shù)據(jù)淘汰策略讳推。
緩存更新
除了緩存服務(wù)器自帶的緩存失效策略之外(Redis默認的有6中策略可供選擇)顶籽,我們還可以根據(jù)具體的業(yè)務(wù)需求進行自定義的緩存淘汰,常見的策略有兩種:
(1)定時去清理過期的緩存银觅;
(2)當有用戶請求過來時礼饱,再判斷這個請求所用到的緩存是否過期,過期的話就去底層系統(tǒng)得到新數(shù)據(jù)并更新緩存究驴。
兩者各有優(yōu)劣镊绪,第一種的缺點是維護大量緩存的key是比較麻煩的,第二種的缺點就是每次用戶請求過來都要判斷緩存失效洒忧,邏輯相對比較復(fù)雜蝴韭!具體用哪種方案,大家可以根據(jù)自己的應(yīng)用場景來權(quán)衡熙侍。
緩存降級
當訪問量劇增榄鉴、服務(wù)出現(xiàn)問題(如響應(yīng)時間慢或不響應(yīng))或非核心服務(wù)影響到核心流程的性能時履磨,仍然需要保證服務(wù)還是可用的,即使是有損服務(wù)庆尘。系統(tǒng)可以根據(jù)一些關(guān)鍵數(shù)據(jù)進行自動降級剃诅,也可以配置開關(guān)實現(xiàn)人工降級。
降級的最終目的是保證核心服務(wù)可用驶忌,即使是有損的矛辕。而且有些服務(wù)是無法降級的(如加入購物車、結(jié)算)付魔。
在進行降級之前要對系統(tǒng)進行梳理聊品,看看系統(tǒng)是不是可以丟卒保帥;從而梳理出哪些必須誓死保護几苍,哪些可降級翻屈;比如可以參考日志級別設(shè)置預(yù)案:
(1)一般:比如有些服務(wù)偶爾因為網(wǎng)絡(luò)抖動或者服務(wù)正在上線而超時,可以自動降級擦剑;
(2)警告:有些服務(wù)在一段時間內(nèi)成功率有波動(如在95~100%之間)妖胀,可以自動降級或人工降級,并發(fā)送告警惠勒;
(3)錯誤:比如可用率低于90%赚抡,或者數(shù)據(jù)庫連接池被打爆了,或者訪問量突然猛增到系統(tǒng)能承受的最大閥值纠屋,此時可以根據(jù)情況自動降級或者人工降級涂臣;
(4)嚴重錯誤:比如因為特殊原因數(shù)據(jù)錯誤了,此時需要緊急人工降級售担。
緩存熱點key
針對于熱點Key的解決方案網(wǎng)上的查找出來無非就是兩種:
- 服務(wù)端緩存:即將熱點數(shù)據(jù)緩存至服務(wù)端的內(nèi)存中赁遗。
- 備份熱點Key:即將熱點Key+隨機數(shù),隨機分配至Redis其他節(jié)點中族铆。這樣訪問熱點key的時候就不會全部命中到一臺機器上了岩四。