Redis實現快取與分散式鎖
阿新 • • 發佈:2020-10-22
# 快取與分散式鎖
哪些資料適合放入快取
- 即時性、資料一致性要求不高的
- 訪問量大且更新頻率不高的資料
**選擇redis做為快取中介軟體**
```xml
```
### 問題記錄與分析
#### 產生堆外記憶體溢位:OutOfDirectMemoryError
1. springboot2.0 以後預設使用lettuce作為操作redis的客戶端,它使用netty進行網路通訊。
2. lettuce的bug導致netty堆外記憶體溢位
解決方案: 切換到jedis(或者升級lettuce)
```xml
```
#### 高併發下快取失效問題-快取穿透
**快取穿透:**
指查詢一個一定不存在的資料,由於快取是不命中,將要去查詢資料庫,但是資料庫也沒有該記錄,我們將這次查詢的null寫入快取,這將導致這個不存在的資料每次請求都要到儲存層去查詢,失去了快取的意義
**風險:**
利用不存在資料進行攻擊,資料庫瞬時壓力增大,最終導致崩潰
**解決:**
null結果快取,並加入短暫過期時間
#### 高併發下快取失效問題-快取雪崩
**快取雪崩:**
快取雪崩是指我們設定快取時key採用了相同的過期時間,導致快取在某一時刻同時失效,請求全部轉發到DB,DB瞬時壓力過重雪崩。
**解決:**
原有的失效時間基礎上增加一個隨機值,比如1-5min隨機,這樣每一個快取的過期時間的重複率就會降低,就很難引發集體失效的事件。
#### 高併發下快取失效問題-快取擊穿
**快取擊穿:**
- 對於一些設定了過期時間的key,如果這些key可能會在某些時間點被超高併發地訪問,是一種非常”熱點“的資料。
- 如果這個key在大量請求同時進來前正好失效,那麼所有key的資料查詢都落到db,我們稱之為快取擊穿。
**解決:**
加鎖,大量併發只讓一個請求去查,其他請求等待,查到以後釋放鎖,其他請求獲取到鎖,先查快取,就會有資料,不用去db。
**加鎖實踐:**
springboot所有的元件在容器中都是單例的,可以使用synchronized(this),JUC(Lock)等解決單體應用中的問題,但是分散式系統中,要想鎖住所有資料,就必須使用分散式鎖
通過分析 分散式鎖必須保證加鎖(佔位+過期時間)和刪除鎖(判斷+刪除)的原子性。
加鎖可以使用redis setnx ex命令來操作,但是刪除鎖的時候 ,要先判斷再刪除,想把這兩步操作做成原則性的,需要採用redis+lusj指令碼的方式來操作。
```java
pu