也许。是的,它等待数据被写入,但根据文档,有一个“当写入操作不完全持久时,日志提交之间存在一个窗口”,不管是什么。我找不到他们指的是什么。
我将编辑后的答案留在这里,但我来回颠倒了自己,所以有点烦人:
这有点棘手,因为您可以拉很多杠杆:
您的 MongoDB 设置
假设日志已激活(默认为 64 位),日志将定期提交。如果日志和数据文件在同一个块设备上,则默认值为journalCommitInterval
100 毫秒,否则为 30 毫秒(因此最好将日志放在单独的磁盘上)。
您也可以将其更改journalCommitInterval
为低至 2ms,但这会增加写入操作的数量并降低整体写入性能。
写作问题
您需要指定一个写入关注点,告诉驱动程序和数据库等到数据写入磁盘。但是,这不会等到数据实际写入磁盘,因为在默认设置的坏情况下,这将花费 100 毫秒。
所以,在最好的情况下,有一个 2ms 的窗口,数据可能会丢失。然而,这对于许多应用程序来说是不够的。
该fsync
命令强制对所有数据文件进行磁盘刷新,但如果您使用日志,则没有必要这样做,而且效率低下。
现实生活中的耐用性
即使您要记录每次写入,但如果数据中心管理员遇到糟糕的一天并在您的硬件上使用电锯,或者硬件只是自行解体,这有什么好处?
冗余存储,不是像 RAID 这样的块设备级别,而是更高级别的冗余存储对于许多场景来说是一个更好的选择:将数据放在不同的位置,或者至少在不同的机器上使用副本集,并使用w:majority
启用日志的写入关注(不过,日志仅适用于主节点)。在个别机器上使用 RAID 来增加你的运气。
这提供了性能、耐用性和一致性的最佳折衷。此外,它允许您为每次写入调整写入关注点,并且具有良好的可用性。如果数据在三台不同的机器上排队等待下一次 fsync,那么任何一台机器上的下一次日志提交可能仍然需要 30 毫秒(最坏情况),但三台机器在 30 毫秒间隔内停机的可能性可能是百万倍低于电锯屠杀管理场景。
证据
TL; DR:我认为我上面的回答是正确的。
文档可能有点烦人,尤其是关于wtimeout
,所以我检查了源代码。我不是 mongo 来源的专家,所以对此持保留态度:
在write_concern.cpp
中,我们发现(为简洁而编辑):
if ( cmdObj["j"].trueValue() ) {
if( !getDur().awaitCommit() ) {
// --journal is off
result->append("jnote", "journaling not enabled on this server");
} // ...
}
else if ( cmdObj["fsync"].trueValue() ) {
if( !getDur().awaitCommit() ) {
// if get here, not running with --journal
log() << "fsync from getlasterror" << endl;
result->append( "fsyncFiles" , MemoryMappedFile::flushAll( true ) );
}
注意调用MemoryMappedFile::flushAll( true )
iffsync
已设置。这个调用显然不在第一个分支中。否则,持久性将在单独的线程上处理(相关文件前缀为dur_
)。
这就解释了什么wtimeout
是for:它是指等待slave的时间,与服务器上的I/O或fsync无关。