先舉兩個例子,都是我做過的項目,應用場景都非常簡單:
曾經做過的一個保費試算的項目,業務場景是根據用戶基本信息+費率做計算,得到一個保費值,如果不了解這個業務場景的話,可以看做【用戶輸入】+【數據庫數據】+【一定的計算】=【結果】;這些數據復雜而且多,使用頻繁,但是每個產品的費率數據,
幾乎是不會改變的(新增修改刪除都不會有):這些數據被我們放在Redis中,而且設置成永不失效;因為數據不會修改,那么數據庫和緩存中的數據肯定是一樣的。 現在做的項目中的一個功能,簡單描述業務場景:系統從N個業務系統中抽取數據,并做加工整合,加工完成后更新到數據庫中;這個場景也比較有特點,
數據時效性要求很低(數據加工到數據庫已經晚了一天), 數據變化的時間固定且唯一(批處理每天固定時間進行,只有一個批處理線程在跑);于是我們采用了一個比較保守的策略,就是設置數據在Redis中的過期時間;等數據過期后,當查詢的時候發現數據不在緩存中,再從數據庫中查詢出來后放入緩存。
現在想一想Redis中數據的更新策略有哪些(或者說緩存更新策略)?
給緩存設置過期時間,是我認為比較好的方式(這里不討論緩存雪崩的問題),這個【比較好】是在實現難度和數據一致性之間找到了一個平衡點;實現起來非常簡單,但是可能在數據變化后,緩存失效前的這段時間,數據庫和緩存之間的數據是不一致的(但最終會一致)。 先更新數據庫,再更新緩存:有兩個比較大的問題,一是多線程的時候,可能會造成數據庫和緩存數據的不一致,而且這個不一致可能會是長期的。二是如果更新操作比較多的話,會頻繁地更新緩存。
- A線程:set數據庫key=1;
- B線程:set數據庫key=100;
- B線程:set緩存key=100;
- A線程:set緩存key=1;(實際上,應該等于100,這樣就造成了緩存和數據庫中的數據不一致,并且如果數據不再更新,那么會使長期不一致)
先刪緩存,再更新數據庫:這個會出現問題,還是A/B兩個線程,如果A刪除了緩存之后,在更新數據庫之前,B過來查詢不到緩存,于是就查詢了數據庫(A還沒更新),把數據寫入緩存,這時候A才把數據庫更新掉,這可能就會造成永久性的不一致。 先更新數據庫,再刪緩存:一樣的道理,大家可以自己想一想這個過程。
有些人可能覺得這個概率很小,怎么可能有這么巧的事情,恰好都是A做到一半,B插進來把全部的事情做完,A再去做后一半的操作;但是概率小,也是可能發生的,不得不考慮。
還有很多復雜的實現方案,比如更新完數據庫之后,把更新操作發給有序的消息隊列(不過過程越復雜,不一致的時間會越長),由另外的線程從隊列里面順序執行更新或刪除緩存的操作;
不過我認為,