MongoDB 说写入成功了,进程被 kill -9 之后还在吗?这篇用一个单线程写入的客户端,在 w:1 和 j:true 下各 kill -9 多次,数丢了多少条,再改 journal 刷盘间隔、看恢复日志。
丢失条数 = 客户端确认过的最大序号 - 恢复后的最大序号(正数表示“确认过但丢了”)
单线程不停地 insert_one,记录客户端收到确认的最大序号;1.5 秒后 SIGKILL,重启后看最大序号,差值就是“确认过但丢了”的条数。
试验 1: 确认到 17,586 恢复后最大 _id 17,264 文档数 17,265 丢失 322 试验 2: 确认到 15,432 恢复后最大 _id 15,025 文档数 15,026 丢失 407 试验 3: 确认到 17,238 恢复后最大 _id 16,818 文档数 16,819 丢失 420 试验 4: 确认到 16,495 恢复后最大 _id 16,092 文档数 16,093 丢失 403 试验 5: 确认到 16,989 恢复后最大 _id 16,797 文档数 16,798 丢失 192
默认的 w:1 在写入进入内存与 journal 缓冲后就确认,不等 journal 落盘;kill -9 后每次丢 192~420 条。
试验 1: 确认到 484 恢复后最大 _id 484 文档数 485 丢失 0 试验 2: 确认到 482 恢复后最大 _id 483 文档数 484 丢失 0 试验 3: 确认到 480 恢复后最大 _id 481 文档数 482 丢失 0 试验 4: 确认到 472 恢复后最大 _id 472 文档数 473 丢失 0 试验 5: 确认到 429 恢复后最大 _id 430 文档数 431 丢失 0
j:true 等 journal 落盘才确认,丢失为 0,代价是吞吐大幅下降(这里 1.5 秒约 480 条,对 w:1 的约 17,000 条)。
commitIntervalMs=10 生效的配置 {'commitIntervalMs': 10};丢失条数 [0, 3, 24, 89, 102, 105, 155, 160],中位数 96,最大 160
commitIntervalMs=100 生效的配置 {'commitIntervalMs': 100};丢失条数 [3, 10, 100, 183, 214, 456, 476, 502],中位数 198,最大 502
commitIntervalMs=500 生效的配置 {'commitIntervalMs': 500};丢失条数 [12, 87, 136, 281, 331, 486, 499, 665],中位数 306,最大 665journal 默认每 100 ms 刷一次盘。间隔调到 10 ms,中位数丢失降到 96 条;调到 500 ms 升到 306 条,但单次试验的波动很大。
重启后日志里含 recover 的行: 47 条;msg 字段:
Recovering data from the last clean checkpoint.
Opening WiredTiger
WiredTiger message
WiredTiger recoveryTimestamp
Opening spill WiredTiger
mongod startup complete
WiredTiger 的 recovery 日志里不同的消息 18 条,前几条:
opening the WiredTiger library
connection configuration string parsing completed
starting WiredTiger utility threads
starting WiredTiger recovery
scanning metadata to remove all incomplete tables
scanning metadata to find the largest file ID重启时没有 checkpoint 可用(刚启动不到 60 秒),WiredTiger 的 recovery 日志记录了扫描元数据、重放 journal 的过程。
试验 1: 确认到 17,807,恢复后最大 _id 17,807,文档数 17,809(含 _id=-1 的那条 j:true 写入),丢失 0 试验 2: 确认到 16,382,恢复后最大 _id 16,382,文档数 16,384(含 _id=-1 的那条 j:true 写入),丢失 0 试验 3: 确认到 16,504,恢复后最大 _id 16,504,文档数 16,506(含 _id=-1 的那条 j:true 写入),丢失 0 试验 4: 确认到 18,576,恢复后最大 _id 18,576,文档数 18,578(含 _id=-1 的那条 j:true 写入),丢失 0
一次 j:true 的写入落盘时,journal 里它之前的所有写入也一起落盘,所以末尾补一次就能保住前面的 w:1 写入。