Java Driver 操作MongoDB GridFS 的資料正確性問題說明
主題: |
Java Driver 操作MongoDB GridFS 的資料正確性問題說明 |
文章簡介: |
介紹由Java Driver操作存取MongoDB的GridFS時,將會碰到的資料正確性問題,即不符合資料庫Transaction的一致性(Consistency)問題說明 |
作者: |
葉文華 |
版本/產出日期: |
V1.0/2016.06.28 |
1. 前言
傳統資料庫如關聯式資料庫中,Transaction的ACID(Atomicity、Consistency、Isolation、Durability)是相當重要的特性,它保證了應用程式的錯誤恢復(rollback),得以信任資料的可靠性。
但是,MongoDB這類新興的資料庫中,可能不存在Transaction的概念或是只部分達到了ACID的特性,因此應用程式若需要確保資料符合該特性,只能以其特性相似的概念來實作達到。如MongoDB建議的Two-Phase Commit做法,提供了transaction-like的操作,仍可惜Java Driver層級提供的GridFS,由Driver底層實作了檔案拆分chunks寫入資料庫的機制,卻未支持Two-Phase Commit的實踐,相當容易造成資料一致性的錯誤。
ps. MongoDB仍保證了single-document atomic的操作結果。
2. 目的
初探Java Driver底層實作GridFS的機制,及可能發生資料一致性問題的情況說明,及提供應用程式面的最簡單解決方式。
3. 開始前準備
Lib:mongo-java-driver-2.14.2.jar
Souce code:mongo-java-driver-r2.14.2.zip
4. 初探Java Driver實作GridFS機制
4.1、 由GridFS建立出可寫入MongoDB的GridFSInputFile(含GridFSFile),以及透過GridFS移除。
- 由GridFS建立GridFSInputFile:在GridFS的建構式中,將自動分成「.files」及「.chunks」兩個collections。
com.mongodb.gridfs.GridFS
com.mongodb.gridfs.GridFSInputFile |
- 由GridFSInputFile負責save:先迴圈切分檔案寫入chunks collecion,再寫入metadata資訊到files collection。由於過程中沒有實踐Two-Phase Commit,若寫入chunks collection的迴圈遭到中斷,將造成寫入部分chunks或許仍不完整,且不存在files的問題,一致性問題即由此產生。
com.mongodb.gridfs.GridFSInputFile
|
com.mongodb.gridfs.GridFSInputFile
|
4.2、 由GridFS先查詢files中存在metadata資料,並轉由GridFSDBFile執行移除動作。若發生前述files未寫入問題,將不會自動刪除chunks中資料,並且GridFSDBFile中也是分別執行了remove files及remove chunks的動作,仍有可能造成移除不完整的一致性問題。
com.mongodb.gridfs.GridFS
com.mongodb.gridfs.GridFSDBFile |
5. 驗證模擬資料一致性問題
5.1、 GridFS寫入過程中斷
經由迴圈寫入大檔案到MongoDB中,過程中直接停止程式的執行,模擬可能造成的process中斷或網路問題,並驗證資料確實出現chunks中已存在資料且不完整,但files中仍無metadata紀錄。
|
- 執行過程在第14次cycle完成前中斷。
|
- 異常的資料,僅在chunks有檔案部分(4份document)的binary,已經成了垃圾資料。
|
- 底下正常的資料除了files有metadata資訊外,chunks的完整數量是13份document。
|
5.2、 驗證移除操作
直接指定移除不完整的該筆GridFS資料,執行完成不會有任何訊息,但驗證資料的結果是沒有正確的刪除該筆資料,證實Java Driver在files中若沒有metadata紀錄的情況下,GridFS是沒有查詢結果,所以移除操作也將不會執行任何動作。
|
5.3、 再次寫入該筆資料
由於上述該筆資料,以正常GridFS進行查詢,將是沒有任何回傳結果。因此可能造成誤會該筆資料完全沒有寫入MongoDB中。以下驗證再次寫入時,將會發生DuplicateKey的問題。
|
- Java Driver在chunks collection仍存在垃圾資料時,寫入將拋出以下錯誤。
|
6. 處理GridFS寫入中斷發生的一致性錯誤問題
由於GridFS在這邊是由Java Driver底層實踐,正常的操作下指定該筆已異常的資料將無法查詢及移除。因此,可透過回歸傳統DBCollection的操作進行刪除在chunks collection的垃圾資料,便可以重新透過GridFS正常寫入該筆資料。
|
7. 參考來源
- 維基百科:資料庫-https://zh.wikipedia.org/wiki/ 資料庫
- Model Data for Atomic Operations-https://docs.mongodb.com/manual/tutorial/model-data-for-atomic-operations/
- Perform Two Phase Commits-https://docs.mongodb.com/manual/tutorial/perform-two-phase-commits/












