Redis中幾個“看似”高大上的概念,經常有人提到,某些好事者喜歡死扣概念,實戰沒多少,嘴巴裡冒出來的全是高大上的名詞,個人一向鄙視概念黨,呵呵,尼瑪! 其實這幾個概念:緩存穿透/緩存擊穿/緩存雪崩,有一個共通的相似之處,就是高併發下,某些原因導致緩存層失去了保護,導致後端的持久化層(資料庫)承擔較 ...
Redis中幾個“看似”高大上的概念,經常有人提到,某些好事者喜歡死扣概念,實戰沒多少,嘴巴裡冒出來的全是高大上的名詞,個人一向鄙視概念黨,呵呵!
其實這幾個概念:緩存穿透/緩存擊穿/緩存雪崩,有一個共通的相似之處,就是高併發下,某些原因導致緩存層失去了保護,導致後端的持久化層(資料庫)承擔較大壓力的情形。
需要註意的是,這些問題發生的前提,需要有足夠大的併發性,如果本身併發性不高,那些即便出現了這些個問題,也不會造成非常大的影響。
甚至極端地講,只要代碼的健壯性足夠,即便是緩存層全部宕機,也不會導致整個應用程式的崩潰,只不過是所有的請求都指向後端的持久化資料庫層罷了。
試問,排出一些低級的問題包括方案,君見過多少請求壓垮資料庫的場景,或者數據緩存流行之前應用程式就應付不了高併發?
使用緩存,更多的進一步改善性能或者併發,而不是因為資料庫被壓垮了才使用緩存。
緩存穿透
緩存穿透本質上是查詢一個緩存和資料庫中都不存在的key值,Redis的緩存層無法命中,導致請求再次指向執行資料庫層的情況。
由於是查詢到值不存在(當然也不存在與Redis緩存中),導致請求總是“穿透”Redis發往資料庫層,因此緩存層失去了“保護”關係資料庫層的意義。
解決方案:
布隆過濾器是一個比較好的選擇,參考:https://www.cnblogs.com/wy123/p/11571215.html
緩存擊穿
緩存穿透本質上是高併發地請求一個緩存中不存在,但是資料庫中可能存在的key值,因此請求指向資料庫,導致資料庫端承擔大量的請求壓力的情況,本質上跟緩存穿透一樣。
主要側重的是併發&&“熱點”Key不存在與緩存中,導致請求指向資料庫層。
解決方案:
這種場景可以從代碼邏輯層面優化,從緩存中查詢不到數據,再次將請求轉向資料庫中的時候,鎖定該key,獲取到該key之後,將該key寫入緩存
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,應用程式端限流,或者通過隊列的方式等削峰的方式來保護後端資料庫