MongoDB 預設寫入關注儲存資料丟失問題與原始碼簡單分析

atliwen發表於2018-10-31

MongoDB 預設寫入關注可能儲存資料丟失問題分析

問題描述:

       EDI服務進行優化,將原有MQ傳送成功並且DB寫入成功,兩個條件都達成,響應接收訂單資料成功,修改為只有有一個條件成功就響應接收資料成功。只要傳送MQ成功,就代表資料已經給下游客單系統,儲存DB資料失敗可以接受,優先保證資料不阻斷。傳送MQ失敗,儲存DB資料成功,代表我們已經接受到訂單資料,可以通過容錯服務進行後續處理。這樣就可以保證MQ與DB只要有任何一個是沒問題就不會影響客戶訂單資料的正常下發。

近期發生MQ服務端忙碌,拒收生成訊息。理論上資料應該已經儲存到DB。通過容錯服務就可以處理。但是客單系統確實沒有收到,並且資料庫中也並未查詢到。ELK確實記錄了客戶是已經傳送訂單下發請求並且我們也返回成功了。

經過ELK日誌記錄排查,可以得到MQ傳送失敗,DB儲存沒有拋異常,應該算DB已經儲存成功。但是實際卻沒成功。

經過一番排查,應該是預設的儲存資料的寫入關注策略問題。

預設寫入關注設定為:WriteConcern.NORMAL

 

WriteConcern概述:

WriteConcern.NONE:               沒有異常丟擲

WriteConcern.NORMAL:           僅丟擲網路錯誤異常,沒有伺服器錯誤異常

WriteConcern.SAFE:                 丟擲網路錯誤異常、伺服器錯誤異常;並等待伺服器完成寫操作。

WriteConcern.MAJORITY:         丟擲網路錯誤異常、伺服器錯誤異常;並等待一個主伺服器完成寫操作。

WriteConcern.FSYNC_SAFE:      丟擲網路錯誤異常、伺服器錯誤異常;寫操作等待伺服器將資料重新整理到磁碟。

WriteConcern.JOURNAL_SAFE:  丟擲網路錯誤異常、伺服器錯誤異常;寫操作等待伺服器提交到磁碟的日誌檔案。

WriteConcern.REPLICAS_SAFE:  丟擲網路錯誤異常、伺服器錯誤異常;等待至少2臺伺服器完成寫操作

Spring MongoDB 設定

       <mongo:client-options write-concern="SAFE " />

Spring data MongoDB

@Autowired
MongoTemplate mongoTemplate;
mongoTemplate.setWriteConcern(WriteConcern.ACKNOWLEDGED);
mongoTemplate.save(data,"ediData");

說明:

@Deprecated
public static final WriteConcern SAFE = ACKNOWLEDGED;

SAFE 已經被棄用,原始碼可以看到直接設定為了 ACKNOWLEDGED

關於Spring data jap MongoDB MongoRepository 介面的說明與原始碼分析:

       MongoRepository提供了簡單直接的幾個方法,其中就有 save 方法。

單條儲存原始碼流程。

           

 

批量儲存

 

可以看到如果是新增資料(沒有設定ID),用save 其實也是走的 insert方法。
 

Mongodb insert 與 save 的區別說明

  insert:當主鍵"_id"在集合中存在時,不做任何處理。 拋異常

  save:當主鍵"_id"在集合中存在時,進行更新。 資料整體都會更新 ,新資料會替換掉原資料 ID 以外的所有資料。如ID 不存在就新增一條資料

       save 方法 需要遍歷列表,一個個插入, 而 insert 方法 是直接批量插入  

 

相關文章