為什麼你的快取更新策略是先更新資料庫後刪除快取,講講其他的情況有什麼問題?
阿新 • • 發佈:2019-03-26
問題:怎麼保持快取與資料庫一致?
要解答這個問題,我們首先來看不一致的幾種情況。我將不一致分為三種情況
- 資料庫有資料,快取沒有資料;
- 資料庫有資料,快取也有資料,資料不相等;
- 資料庫沒有資料,快取有資料。
在討論這三種情況之前,先說明一下我使用快取的策略,也是大多數人使用的策略,叫做 Cache Aside Pattern。酷殼裡的 快取更新的套路 一文,很值得一讀,我的策略也是從他那學來的。 簡而言之,就是
- 首先嚐試從快取讀取,讀到資料則直接返回;如果讀不到,就讀資料庫,並將資料會寫到快取,並返回。
- 需要更新資料時,先更新資料庫,然後把快取裡對應的資料失效掉(刪掉)。
因為:
-
讀的邏輯大家都很容易理解,談談更新。如果不採取我提到的這種更新方法,你還能想到什麼更新方法呢?大概會是:先刪除快取,然後再更新資料庫。這麼做引發的問題是,如果A,B兩個執行緒同時要更新資料,並且A,B已經都做完了刪除快取這一步,接下來,A先更新了資料庫,C執行緒讀取資料,由於快取沒有,則查資料庫,並把A更新的資料,寫入了快取,最後B更新資料庫。那麼快取和資料庫的值就不一致了。
-
另外有人會問,如果採用你提到的方法,為什麼最後是把快取的資料刪掉,而不是把更新的資料寫到快取裡。這麼做引發的問題是,如果A,B兩個執行緒同時做資料更新,A先更新了資料庫,B後更新資料庫,則此時資料庫裡存的是B的資料。而更新快取的時候,是B先更新了快取,而A後更新了快取,則快取裡是A的資料。這樣快取和資料庫的資料也不一致。
按照我提到的這種更新快取的策略,理論上也是有不一致的風險的,酷殼的文章有提到,只不過概率很小,我們暫時可以不考慮,後面我們有其他手段來補救。 討論完使用快取的策略,我們再來看這三種不一致的情況。
- 對於第一種,在讀資料的時候,會自動把資料庫的資料寫到快取,因此不一致自動消除
- 對於第二種,資料最終變成了不相等,但他們之前在某一個時間點一定是相等的(不管你使用懶載入還是預載入的方式,在快取載入的那一刻,它一定和資料庫一致)。這種不一致,一定是由於你更新資料所引發的。前面我們講了更新資料的策略,先更新資料庫,然後刪除快取。因此,不一致的原因,一定是資料庫更新了,但是刪除快取失敗了。
- 對於第三種,情況和第二種類似,你把資料庫的資料刪了,但是刪除快取的時候失敗了。
因此,最終的結論是,需要解決的不一致,產生的原因是更新資料庫成功,但是刪除快取失敗。 我想出的解決方案大概有以下幾種:
- 對刪除快取進行重試,資料的一致性要求越高,我越是重試得快。
- 定期全量更新,簡單地說,就是我定期把快取全部清掉,然後再全量載入。
- 給所有的快取一個失效期。
第三種方案可以說是一個大殺器,任何不一致,都可以靠失效期解決,失效期越短,資料一致性越高。但是失效期越短,查資料庫就會越頻繁。因此失效期應該