据我了解,这就是发生的事情。我简化了一点,但它应该清楚它是如何工作的。
- 客户端连接到 mongo。到目前为止没有写入,也没有断开连接,因为它真的取决于现在发生的写入问题。让我们假设我们使用(在撰写本文时)默认的“已确认”。
- 客户端发送它的写操作。这是我真的不确定的地方。在此步骤或下一个步骤之后,确认将发送给驱动程序。
- 写操作通过查询优化器运行。在这里发送确认,因为在确认的写入问题中,您可能会收到重复键错误。这可能是在最后一步中检查的。如果我应该打赌,我会说是在这个之后。
- 查询优化器的输出然后应用到内存中的数据实际上是内存映射数据文件的数据,内存映射的 oplog 和日志的内存映射文件。从该内存映射部分回答查询,或者将相应的数据映射到内存以回答查询。如果存在,oplog 也会从内存中读取。
- 一般每 100 毫秒,日志就会同步到磁盘。精确值由许多因素决定,其中之一是journalCommitInterval 配置参数。如果您有日志的写入问题,现在将通知驱动程序。
- 每syncDelay秒,内存映射文件的当前状态都会同步到磁盘我认为日志被截断为尚未应用于数据的条目,但我不太确定,因为它基本上不应该发生日志中的数据尚未应用于当前数据。
如果您仔细阅读,您会注意到数据早在通过查询优化器运行并应用于映射到内存的文件时就已为 oplog 准备好。当 oplog 条目被其中一个辅助节点拉取时,它会立即应用于内存映射文件的数据,并以与主节点相同的方式同步到磁盘中。
一些需要注意的事项: 相对较小的数据一旦写入日志,是相当安全的。如果一个节点在两次同步到数据文件之间发生故障,则数据文件和 oplog 都可以从它们在数据文件和日志中的最后状态恢复。一般来说,您可以拥有的最大数据丢失是上次提交后记录到日志中的操作,中位数为 50 毫秒。
至于锁。如果您写得仔细,当数据同步到磁盘时,不会在数据库级别上施加锁定。可以创建写锁以确保在任何给定时间点只有一个线程修改给定文档。还有其他可能的写锁,但一般来说,它们应该很少见。
文件系统层上的写锁只创建一次,尽管只是隐式的,iirc。在应用程序启动期间,会在 dbpath 的根目录中创建一个锁定文件。当存在有效锁时,任何其他 mongod 实例都将拒绝对这些数据文件执行任何操作。你也不应该;)
希望这可以帮助。