緩存擊穿redis
緩存擊穿,是指一個key很是熱點,在不停的扛着大併發,大併發集中對這一個點進行訪問,當這個key在失效的瞬間,持續的大併發就穿破緩存,直接請求數據庫,就像在一個屏障上鑿開了一個洞。數據庫
好比在作電商項目的時候,把這貨就成爲「爆款」。緩存
其實,大多數狀況下這種爆款很難對數據庫服務器形成壓垮性的壓力。達到這個級別的公司沒有幾家的。因此,本着務實主義,對主打商品都是早早的作好了準備,讓緩存永不過時。即使某些商品本身發酵成了爆款,也是直接設爲永不過時就行了。服務器
其餘方式:併發
1. 使用互斥鎖(mutex key): 這種解決方案思路比較簡單,就是隻讓一個線程構建緩存,其餘線程等待構建緩存的線程執行完,從新從緩存獲取數據就能夠了。異步
若是是分佈式鎖,就是用分佈式鎖來處理就行了。分佈式
2. "提早"使用互斥鎖(mutex key):
在value內部設置1個超時值(timeout1), timeout1比實際的memcache timeout(timeout2)小。當從cache讀取到timeout1發現它已通過期時候,立刻延長timeout1並從新設置到cache。而後再從數據庫加載數據並設置到cache中。
性能
3. "永遠不過時":
這裏的「永遠不過時」包含兩層意思:
(1) 從redis上看,確實沒有設置過時時間,這就保證了,不會出現熱點key過時問題,也就是「物理」不過時。
(2) 從功能上看,若是不過時,那不就成靜態的了嗎?因此咱們把過時時間存在key對應的value裏,若是發現要過時了,經過一個後臺的異步線程進行緩存的構建,也就是「邏輯」過時
spa
從實戰看,這種方法對於性能很是友好,惟一不足的就是構建緩存時候,其他線程(非構建緩存的線程)可能訪問的是老數據,可是對於通常的互聯網功能來講這個仍是能夠忍受。線程
4. 資源保護:
能夠作資源的隔離保護主線程池,若是把這個應用到緩存的構建也何嘗不可。
總結
1. 熱點key + 過時時間 + 複雜的構建緩存過程 => mutex key問題
2. 構建緩存一個線程作就能夠了。
3. 四種解決方案:沒有最佳只有最合適。