如何保證mongodb和資料庫雙寫資料一致性?
前言
最近在我的技術群裡,有位小夥伴問了大家一個問題:如何保證Mongodb和資料庫雙寫的資料一致性?
群友們針對這個技術點討論的內容,引起了我的興趣。
其實我在實際工作中的有些業務場景,也在使用Mongodb
,也遇到過雙寫的資料一致性問題。
今天跟大家一起分享一下,這類問題的解決辦法,希望對你會有所幫助。
1 常見誤區
很多小夥伴看到雙寫資料一致性問題,首先會想到的是Redis
和資料庫
的資料雙寫一致性問題。
有些小夥伴認為,Redis
和資料庫
的資料雙寫一致性問題,跟Mongodb
和資料庫
的資料雙寫一致性問題,是同一個問題。
但如果你仔細想想它們的使用場景,就會發現有一些差異。
1.1 我們是如何用快取的?
Redis快取能提升我們系統的效能。
一般情況下,如果有使用者請求過來,先查快取,如果快取中存在資料,則直接返回。如果快取中不存在,則再查資料庫,如果資料庫中存在,則將資料放入快取,然後返回。如果資料庫中也不存在,則直接返回失敗。
流程圖如下:有了快取之後,能夠減輕資料庫的壓力,提升系統效能。
通常情況下,保證快取和資料雙寫資料一致性,最常用的技術方案是:延遲雙刪
。
感興趣的小夥伴,可以看看我的另一篇文章《如何保證資料庫和快取雙寫一致性?》,裡面有非常詳細的介紹。
1.2 我們是如何用MongoDB的?
MongoDB
是一個高可用、分散式的文件資料庫
,用於大容量資料儲存。文件儲存一般用類似json
的格式儲存,儲存的內容是文件型的。
通常情況下,我們用來儲存大資料或者json格式的資料。
使用者寫資料的請求,核心資料
會被寫入資料庫,json格式的非核心資料
,可能會寫入MongoDB。
流程圖如下:此外,在資料庫的表中,儲存了MongoDB相關文件的id。
使用者讀資料的請求,會先讀資料庫中的資料,然後透過文件的id,讀取MongoDB中的資料。
流程圖如下:這樣可以保證核心屬性不會丟失,同時儲存使用者傳入的較大的資料,兩全其美。
Redis和MongoDB在我們實際工作中的用途不一樣,導致了它們雙寫資料一致性問題的解決方案是不一樣的。
接下來我們一起看看,如何保證MongoDB和資料庫的雙寫的資料一致性?
2 如何保證雙寫一致性?
目前雙寫MongoDB和資料庫的資料,用的最多的就是下面這兩種方案。
2.1 先寫資料庫,再寫MongoDB
該方案最簡單,先在資料庫中寫入核心資料,再在MongoDB中寫入非核心資料。
流程圖如下:如果有些業務場景,對資料的完整性要求不高,即非核心資料可有可無,使用該方案也是可以的。
但如果有些業務場景,對資料完整性要求比較高,用這套方案可能會有問題。
當資料庫剛儲存了核心資料,此時網路出現異常,程式儲存MongoDB的非核心資料時失敗了。
但MongoDB並沒有丟擲異常,資料庫中已經儲存的資料沒法回滾,這樣會出現資料庫中儲存了資料,而MongoDB中沒儲存資料的情況,從而導致MongoDB中的非核心資料丟失的問題。
所以這套方案,在實際工作中使用不多。
2.2 先寫MongoDB,再寫資料庫
在該方案中,先在MongoDB中寫入非核心資料,再在資料庫中寫入核心資料。
流程圖如下:關鍵問題來了:如果MongoDB中非核心資料寫入成功了,但資料庫中的核心資料寫入失敗了怎麼辦?
這時候MongoDB中非核心資料不會回滾,可能存在MongoDB中儲存了資料,而資料庫中沒儲存資料的問題,同樣會出現資料不一致的問題。
答:我們忘了一個前提,查詢MongoDB文件中的資料,必須透過資料庫的表中儲存的mongo id
。但如果這個mongo id
在資料庫中都沒有儲存成功,那麼,在MongoDB文件中的資料是永遠都查詢不到的。
也就是說,這種情況下MongoDB文件中儲存的是垃圾資料,但對實際業務並沒有影響。
這套方案可以解決雙寫資料一致性問題,但它同時也帶來了兩個新問題:
使用者修改操作如何儲存資料? 如何清理垃圾資料?
3 使用者修改操作如何儲存資料?
我之前聊的先寫MongoDB,再寫資料庫,這套方案中的流程圖,其實主要說的是新增資料的場景。
但如果在使用者修改資料的操作中,使用者先修改MongoDB文件中的資料,再修改資料庫表中的資料。
流程圖如下:如果出現MongoDB文件中的資料修改成功了,但資料庫表中的資料修改失敗了,不也出現問題了?
那麼,使用者修改操作時如何儲存資料呢?
這就需要把流程調整一下,在修改MongoDB文件時,還是新增一條資料,不直接修改,生成一個新的mongo id。然後在修改資料庫表中的資料時,同時更新mongo id欄位為這個新值。
流程圖如下:這樣如果新增MongoDB文件中的資料成功了,但修改資料庫表中的資料失敗了,也沒有關係,因為資料庫中老的資料,儲存的是老的mongo id。透過該id,依然能從MongoDB文件中查詢出資料。
使用該方案能夠解決修改資料時,資料一致性問題,但同樣會存在垃圾資料。
其實這個垃圾資料是可以即使刪除的,具體流程圖如下:在之前的流程中,修改完資料庫,更新了mongo id為新值,接下來,就把MongoDB文件中的那條老資料直接刪了。
該方案可以解決使用者修改操作中,99%的的垃圾資料,但還有那1%的情況,即如果最後刪除失敗該怎麼辦?
答:這就需要加重試機制
了。
我們可以使用job
或者mq
進行重試,優先推薦使用mq增加重試功能。特別是想RocketMQ
,自帶了失敗重試機制,有專門的重試佇列
,我們可以設定重試次數
。
流程圖最佳化如下:將之前刪除MongoDB文件中的資料操作,改成傳送mq訊息,有個專門的mq消費者,負責刪除資料工作,可以做成共用的功能。它包含了失敗重試機制,如果刪除5次還是失敗,則會把該訊息儲存到死信佇列
中。
然後專門有個程式監控死信佇列中的資料,如果發現有資料,則發報警郵件
。
這樣基本可以解決修改刪除垃圾資料失敗的問題。
4 如何清理新增的垃圾資料?
還有一種垃圾資料還沒處理,即在使用者新增資料時,如果寫入MongoDB文件成功了,但寫入資料庫表失敗了。由於MongoDB不會回滾資料,這時候MongoDB文件就儲存了垃圾資料,那麼這種資料該如何清理呢?
4.1 定時刪除
我們可以使用job定時掃描,比如:每天
掃描一次MongoDB文件,將mongo id取出來,到資料庫查詢資料,如果能查出資料,則保留MongoDB文件中的資料。
如果在資料庫中該mongo id不存在,則刪除MongoDB文件中的資料。
如果MongoDB文件中的資料量不多,是可以這樣處理的。但如果資料量太大,這樣處理會有效能問題。
這就需要做最佳化,常見的做法是:縮小掃描資料的範圍
。
比如:掃描MongoDB文件資料時,根據建立時間,只查最近24小時的資料,查出來之後,用mongo id去資料庫查詢資料。
如果直接查最近24小時的資料,會有問題,會把剛寫入MongoDB文件,但還沒來得及寫入資料庫的資料也查出來,這種資料可能會被誤刪。
可以把時間再整體提前一小時,例如:
in_time < 當前時間-1 and in_time >= 當前時間-25
獲取25小時前到1小時前的資料。
這樣可以解決大部分系統中,因為資料量過多,在一個定時任務的執行週期內,job處理不完的問題。
但如果根據時間縮小範圍之後,資料量還是太大,job還是處理不完該怎麼辦?
答:我們可以在job用多執行緒
刪除資料。
當然我們還可以將job的執行時間縮短,根據實際情況而定,比如每隔12小時,查詢建立時間是13小時前到1小時前的資料。
或者每隔6小時,查詢建立時間是7小時前到1小時前的資料。
或者每隔1小時,查詢建立時間是2小時前到1小時前的資料等等。
4.2 隨機刪除
其實刪除垃圾資料還有另外一種思路。
不知道你瞭解過Redis
刪除資料的策略
嗎?它在處理大批次資料時,為了防止使用過多的CPU資源,用了一種隨機刪除
的策略。
我們在這裡可以借鑑一下。
有另外一個job,每隔500ms隨機
獲取10條資料進行批次處理,當然獲取的資料也是根據時間縮小範圍的。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024420/viewspace-2927956/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 如何保證快取與資料庫的雙寫一致性?快取資料庫
- 如何保證快取(redis)與資料庫的雙寫一致性快取Redis資料庫
- 阿里面試題:如何保證快取與資料庫的雙寫一致性?阿里面試題快取資料庫
- 資料庫和快取的一致性如何保證資料庫快取
- 如何保證快取和資料庫的一致性?快取資料庫
- 使用雙非同步後,如何保證資料一致性?非同步
- 趣說 | 資料庫和快取如何保證一致性?資料庫快取
- 如何保證MySQL和Redis資料一致性?MySqlRedis
- 面試常問:如何保證Redis快取和資料庫的資料一致性NRXW面試Redis快取資料庫
- 面試重災區:怎麼保證快取與資料庫的雙寫一致性?面試快取資料庫
- 冗餘資料一致性,到底如何保證?
- 資料庫與快取雙寫一致性資料庫快取
- 資料庫和快取雙寫一致性方案總結分析資料庫快取
- 快取與資料庫的雙寫一致性快取資料庫
- 針對靜默資料錯誤,如何採用DIX和DIF保證資料一致性?
- Zookeeper 如何保證分散式系統資料一致性分散式
- 分散式之資料庫和快取雙寫一致性方案解析分散式資料庫快取
- 分散式之資料庫和快取雙寫一致性方案(二)分散式資料庫快取
- mongodb 如何建立資料庫MongoDB資料庫
- 快取與資料庫雙寫一致性 深度分析快取資料庫
- 如何能保證頁面顯示的資料與資料庫的資料同步資料庫
- FAQ系列|如何保證主從複製資料一致性
- Oracle Goldengate是如何保證資料有序和確保資料不丟失的?OracleGo
- 美團二面:Redis與MySQL雙寫一致性如何保證?RedisMySql
- Spark CommitCoordinator 保證資料一致性SparkMIT
- mongodb資料庫如何建立索引?MongoDB資料庫索引
- 【面試普通人VS高手系列】Redis和Mysql如何保證資料一致性面試RedisMySql
- 如何修改MongoDB3.0的資料庫認證機制MongoDB資料庫
- 快取與資料庫雙寫一致性幾種策略分析快取資料庫
- MongoDB資料庫MongoDB資料庫
- MySQL是怎麼保證資料一致性的MySql
- Elasticsearch如何保證資料不丟失?Elasticsearch
- 深入理解分散式之資料庫和快取雙寫一致性方案解析分散式資料庫快取
- mongodb資料庫中插入資料MongoDB資料庫
- 如何將 EXCEL 資料寫入資料庫Excel資料庫
- 如何保證資料新增或修改成功失敗的一致性?
- Elasticsearch 如何保證寫入過程中不丟失資料的Elasticsearch
- MySQL InnoDB資料庫如何保證事務特性示例詳解MySql資料庫