通常來說,在我們的系統中會把數據永久保存在DB中,並且冗余一份數據在緩存中。讀請求優先從緩存讀取數據,沒有再從DB讀取,如下圖:
這樣做的好處是可以減小DB的壓力,提高請求的響應速度。
但這種架構在提升系統讀請求處理能力的同時,給系統寫請求的處理帶來了不少的麻煩。因為數據在DB跟緩存中各自保存了一份,如何保證它們之間的數據一致就是需要注意的問題了。
當處理寫請求時有兩種方式:
一、先寫緩存再寫DB
- 如果第一步寫緩存失敗,直接返回,無影響。
- 如果緩存寫成功,DB寫失敗,此時如果不清除緩存中已寫入的數據,則會造成數據不一致(緩存中是新值,DB中是舊值)。
如果增加清除緩存的邏輯,那么清除操作又失敗了該如何處理?
二、先寫DB再寫緩存
- 如果DB寫入失敗,直接返回,無影響。
- 如果DB寫入成功,緩存寫入失敗則會造成數據不一致(即DB中是新值,緩存中是舊值)。
如果重試寫入緩存,那重試也失敗該如何處理?
三、問題分析
問題本質上就是一個分布式數據一致性問題,在不要求強一致性的場景下,我們只要開辟一個異步任務去保證最終一致性即可。
就上面所說的場景來說,發生失敗時,我們可以開啟一個異步線程去做數據回填操作,反復重試直到成功。如果采用異步線程回填數據的方式做最終一致性,那么這個容錯性是內存級別的,也就是說如果此時重啟服務(線程消失),那么這個重試任務就丟失了,導致數據不一致。
其實宏觀上來說,緩存數據設置過期時間就是一種數據最終一致性的方案。這種方案下,我們可以對存入緩存的數據設置過期時間,所有的寫操作以DB為准,對緩存操作只是盡最大努力即可。也就是說如果DB寫成功,緩存更新失敗,那么只要到達過期時間,則后面的讀請求自然會從DB中讀取新值然后回填緩存,完成數據的最終一致性。