Redis數(shù)據(jù)一致性詳解
1、一致性
一致性是指系統(tǒng)中各節(jié)點數(shù)據(jù)保持一致。分布式系統(tǒng)中,可以理解為多個節(jié)點中的數(shù)據(jù)是一致的。
一致性根據(jù)嚴(yán)苛程度分類:
強一致性:寫進去的數(shù)據(jù)是什么,讀出來的數(shù)據(jù)就是什么,對性能影響最大;
弱一致性:數(shù)據(jù)寫入成功后,系統(tǒng)不保證能立刻讀出最新的數(shù)據(jù),也不承諾多久之后數(shù)據(jù)可以達到一致,但保證到某個時間級別后,數(shù)據(jù)能達到一致;
最終一致性:最終一致性是弱一致性的一個特例,最終一致性同樣只保證數(shù)據(jù)寫入成功后,在某個時間點后數(shù)據(jù)會達到一致。這個系統(tǒng)無法保證強一致性的時間片段被稱為不一致窗口。不一致時間窗口的時間長短取決于很多因素,比如副本個數(shù)、網(wǎng)絡(luò)延遲、系統(tǒng)負(fù)載等。
最終一致性是弱一致性中非常受大眾推崇的一種一致性模型,也是目前業(yè)界在大型分布式系統(tǒng)的數(shù)據(jù)一致性上比較推崇的模型。
2、緩存使用場景
對于大部分系統(tǒng)而言,高并發(fā)常見于讀數(shù)據(jù)的場景,對于此場景我們可以使用緩存提升數(shù)據(jù)查詢速度。當(dāng)我們使用Redis作緩存的時候,常見場景如下所示:
緩存存在
如果數(shù)據(jù)在緩存中存在,則直接從緩存返回數(shù)據(jù)至應(yīng)用,無需查詢數(shù)據(jù)庫
緩存不存在
如果數(shù)據(jù)在緩存中不存在,則需查詢數(shù)據(jù)庫獲取數(shù)據(jù)并更新緩存。
對于大部分系統(tǒng)而言最終數(shù)據(jù)都會存儲在數(shù)據(jù)庫中,也就是系統(tǒng)需已數(shù)據(jù)庫中數(shù)據(jù)為準(zhǔn),那么對于上圖緩存存在的場景下,當(dāng)數(shù)據(jù)庫中的數(shù)據(jù)發(fā)生變化時,就可能會出現(xiàn)數(shù)據(jù)不一致的問題。
實際情況下考慮網(wǎng)絡(luò)、操作、異常等種種因素,根本無法保證可以同時更新所有副本數(shù)據(jù)使得數(shù)據(jù)保持一致。因此,如何在最大程度上保證各副本數(shù)據(jù)一致的同時也不影響系統(tǒng)性能,成了各系統(tǒng)需要均衡的問題。
3、數(shù)據(jù)同步策略
為保證緩存數(shù)據(jù)與數(shù)據(jù)庫數(shù)據(jù)一致,主要考慮如下兩種策略實現(xiàn):
1、先刪除緩存,再更新數(shù)據(jù)庫;
2、先更新數(shù)據(jù)庫,再刪除緩存;
當(dāng)然除了這兩種策略之外,還有其他策略如將刪除緩存改為更新緩存,但考慮高頻繁更新及熱冷數(shù)據(jù)場景下緩存使用效率問題,個人不推薦更新緩存方式,所以此處不做展開。
3.1 先刪除緩存,在更新數(shù)據(jù)庫
操作流程如圖
如上圖,若先刪除緩存,再更新數(shù)據(jù)庫,則可能存在如下問題:
若步驟5、6、7順序發(fā)生在步驟3、4之前或步驟3更新失敗,則步驟8中線程B查詢出的數(shù)據(jù)為舊數(shù)據(jù),導(dǎo)致重新寫入緩存的也為舊數(shù)據(jù)。
3.1.1 解決思路
失敗重試 + 延時雙刪
如圖中紅色部分所述,線程A在步驟4數(shù)據(jù)更新成功后,延遲一段時間,再次刪除緩存,這樣即可解決并發(fā)場景下線程B并發(fā)操作導(dǎo)致緩存與數(shù)據(jù)庫數(shù)據(jù)不一致問題。延遲時間視實際業(yè)務(wù)場景對時間敏感度而定。
3.2 先更新數(shù)據(jù)庫,再刪除緩存
操作流程如圖
如上圖,若先更新數(shù)據(jù)庫,再刪除緩存,則可能存在如下問題:
步驟5、6發(fā)生在步驟3之前或步驟3刪除緩存失敗,則線程B通過步驟5會拿到緩存數(shù)據(jù),但此時獲取到的緩存數(shù)據(jù)仍為舊數(shù)據(jù)。
3.2.1 解決思路
訂閱binlog
數(shù)據(jù)庫的每一步操作均會寫入binlog日志,可以通過監(jiān)聽binlog,實時感知數(shù)據(jù)變化情況,根據(jù)數(shù)據(jù)變化情況刪除redis并添加重試機制,直至redis刪除成功。
引入消息隊列
上圖步驟3中若Redis刪除失敗,則將Redis key放入消息隊列,消費端監(jiān)聽消息隊列并刪除Redis直至刪除成功;
總結(jié)
需要注意的是3.1.1 和 3.2.1中描述的解決方案也只能保證最終數(shù)據(jù)一致性,無法保證強一致性,如上述各場景中若線程A操作異常,在通過3.1.1 和 3.2.1的方式解決問題之前,其他線程仍有可能獲取到臟數(shù)據(jù)。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
基于redis實現(xiàn)世界杯排行榜功能項目實戰(zhàn)
前段時間,做了一個世界杯競猜積分排行榜。對世界杯64場球賽勝負(fù)平進行猜測,猜對+1分,錯誤+0分,一人一場只能猜一次。下面通過本文給大家分享基于redis實現(xiàn)世界杯排行榜功能項目實戰(zhàn),感興趣的朋友一起看看吧2018-10-10基于redis 7.2.3的makefile源碼解讀學(xué)習(xí)
這篇文章主要為大家介紹了基于redis 7.2.3的makefile源碼解讀學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12Redis如何實現(xiàn)數(shù)據(jù)庫讀寫分離詳解
Redis的主從架構(gòu),能幫助我們實現(xiàn)讀多,寫少的情況,下面這篇文章主要給大家介紹了關(guān)于Redis如何實現(xiàn)數(shù)據(jù)庫讀寫分離的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。2018-03-03Redis+PHP實現(xiàn)用戶消息推送每天最多通知2次的功能
在開發(fā)應(yīng)用程序中,經(jīng)常需要向用戶推送消息通知,但是為了避免過多的打擾用戶,我們希望限制每天最多通知2次,本篇博文將介紹如何使用PHP和Redis實現(xiàn)這一功能,文中有詳細(xì)的代碼示例,需要的朋友可以參考下2023-10-10