《分布式之資料庫快取雙寫一致性方案解析》

2022-06-27 23:42:10 字數 1686 閱讀 9621

但是在更新快取方面,對於更新完資料庫,是更新快取呢,還是刪除快取。又或者是先刪除快取,再更新資料庫,其實大家存在很大的爭議。目前沒有一篇全面的部落格,對這幾種方案進行解析。於是博主戰戰兢兢,頂著被大家噴的風險,寫了這篇文章。

本文由以下三個部分組成 1、講解快取更新策略 2、對每種策略進行缺點分析 3、針對缺點給出改進方案

先做乙個說明,從理論上來說,給快取設定過期時間,是保證最終一致性的解決方案。這種方案下,我們可以對存入快取的資料設定過期時間,所有的寫操作以資料庫為準,對快取操作只是盡最大努力即可。也就是說如果資料庫寫成功,快取更新失敗,那麼只要到達過期時間,則後面的讀請求自然會從資料庫中讀取新值然後回填快取。因此,接下來討論的思路不依賴於給快取設定過期時間這個方案。 在這裡,我們討論三種更新策略:

應該沒人問我,為什麼沒有先更新快取,再更新資料庫這種策略。

這就出現請求a更新快取應該比請求b更新快取早才對,但是因為網路等原因,b卻比a更早更新了快取。這就導致了髒資料,因此不考慮。

(2)如果你寫入資料庫的值,並不是直接寫入快取的,而是要經過一系列複雜的計算再寫入快取。那麼,每次寫入資料庫後,都再次計算寫入快取的值,無疑是浪費效能的。顯然,刪除快取更為適合。

接下來討論的就是爭議最大的,先刪快取,再更新資料庫。還是先更新資料庫,再刪快取的問題。

public void write(string key,object data)

那麼,這個1秒怎麼確定的,具體該休眠多久呢?

如果你用了mysql的讀寫分離架構怎麼辦?

採用這種同步淘汰策略,吞吐量降低怎麼辦?

第二次刪除,如果刪除失敗怎麼辦?

失效:應用程式先從cache取資料,沒有得到,則從資料庫中取資料,成功後,放到快取中。

更新:先把資料存到資料庫中,成功後,再讓快取失效。

這種情況不存在併發問題麼?

然而,發生這種情況的概率又有多少呢?

發生上述情況有乙個先天性條件,就是步驟(3)的寫資料庫操作比步驟(2)的讀資料庫操作耗時更短,才有可能使得步驟(4)先於步驟(5)。

如何解決上述併發問題?

還有其他造成不一致的原因麼?

有的,這也是快取更新策略(2)和快取更新策略(3)都存在的乙個問題,如果刪快取失敗了怎麼辦,那不是會有不一致的情況出現麼。比如乙個寫資料請求,然後寫入資料庫了,刪快取失敗了,這會就出現不一致的情況了。這也是快取更新策略(2)裡留下的最後乙個疑問。

(7)重新從訊息佇列中獲得該資料,重試操作。

備註說明:上述的訂閱binlog程式在mysql中有現成的中介軟體叫canal,可以完成訂閱binlog日誌的功能。至於oracle中,博主目前不知道有沒有現成中介軟體可以使用。另外,重試機制,博主是採用的是訊息佇列的方式。如果對一致性要求不是很高,直接在程式中另起乙個執行緒,每隔一段時間去重試即可,這些大家可以靈活自由發揮,只是提供乙個思路。

本文其實是對目前網際網路中已有的一致性方案,進行了乙個總結。對於先刪快取,再更新資料庫的更新策略,還有方案提出維護乙個記憶體佇列的方式,博主看了一下,覺得實現異常複雜,沒有必要,因此沒有必要在文中給出。最後,希望大家有所收穫。

1、主從db與cache一致性

分布式之資料庫和快取雙寫一致性方案解析

對每種策略進行缺點分析 針對缺點給出改進方案 先刪除快取,再更新資料庫 先更新資料庫,再刪除快取 執行緒b更新了資料庫 執行緒b更新了快取 執行緒a更新了快取 請求b查詢發現快取不存在 請求b去資料庫查詢得到舊值 請求b將舊值寫入快取 請求a將新值寫入資料庫 public void write st...

分布式之資料庫和快取雙寫一致性方案解析

為什麼寫這篇文章?首先,快取由於其高併發和高效能的特性,已經在專案中被廣泛使用。在讀取快取方面,大家沒啥疑問,都是按照下圖的流程來進行業務操作。但是在更新快取方面,對於更新完資料庫,是更新快取呢,還是刪除快取。又或者是先刪除快取,再更新資料庫,其實大家存在很大的爭議。目前沒有一篇全面的部落格,對這幾...

分布式之資料庫和快取雙寫一致性方案解析

首先,快取由於其高併發和高效能的特性,已經在專案中被廣泛使用。在讀取快取方面,大家沒啥疑問,都是按照下圖的流程來進行業務操作。但是在更新快取方面,對於更新完資料庫,是更新快取呢,還是刪除快取。又或者是先刪除快取,再更新資料庫,其實大家存在很大的爭議。目前沒有一篇全面的部落格,對這幾種方案進行解析。於...