數據庫最終一致性的四種方案-緩存


數據庫最終一致性的四種方案

緩存是什么

緩存的速度是有區別的.緩存就是把低速存儲的結果,臨時保存在高速存儲的數據.

img

如圖所示.金字塔更上面的存儲,可以作為下面存儲的緩存.
我們本次的討論,主要針對數據庫緩存場景,將以redis作為mysql的緩存為案例來進行.

為什么需要緩存

存儲如mysql通常支持完整的ACID特性,因為可靠性,持久性等因素.性能普遍不高,高並發的查詢會給mysql帶來壓力,造成數據庫系統的不穩定.同時也容易產生延遲.

根據局部性原理,80%請求回落到20%的熱點數據上,在讀多寫少場景,增加一層緩存非常有助於提升系統的吞吐量和健壯性.

存在問題

存儲的數據隨着時間可能發生變化,而緩存中的數據就會不一致.具體能容忍的不一致時間,需要具體業務分析,但是通常的業務,都需要做到最終一致.

Redis作為mysql緩存

通常的開發模式中,都會使用mysql作為緩存,而redis作為緩存,加速和保護mysql.但是,當mysql數據更新之后,redis怎么保持同步呢.

強一致性同步成本太高,如果追求強一致,那么就沒必要用緩存了,直接用mysql即可.通常考慮的都是最終一致性.

解決方案

方案一

通過key的過期時間,mysql更新時,redis不更新.

這種方式實現簡單,但不一致的時間會很長.如果讀請求非常頻繁,且過期時間比較長,則會產生很多長期的臟數據.

優點:

	* 開發成本低,易於實現;
	* 管理成本低,出問題概率會比較小.

缺點:

		* 完全依賴過期時間,時間太短容易緩存頻繁失效,太長容易有長時間更新延遲(不一致).

方案二

在方案一的基礎上擴展,通過key的過期時間兜底,並且,在更新mysql時,同時更新redis.

優點:

		* 相對方案一,更新延遲更小

缺點:

		* 如果更新mysql成功,更新redis卻失敗,就退化到了方案一;
		* 在高並發場景,業務server需要和mysql,redis同時進行連接.這樣需要損耗雙倍的連接資源,容易造成連接數過多的問題.

方案三

針對方案二的同步寫redis進行優化,增加消息隊列,將redis更新操作交給kafka,由消息隊列保證可靠性,再搭建一個消費服務,來異步更新redis.

優點:

		* 消息隊列可以用一個句柄,很多消息隊列客戶端還支持本地緩存發送,有效解決了方案二的連接過多問題;
		* 使用消息隊列,實現了邏輯上的解耦;
		* 消息隊列本身具有可靠性,通過手動提交等手段.可以至少一次消費到redis.

缺點:

		* 依舊解決不了時序性問題,如果多台業務服務器分別處理針對同一行數據的兩條請求,舉個例子,a=1;a=5;如果mysql中十第一條先執行,而進入kafka的順序是第二條先執行,那么數據就會產生不一致.
		* 引入了消息隊列,同時要增加服務消費消息,成本較高,還有重復消費的風險.

方案四

通過訂閱binlog來更新redis,把我們搭建的消費服務,作為mysql的一個slave,訂閱binlog,解析出更新內容,再更新到redis.

優點:

		* 在mysql壓力不大的情況下,延遲較低;
		* 和業務完全解耦
		* 解決了時序問題

缺點:

		* 要單獨搭建一個同步服務,並且引入binlog同步機制,成本較大.

總結

方案選型

首先確認產品的延遲性要求,如果延遲要求極高,且數據可能變化,別用緩存.

通常來說,方案1就夠了,因為能用緩存的方案,通常是讀多寫少場景,同時業務上對延遲具有一定的包容性.方案一是沒有開發成本的,其實比較實用.

如果想增加更新時的及時性,選擇方案二,不過沒必要做重試保證之類的.

方案3和方案4正對於對延遲要求較高業務,一個是推模式,一個是拉模式,而方案四具備更強的可靠性,既然都願意花功夫做處理消息的邏輯,不如一步到位,用方案4.

一般情況下,方案1夠用.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM