Redis、MySQL快取雙寫不一致怎麼辦?本篇文章就來跟大家分享解決快取雙寫不一致問題的方法,希望能夠給大家幫忙!
redis、mysql雙寫快取不一致:
但是在更新快取方面,對於更新完資料庫,是更新快取呢,還是刪除快取。
又或是先刪除緩存,再更新資料庫,其實大家存在很大的爭議。
目前沒有一篇全面的博客,對這幾種方案進行解析。於是部落客戰戰兢兢,頂著被大家噴的風險,寫了這篇文章。
正文
給快取資料設定過期時間
先做一個說明,從理論上來說,給快取設置過期時間,是確保最終一致性的解決方案。這種方案下,我們可以對存入快取的資料設定過期時間,所有的寫入操作以資料庫為準,對快取操作只是盡力即可。也就是說如果資料庫寫成功,快取更新失敗,那麼只要到達過期時間,則後面的讀取請求自然會從資料庫讀取新值然後回填快取。因此,接下來討論的思路不依賴給快取設定過期時間這個方案。
在這裡,我們先討論三種更新策略:
- 先更新資料庫,再更新快取
- 先刪除緩存,再更新資料庫
- 先更新資料庫,再刪除快取
先更新資料庫,再更新快取
這套方案,大家普遍反對。為什麼呢?有以下兩點:
- 原因一(線程安全角度)
(1)線程A更新了資料庫
(2)線程B更新了資料庫
(3)線程B更新了快取
(4)線程A更新了快取
這就出現請求A更新快取應該比請求B更新快取早才對,但是因為網路等原因, B卻比A更早更新了快取。這就導致了髒數據,因此不考慮。
- 原因二(業務場景角度)
(1)如果你是一個寫資料庫場景比較多,而讀資料場景比較少的業務需求,採用這種方案就會導致,資料壓根還沒讀到,快取就被頻繁的更新,浪費效能。
(2)如果你寫入資料庫的值,並不是直接寫入快取的,而是要經過一連串複雜的計算再寫入快取。那麼,每次寫入資料庫後,都再次計算寫入快取的值,無疑是浪費效能的。顯然,刪除快取更適合。
先刪除緩存,再更新資料庫
該方案會導致不一致原因是。同時一個請求A進行更新操作,另一個請求B進行查詢操作。那麼就會出現如下情形:
(1)請求A進行寫入操作,刪除快取
(2)請求B查詢發現快取不存在
(3)請求B去資料庫查詢得到舊值
(4)請B將舊值寫入快取
(5)請求A將新值寫入資料庫
上述情況就會導致不一致的情形出現。而且,如果不採用給快取設定過期時間策略,該資料永遠都是髒資料。
那麼,要如何解決呢?採用延時雙刪策略
快取延時雙刪
public class CacheServiceImpl implements ICacheService { @Resource private RedisOperator redisOperator; @Autowired private IShopService shopService; //1. 采用延时双删,解决数据库和缓存的一致性 @Override public void updateHotCount(String id) { try { //删除缓存 redisOperator.del("redis_key_" + id); //更新数据库 shopService.updataHotShop(); Thread.sleep(1000);//休眠1秒 //延时删除 redisOperator.del("redis_key_" + id); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public Integer getHotCount(String id) { return null; }}
解釋:
- ##先淘汰快取
- 再寫資料庫
- 休眠1秒,再淘汰快取(
- 這麼做,可以將1秒內所造成的快取髒數據,再刪除。)
#針對上面的情形,讀者應該自行評估自己的專案的讀取資料業務邏輯的耗時。然後寫資料的休眠時間則在讀取資料業務邏輯的耗時基礎上,加幾百ms即可。這麼做的目的,就是確保讀取請求結束,寫入請求可以刪除讀取請求造成的快取髒資料。
如果資料庫採用了讀寫分離架構,那麼辦? (主庫負責寫入操作,從庫負責讀取操作)
ok,在這種情況下,造成資料不一致的原因如下,還是兩個請求,一個請求A進行更新操作,另一個請B進行查詢操作。 (1)請求A進行寫入操作,刪除緩存,請求A把資料寫入主庫,還沒開始同步從庫(2)(1s內)請求B查詢緩存,沒有發現緩存,請求B去從庫查詢,這時還沒有完成主從同步,查到是舊值,並且把舊值寫入緩存。 (3)主庫完成主從同步,從庫變成新值上述流程,就是資料不一致問題,也使用雙刪延時策略。只是,睡眠時間修改為在主從同步的延時時間基礎之上,加幾百ms採用這種同步淘汰策略,吞吐量降低怎麼辦?
ok,那就將第二次刪除當作非同步的。自己起一個線程,非同步刪除。這樣,寫的請求就不用沉睡一段時間後了,再回來。這麼做,加大吞吐量。
第二次刪除,如果刪除失敗怎麼辦?
這是個非常好的問題,因為第二次刪除失敗,就會出現如下情形。還是有兩個請求,一個請求A進行更新操作,另一個請求B進行查詢操作,為了方便,假設是單庫:
(1)請求A進行寫入操作,刪除快取
( 2)請求B查詢發現快取不存在
(3)請求B去資料庫查詢得到舊值
(4)請求B將舊值寫入快取
(5)請求A將新值寫入資料庫
(6)請求A試圖去刪除請求B寫入對快取值,結果失敗了。
ok,這也就是說。如果第二次刪除快取失敗,會再次出現快取和資料庫不一致的問題。
如何解決呢?
具體解決方案,且看部落客對第先更新資料庫,再刪除快取種更新策略的解析。
刪除快取重試機制
不管是延時雙刪還是Cache-Aside的先操作資料庫再刪除快取,都可能存在第二步驟的刪除快取失敗,導致的資料不一致問題。可以使用這個方案優化:刪除失敗就多刪除幾次呀,保證刪除快取成功就可以了呀~ 所以可以引入刪除快取重試機制
- #(1)更新資料庫資料;
(2)快取因為種種問題刪除失敗
(3)將需要刪除的key傳送至訊息佇列
(4)自己消費訊息,取得需要刪除的key
(5)繼續重試刪除操作,直到成功
然而,該方案有一個缺點,對業務線程式碼造成大量的侵入。於是有了方案二,在方案二中,啟動一個訂閱程式去訂閱資料庫的binlog,取得需要操作的資料。在應用程式中,另起一段程序,獲得這個訂閱程序傳來的信息,進行刪除快取操作。
讀取biglog非同步刪除快取
#流程如下圖所示:
(1)更新資料庫資料
(2)資料庫會將操作資訊寫入binlog日誌當中
(3)訂閱程式擷取所需的資料以及key
(4)另起一段非業務程式碼,取得該資訊
(5)嘗試刪除快取操作,發現刪除失敗
(6)將這些資訊傳送至訊息佇列
(7)重新從訊息佇列中取得該數據,重試操作。
備註說明:上述的訂閱binlog程式在mysql中有現成的中間件**叫canal,**可以完成訂閱binlog日誌的功能。至於oracle中,部落客目前不知道有沒有現成中間件可以使用。另外,重試機制,部落客是採用的是訊息佇列的方式。如果對一致性要求不是很高,直接在程式中另起一個線程,每隔一段時間去重試即可,這些大家可以靈活自由發揮,只是提供一個思路。
本文其實是對目前網路中已有的一致性方案,做了一個總結。對於先刪緩存,再更新資料庫的更新策略,還有方案提出維護一個內存隊列的方式,博主看了一下,覺得實現異常複雜,沒有必要,因此沒有必要在文中給出。最後,希望大家有所收穫。
【相關推薦:mysql影片教學】
#以上是Redis、MySQL快取雙寫不一致怎麼辦?解決方案分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!

MySQL適合初學者學習數據庫技能。 1.安裝MySQL服務器和客戶端工具。 2.理解基本SQL查詢,如SELECT。 3.掌握數據操作:創建表、插入、更新、刪除數據。 4.學習高級技巧:子查詢和窗口函數。 5.調試和優化:檢查語法、使用索引、避免SELECT*,並使用LIMIT。

MySQL通過表結構和SQL查詢高效管理結構化數據,並通過外鍵實現表間關係。 1.創建表時定義數據格式和類型。 2.使用外鍵建立表間關係。 3.通過索引和查詢優化提高性能。 4.定期備份和監控數據庫確保數據安全和性能優化。

MySQL是一個開源的關係型數據庫管理系統,廣泛應用於Web開發。它的關鍵特性包括:1.支持多種存儲引擎,如InnoDB和MyISAM,適用於不同場景;2.提供主從復制功能,利於負載均衡和數據備份;3.通過查詢優化和索引使用提高查詢效率。

SQL用於與MySQL數據庫交互,實現數據的增、刪、改、查及數據庫設計。 1)SQL通過SELECT、INSERT、UPDATE、DELETE語句進行數據操作;2)使用CREATE、ALTER、DROP語句進行數據庫設計和管理;3)複雜查詢和數據分析通過SQL實現,提升業務決策效率。

MySQL的基本操作包括創建數據庫、表格,及使用SQL進行數據的CRUD操作。 1.創建數據庫:CREATEDATABASEmy_first_db;2.創建表格:CREATETABLEbooks(idINTAUTO_INCREMENTPRIMARYKEY,titleVARCHAR(100)NOTNULL,authorVARCHAR(100)NOTNULL,published_yearINT);3.插入數據:INSERTINTObooks(title,author,published_year)VA

MySQL在Web應用中的主要作用是存儲和管理數據。 1.MySQL高效處理用戶信息、產品目錄和交易記錄等數據。 2.通過SQL查詢,開發者能從數據庫提取信息生成動態內容。 3.MySQL基於客戶端-服務器模型工作,確保查詢速度可接受。

構建MySQL數據庫的步驟包括:1.創建數據庫和表,2.插入數據,3.進行查詢。首先,使用CREATEDATABASE和CREATETABLE語句創建數據庫和表,然後用INSERTINTO語句插入數據,最後用SELECT語句查詢數據。

MySQL適合初學者,因為它易用且功能強大。 1.MySQL是關係型數據庫,使用SQL進行CRUD操作。 2.安裝簡單,需配置root用戶密碼。 3.使用INSERT、UPDATE、DELETE、SELECT進行數據操作。 4.複雜查詢可使用ORDERBY、WHERE和JOIN。 5.調試需檢查語法,使用EXPLAIN分析查詢。 6.優化建議包括使用索引、選擇合適數據類型和良好編程習慣。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

SublimeText3 英文版
推薦:為Win版本,支援程式碼提示!

Atom編輯器mac版下載
最受歡迎的的開源編輯器

Dreamweaver Mac版
視覺化網頁開發工具