1. 雙寫模式
做法順序:先寫數據庫,再寫緩存
併發的問題:
由於卡頓等原因,導致寫緩存2在最前,寫緩存1在後面就出現了不一致
髒數據問題: 這是暫時性的髒數據問題,但是在數據穩定,緩存過期以後,又能得到最新的正確數據
讀到的最新數據有延遲:最終一致性
2. 失效模式
做法順序:先寫數據庫,在刪除緩存
併發問題:
由於網絡或者i/o問題導致第三個請求拿到了數據庫中數據:db-1,此時第二個請求數據庫寫更新db-1->db-2已完成,立刻刪除緩存,第三個請求又將緩存刷新成第一個請求時的數據
還是會出現髒數據問題:最終不一致性
解決方案: 無論是雙寫模式還是失效模式,都會導致緩存的不一致問題(多個實例同時更新)。
- 緩存數據加上過期時間,每隔一段時間觸發讀的主動更新
- 如果是菜單,商品介紹等基礎數據,也可以去使用canal訂閱binlog的方式(比較優秀)。
- 通過加鎖保證併發讀寫,寫寫的時候按順序排好隊。讀讀無所謂。所以適合使用讀寫鎖。
高併發緩存問題高併發緩存問題
1、緩存集中失效
將原來的固定過期時間,調整爲過期時間=基礎時間+隨機時間,讓緩存慢慢過期,避免瞬間全部過期對DB產生過大壓力。
2、緩存穿透
方案一:查存DB 時,如果數據不存在,預熱一個特殊空值到緩存中。這樣,後續查詢都會命中緩存,但是要對特殊值,解析處理。
方案二:構造一個BloomFilter過濾器,初始化全量數據,當接到請求時,在BloomFilter中判斷這個key是否存在,如果不存在,直接返回即可,無需再查詢緩存和DB
3、緩存雪崩
4、緩存熱點
將集中化流量打散,避免一個緩存節點過載。由於只有一個key,我們可以在key的後面拼上有序編號,比如key#01、key#02。。。key#10多個副本,這些加工後的key位於多個緩存節點上。 每次請求時,客戶端隨機訪問一個即可
5、緩存大Key
6、緩存數據一致性
緩存是用來加速的,一般不會持久化儲存。所以,一份數據通常會存在DB和緩存中,由此會帶來一個問題,如何保證這兩者的數據一致性。另外,緩存熱點問題會引入多個副本備份,也可能會發生不一致現象。
方案一:當緩存更新失敗後,進行重試,如果重試失敗,將失敗的key寫入MQ消息隊列,通過異步任務補償緩存,保證數據的一致性。
方案二:設置一個較短的過期時間,通過自修復的方式,在緩存過期後,緩存重新加載最新的數據
7、數據併發競爭預熱
互聯網系統典型的特點就是流量大,一旦緩存中的數據過期、或因某些原因被刪除等,導致緩存中的數據爲空,大量的併發線程請求(查詢同一個key)就會一起併發查詢數據庫,數據庫的壓力陡然增加。
如果請求量非常大,全部壓在數據庫,可能把數據庫壓垮,進而導致整個系統的服務不可用。
方案一:引入一把全局鎖,當緩存未命中時,先嚐試獲取全局鎖,如果拿到鎖纔有資格去查詢DB,並將數據預熱到緩存中。雖然client端發起的請求非常多,但是由於拿不到鎖只能處於等待狀態,當緩存中的數據預熱成功後再從緩存中獲取
方案二:緩存數據創建多個備份,當一個過期失效後,可以訪問其他備份。