天天看點

MongoDB: 通過ReadConcern 達到 snapshot 讀的效果

MongoDB 4.0 提供了level == “snapshot” 的readConcern。 該level 的readConcern 本質上和Primary Secondary 無關, 主要解決的問題是:

時間點1: session 1 打開一個cursor 用于讀資料

時間點2: session 2 修改了 session 1 要讀的資料,并且commit 了

時間點3: session 1 讀到了 session 2 修改的資料。

最終造成了 session 1 讀取到的資料 并不是 “時間點1” 的資料。

snapshot 正是用于解決上述問題。

使用方法

需要啟動一個transaction 并指定readConcern level == “snapshot”

session.startTransaction({readConcern: {level: "snapshot"}})
var cursor = coll.find({..})
while (cursor.hasNext()) {
    printjson(cursor.next());
}
session.commitTransaction()           

實作原理

一個正常的讀請求的邏輯如下:

while (!batch.full() && wtCursor.hasNext()) {
    next = wtCursor.next();
    if (filter.matches(next) {
      batch.add(next);
    }
    if (timeToYield()) {
        checkForInterrupt();
        wtCursor.saveState();
        releaseLocksAndWTSnapshot();
        reacquireLocksAndWTSnapshot();
        wtCursor.restoreState();
    }
}           

對于一般的的cursor,即使在同一個batch 内部,MongoDB 也會在yield 的時候 release/reacquireLocksAndWTSnapshot. 導緻讀的不同階段也會讀取到不同時間點的snapshot 資料。主要用于減少因為snapshot 對記憶體産生的額外壓力。

對于snapshot cursor, MongoDB 不會做上述的2個步驟。對記憶體多了一些壓力,但提供了snapshot read 的結果