經過一番排查,確認伺服器的效能瓶頸是在資料庫。給伺服器加上Redis,讓其作為資料庫的快取。
這樣,在客戶端請求資料時,如果能在快取中命中資料,那就查詢快取,不用再去查詢資料庫,從而減輕資料庫的壓力,提高伺服器的效能。
一、快取模型
二、資料庫和快取的資料不一致問題
更新資料時,資料庫的資料時客戶端第二次更新操作的資料,而快取確還是第一次更新操作的資料,也就是出現了資料庫和快取不一致的問題。
造成快取和資料庫的資料不一致的現象,是因為併發問題!
先更新資料庫,還是先更新快取?(併發雙寫,不使用該方案)
併發雙寫:在併發雙寫中,當資料更新時,會同時更新快取和資料庫,以確保它們保持一致。
儘管併發雙寫可以減少資料不一致性的可能性,但它並不能完全消除這種風險。
先更新資料庫,再更新快取:
先更新快取,再更新資料庫:
所以,無論是「先更新資料庫,再更新快取」,還是「先更新快取,再更新資料庫」,這兩個方案都存在併發問題,當兩個請求併發更新同一條資料的時候,可能會出現快取和資料庫中的資料不一致的現象。
先更新資料庫,還是先刪除快取?
不更新快取,而是刪除快取中的資料。然後,到讀取資料時,發現快取中沒了資料之後,再從資料庫中讀取資料,更新到快取中。(即用刪除快取代替更新快取)
寫策略步驟:
- 更新資料庫中的資料
- 刪除快取中的資料
讀策略步驟:
- 如果讀取的資料命中了快取,則直接返回資料
- 如果讀取的資料沒有命中快取,則從資料庫中讀取資料,然後將資料寫入到快取,並返回給使用者
那問題又來了:在[寫策略]的時候,到底選擇哪種順序呢?
- 先刪除Redis快取中資料,再更新MySQL中的資料
- 先更新MySQL中的資料,再刪除Redis快取中的資料
先刪除快取,再更新資料庫:
可以看到,先刪除快取,再更新資料庫,在「讀 + 寫」併發的時候,還是會出現快取和資料庫的資料不一致的問題。
解決方案:雙刪
雙刪的問題:
如果重建快取的時間比較長,執行緒1刪除Redis快取後,執行緒2才重建完快取,這時會出現資料不一致問題。
延遲雙刪:
第二次刪除操作具體延遲多久呢?
大於執行緒2重建快取的時間。
先更新資料庫,再刪除快取:
因為快取的寫入通常要遠遠快於資料庫的寫入,所以在實際中很難出現請求 B 已經更新了資料庫並且刪除了快取,請求 A 才更新完快取的情況。
而一旦請求 A 早於請求 B 刪除快取之前更新了快取,那麼接下來的請求就會因為快取不命中而從資料庫中重新讀取資料,所以不會出現這種不一致的情況。
所以,「先更新資料庫 + 再刪除快取」的方案,是可以保證資料一致性的。(也得承受幾百毫秒的資料不一致性)
先刪除快取,資料不一致更加嚴重點。所以,我們一般選擇使用後刪除快取。
但是後刪除快取也可能存在問題(當刪除快取失敗的時候):
所以我們給key設定一個過期時間(兜底方案)。
最好的解決方案:
三、總結