實際業務開發中使用Mongo DB Replication 寫入後立即讀取資料不一致
我在開發實際服務時使用 MongoDB 時遇到了問題。問題是,如果寫入後立即讀取相同的數據,則數據未得到確認。當時我對題材不太了解,所以花了很多時間,也吃了不少苦頭。我寫了這個問題的情況和原因。
問題狀況
- 當時公司主要在許多服務中使用**MongoDB。
- 在創建新服務和準備全球發佈時發現的問題。 經過階段測試,服務投入生產時出現異常行為
- 伺服器請求的查詢間歇性失敗(客戶端呼叫的伺服器查詢內部寫入mongodb,然後再次讀取資料)
- 正常操作時,必須重新讀取寫入的資料並執行下一步操作,但如果失敗,則用戶端會遇到錯誤。
- 查詢依照以下流程進行:
- 客戶來電
- 向伺服器請求AWS服務並等待結果
- AWS服務完成後將結果寫入mongodb
- 寫入後,再次從mongodb讀取數據,執行以下操作
- 在伺服器上檢視AWS服務查詢時,AWS服務運作正常。
- 當我直接進入mongodb查看伺服器的寫入部分時,資料確實存在。也就是說,確認了寫入操作沒有問題。
- 伺服器查詢讀取部分失敗,但db中有寫入資料。由於具體原因尚不清楚,因此難以糾正的情況。
- 在現有測試環境檢查中未發現異常
- 測試環境為staging。產品中出現了測試時根本沒有出現的現象。
解決
- 起初並沒有被認為是環境的差異,而是認為是程式碼的bug,檢查了邏輯。即使檢查了好幾遍,也沒有發現什麼大問題。
- 一直檢查沒找到解決方法,就請教了解較多的同事,一起檢查。
- 這是一個連我的同事都不熟悉的問題,所以需要一些時間來解決。
- 當時我了解了一點分散式DB,能夠推導出問題。
- 比較階段和生產之間的差異以發現問題。比較差異時,差異如下:
- 在階段中,MongoDB 在單一節點上運行,沒有複製。
- 在生產中,MongoDB 有兩個複製輔助節點。
- 在生產環境中,配置了副本集以確保可用性。
- 在複製中,生產MongoDB寫入數據,然後將數據傳播到輔助節點。
- 由於沒有單獨設置,如果從 db 寫入並立即讀取,則讀取操作會在資料傳播到輔助資料庫之前執行。輔助將現有資料作為回應值傳遞
- 傳播時間被確認約為 2 至 4 秒。
- 後來檢查mongodb compass中的資料時,傳播時間已經過去,讀取時寫入 的資料正確可見。
- 當時出現的解決上述問題的方法如下。
- 等待客戶端輪詢,直到資料庫狀態變更。這似乎是最簡單的方法。
- 等待伺服器輪詢,直到資料庫狀態變更。從客戶端的角度來看,現有的查詢無需更改即可使用。
- 確保向mongodb查詢的傳播完成並設定為可讀,例如查詢或集合
- 我嘗試了上述方法中的第二種方法。 不是在寫入後立即進行讀取操作,而是在寫入和讀取之間添加了一個小的延遲
- 新增延遲後檢查是否正常運作
- 透過這次,我對CAP理論有了更多的了解。
- 在分散式結構的情況下,具有一致性、可用性、分區容錯性三個特徵。
- 要滿足一致性和可用性其中之一,就必須放棄另一個。
- 滿足一致性時:無論存取哪個分散式節點,資料值都必須相同。如果一致性被破壞,則請求查詢時可以傳遞不同的資料。
- 當可用性滿足時:即使一個或多個分散式節點無法同步,也能提供正常處理請求的能力。
- 由於目前資料庫結構滿足可用性而導致一致性被破壞的情況。
組織
- 如果在db中設定了複製,當寫入和讀取時間不同時要小心
- 親眼看到、感受到CAP理論是一次很好的體驗。
- 有時間就研究一下我正在開發的服務。您不可能知道所有事情,但是您知道的越多,對故障排除就越有幫助。
- 請注意,舞台和製作之間的環境可能會有所不同。也就是說,如果測試環境和實際 運行環境有差異,可能會出現問題,最好事先考慮一下。
- 為了減少調試時間,最好保持生產和階段環境幾乎相似或相同。
- 時間也是一種成本。許多事情,例如勞動成本和服務開放延遲,都可能會被延遲或導致額外成本。我認為只要成本與伺服器成本相比不是太大,舞台和製作設定相同就可以了。