Redis緩存之解決高并發(fā)問題

Resisson-GitHub Wiki

  1. 為什么要使用Redis?
  2. 那些數(shù)據(jù)適合放入緩存?

一、緩存失效問題

1. 緩存穿透

指查詢一個一定不存在的數(shù)據(jù),由于緩存是不命中,將去查詢數(shù)據(jù)庫,但是
數(shù)據(jù)庫也無此記錄,我們沒有將這次查詢的null寫入緩存,這將導(dǎo)致這個不
存在的數(shù)據(jù)每次請求都要到存儲層去查詢,失去了緩存的意義

風(fēng)險:
利用不存在的數(shù)據(jù)進(jìn)行攻擊,數(shù)據(jù)庫瞬時壓力增大,最終導(dǎo)致崩潰

解決:
null結(jié)果緩存,并加入短暫過期時間

2. 緩存雪蹦

緩存雪崩是指在我們設(shè)置緩存時key采用了相同的過期時間,
導(dǎo)致緩存在某一時刻同時失效,請求全部轉(zhuǎn)發(fā)到DB,DB瞬時
壓力過重雪崩。

解決:
原有的失效時間基礎(chǔ)上增加一個隨機(jī)值,比如1-5分鐘隨機(jī),這
樣每一個緩存的過期時間的重復(fù)率就會降低,就很難引發(fā)集體
失效的事件。

3. 緩存擊穿

  • 對于一些設(shè)置了過期時間的key,如果這些key可能會在某些
    時間點(diǎn)被超高并發(fā)地訪問,是一種非?!盁狳c(diǎn)”的數(shù)據(jù)。

  • 如果這個key在大量請求同時進(jìn)來前正好失效,那么所有對
    這個key的數(shù)據(jù)查詢都落到db,我們稱為緩存擊穿。

解決:
加鎖
大量并發(fā)只讓一個去查,其他人等待,查到以后釋放鎖,其他
人獲取到鎖,先查緩存,就會有數(shù)據(jù),不用去db

二、分布式加鎖

本地鎖,只能鎖住當(dāng)前進(jìn)程,所以我們需要分布式鎖

屏幕快照 2020-06-28 下午11.02.40.png
  • 分布式鎖基本原理

我們可以同時去一個地方“占坑”,如果占到,就執(zhí)行邏輯。否則就必須等待,直到釋放鎖。
“占坑”可以去redis,可以去數(shù)據(jù)庫,可以去任何大家都能訪問的地方。
等待可以自旋的方式。

屏幕快照 2020-06-28 下午11.07.44.png
1. 分布式鎖演進(jìn)-階段一

問題:
setnx占好了位,業(yè)務(wù)代碼異?;蛘叱绦蛟陧撁孢^程
中宕機(jī)。沒有執(zhí)行刪除鎖邏輯,這就造成了死鎖

解決:
設(shè)置鎖的自動過期,即使沒有刪除,會自動刪除

2. 分布式鎖演進(jìn)-階段二

問題:
setnx設(shè)置好,正要去設(shè)置過期時間,宕機(jī)。又死鎖了。

解決:
設(shè)置過期時間和占位必須是原子的。redis支持使用setnx ex
命令

3. 分布式鎖演進(jìn)-階段三

問題:
刪除鎖直接刪除???
如果由于業(yè)務(wù)時間很長,鎖自己過期了,我們
直接刪除,有可能把別人正在持有的鎖刪除了。

解決:
占鎖的時候,值指定為uuid,每個人匹配是自己
的鎖才刪除。

4. 分布式鎖演進(jìn)-階段四

問題:
如果正好判斷是當(dāng)前值,正要刪除鎖的時候,鎖已經(jīng)過期,
別人已經(jīng)設(shè)置到了新的值。那么我們刪除的是別人的鎖

解決:
刪除鎖必須保證原子性。使用redis+Lua腳本完成

5. 分布式鎖演進(jìn)-階段五-最終形態(tài)
屏幕快照 2020-06-28 下午11.30.09.png
保證加鎖【占位+過期時間】和刪除鎖【判斷+刪除】的原子性。
更難的事情,鎖的自動續(xù)期

Lua腳本:
  [圖片上傳中...(屏幕快照 2020-06-28 下午11.27.40.png-299051-1593358130785-0)]
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return
redis.call('del', KEYS[1]) else return 0 end";

三、緩存數(shù)據(jù)一致性

緩存里面的數(shù)據(jù)如何和數(shù)據(jù)庫保存一致性?

  • 雙寫模式
  • 失效模式

采用方案: 失效模式

  • 緩存的所有數(shù)據(jù)都有過期時間,數(shù)據(jù)過期下一次查詢觸發(fā)主動更新
  • 讀寫數(shù)據(jù)的時候,加分布式讀寫鎖。(如經(jīng)常寫,經(jīng)常讀會對系統(tǒng)造成影響。如偶爾寫,經(jīng)常讀,無影響。因?yàn)樽x寫鎖最大的特定是:讀相當(dāng)于無鎖狀態(tài),只有在寫鎖的情況下,讀鎖才需要等待。)
1. 雙寫模式
屏幕快照 2020-06-29 下午3.41.03.png
2. 失效模式
屏幕快照 2020-06-29 下午3.39.56.png
3. 解決方案

無論是雙寫模式還是失效模式,都會導(dǎo)致緩存的不一致問題。即多個實(shí)例同時更新會出事。怎么辦?

? 1. 如果是用戶緯度數(shù)據(jù)(訂單數(shù)據(jù)、用戶數(shù)據(jù)),這種并發(fā)幾率非常小,不用考慮這個問題,緩存數(shù)據(jù)加
上過期時間,每隔一段時間觸發(fā)讀的主動更新即可
? 2. 如果是菜單,商品介紹等基礎(chǔ)數(shù)據(jù),也可以去使用canal訂閱binlog的方式。
? 3. 緩存數(shù)據(jù)+過期時間也足夠解決大部分業(yè)務(wù)對于緩存的要求。
? 4. 通過加鎖保證并發(fā)讀寫,寫寫的時候按順序排好隊(duì)。讀讀無所謂。所以適合使用讀寫鎖。(業(yè)務(wù)不關(guān)心
臟數(shù)據(jù),允許臨時臟數(shù)據(jù)可忽略);

總結(jié):

  1. 我們能放入緩存的數(shù)據(jù)本就不應(yīng)該是實(shí)時性、一致性要求超高的。所以緩存數(shù)據(jù)的時候加上過期時間,保證每天拿到當(dāng)前最新數(shù)據(jù)即可。
  2. 我們不應(yīng)該過度設(shè)計(jì),增加系統(tǒng)的復(fù)雜性
  3. 遇到實(shí)時性、一致性要求高的數(shù)據(jù),就應(yīng)該查數(shù)據(jù)庫,即使慢點(diǎn)。
4. 緩存一致性解決-Canal

Canal是阿里開源的中間件

屏幕快照 2020-06-29 下午3.50.42.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容