Redis中幾個「看似」高大上的概念,常常有人提到,某些好事者喜歡死扣概念,實戰沒多少,嘴巴里冒出來的全是高大上的名詞,我的一貫鄙視概念黨,呵呵!html
其實這幾個概念:緩存穿透/緩存擊穿/緩存雪崩,有一個共通的類似之處,就是高併發下,某些緣由致使緩存層失去了保護,致使後端的持久化層(數據庫)承擔較大壓力的情形。
須要注意的是,這些問題發生的前提,須要有足夠大的併發性,若是自己併發性不高,那些即使出現了這些個問題,也不會形成很是大的影響。
甚至極端地講,只要代碼的健壯性足夠,即使是緩存層所有宕機,也不會致使整個應用程序的崩潰,只不過是全部的請求都指向後端的持久化數據庫層罷了。
試問,排出一些低級的問題包括方案,君見過多少請求壓垮數據庫的場景,或者數據緩存流行以前應用程序就應付不了高併發?
使用緩存,更多的進一步改善性能或者併發,而不是由於數據庫被壓垮了才使用緩存。mysql
緩存穿透
緩存穿透本質上是查詢一個緩存和數據庫中都不存在的key值,Redis的緩存層沒法命中,致使請求再次指向執行數據庫層的狀況。
因爲是查詢到值不存在(固然也不存在與Redis緩存中),致使請求老是「穿透」Redis發往數據庫層,所以緩存層失去了「保護」關係數據庫層的意義。
解決方案:
布隆過濾器是一個比較好的選擇,參考:http://www.javashuo.com/article/p-qgjuyrdm-gs.htmlredis
緩存擊穿
強調對於某些熱點key,緩存穿透本質上是高併發地請求一個緩存中不存在,可是數據庫中存在的key值,致使併發請求指向數據庫,致使數據庫端承擔大量的請求壓力的狀況,本質上跟緩存穿透同樣。
主要側重的是併發&&「熱點」Key不存在與緩存中,致使請求指向數據庫層。
解決方案:
這種場景能夠從代碼邏輯層面優化,從緩存中查詢不到數據,再次將請求轉向數據庫中的時候,鎖定該key,獲取到該key以後,將該key寫入緩存,僞代碼以下sql
value = get_value_from_redis(key1) if not value: if exclusiveness_lock(key1):#成功排他性鎖定目標,請求指向數據庫 value = get_value_from_mysql(key1) if value: write_key_to_redis(key1,value) else:#沒法獲取排他性鎖,間隔0.1s以後再次查詢緩存 time.sleep(0.1) # 再次從緩存中查詢 get_value_from_redis(key1)
緩存雪崩
某些緣由,好比:
1,Redis實例(主從,集羣,哨兵等等)故障。
2,Redis中的key因爲過時時間已到,自動過時。
3,因爲Redis內存策略致使(maxmemory,maxmemory-policy配置)某些key失效(過時,被清理出緩存等)。
若是此時出現高併發的請求出現,這些請求會所有指向數據庫層,緩存層失去了對數據庫層的保護,致使數據庫承擔絕大壓力的狀況。
解決方案:
1,Redis層的高可用,保證緩存層能夠有效地保護數據庫層
2,從Redis配置(內存管理策略maxmemory,maxmemory-policy)以及結合業務,避免某些潛在的熱點key值過時
3,應用程序端限流,或者經過隊列的方式等削峯的方式來保護後端數據庫數據庫