MongoDB的Journal

本文介绍了MongoDB中Journal机制如何保障数据持久性和一致性。详细解释了WiredTiger、MMAPv1和In-Memory存储引擎下Journal的运作原理,包括日志记录过程、日志文件管理和预先分配延迟等内容。

MongoDB采用提前写日志到磁盘日志文件的方式来实现发生故障时的数据持久化。
Journal是一个连续的、二进制的事务日志,在突然停机时,我们用它来恢复数据库到一个有效的状态。
下面分别介绍Journaling在三种不同存储引擎下的作用。

一、WiredTiger
WiredTiger使用检查点来为磁盘上的数据提供一个一致性的试图,允许MongoDB从上一个检查点恢复数据。然而,如果MongoDB在两个检查点之间意外退出,则会丢失两个检查点之间的数据。此时我们需要用Journaling来恢复最后一个检查点之后产生的信息。
1、使用journaling,恢复数据的步骤如下:

(1) 在数据文件中查找最后一个检查点的标识;
(2) 在journal文件中搜索匹配最后一个检查点标识的记录;
(3) 应用journal文件中从最后一个检查点之后的所有操作。

2、日志记录的过程(Journaling Process)
WiredTiger 为每一个客户端创建一个journal记录来初始化写操作。例如,更新集合中的一个文档会造成索引的修改,WiredTiger 会创建一条单独journal,该条journal中包含更新操作和与它关联的索引的修改信息。
MongoDB配置WiredTiger使用内存缓冲来存储journal记录。使用线程协调来分配和拷贝到缓冲的部分。所有大于128KB的journal记录会被缓冲。
WiredTiger 同步*缓冲的journal记录磁盘*根据以下的时间间隔或者条件:

(1) 在3.2版本中,每50毫秒同步一次
(2) MongoDB设置WiredTiger存储引擎创建检查点的时机有两个:一个是在每60秒的时候,另一个是journal文件中已经写入了2GB的数据。二者中哪一个先发生都会开始创建检查点。
(3) 如果写操作包含一个写关心j: true,那么WiredTiger会强制一次journal 文件同步。
(4) 因为MongoDB有100MB journal文件的限制,WiredTiger 会创建一个新的journal文件近似100MB数据,当创建了一个新的journal文件之后,WiredTiger会同步之前的journal文件。

注意:当在写操作之间发生突然停机的话,保存在WiredTiger缓存中的更新会丢失。

3、日志文件(Journal Files)
开启journaling的情况下,MongoDB会在dbpath下创建一个叫做journal 的子目录,WiredTiger的journal文件的名字格式为WiredTigerLog.,其中是一个用0填充的数字,从0000000001开始。
journal文件中包含对应每一次写操作的一条记录,每条记录都有唯一的标识符。WiredTiger 最小的日志记录大小是128字节,如果记录小于128字节,则不会对其压缩。
WiredTiger 会自动移除老的journal文件,并且仅维护从最后一个检查点恢复数据时所需的journal文件。

二、MMAPv1
使用MMAPv1存储引擎,当写操作发生时,MongoDB会更新内存中的视图。在journaling开启时,MongoDB首先将内存中的改变写入到磁盘上的journal文件中。如果在将数据提交到数据文件之前发生发生终止或错误,MongoDB会使用journal文件将写操作应用到数据文件中,以此来维护一个一致的状态。
1、日志记录的过程(Journaling Process)
使用journaling,MongoDB的存储层有两个关于数据集的内部视图,分别是用于写入journal文件私有视图和用于写入数据文件共享视图

(1) MongoDB首先将写操作应用于私有视图
(2) 然后,MongoDB以大约100毫秒的时间间隔将私有视图中的更改应用到日志目录中的磁盘journal文件中。MongoDB成批地将写操作记录到磁盘上的journal文件的操作叫做组提交。这样做的目的是为了最小化对journaling的性能影响,因为这些提交必须在提交期间阻塞所有的写入器。写入journal文件具有原子性。
(3) 一经journal提交,MongoDB 会将journal中的所有改变应用到共享视图中去。
(4) 最后,MongoDB将共享视图中的改变应用到数据文件中,更准确的说是,每隔60秒,MongoDB 会让操作系统刷新共享视图中的数据到数据文件。操作系统有可能会以比60秒更高的频率去刷新共享视图中的数据到数据文件,尤其是当系统内存比较小的时候。
MongoDB共享视图与磁盘上数据文件的交互方式与在不开启journaling时MongoDB的工作方式类似。不开启journaling的时候,MongoDB让操作系统每隔60秒将内存中数据的变化刷新到到磁盘的数据文件中。

2、日志文件(Journal Files)
开启journaling的情况下,MongoDB会在dbpath下创建一个叫做journal 的子目录,journal 目录下包含一些命名格式为j._的journal文件,其中从整数0开始,还包含一个“last sequence number” 文件lsn。
Journal 文件包含提前写日志;每一个journal条目描述写操作在数据文件中改变的字节数。Journal 文件是只追加文件。每当一个journal文件达到1GB,MongoDB 都会创建一个新的journal文件。如果启动数据库实例mongod的时候使用storage.smallFiles参数,则限制每一个journal文件的大小为128 megabytes(百万字节,近似于MB)
lsn文件中保存着最后一次刷新数据到数据文件的时间。
一旦MongoDB 将某个特定journal文件中的写操作写入数据文件后,MongoDB可以将它用于一个新的journal文件。
除非你每秒写很多数据,否则journal目录下将仅有两到三个journal 文件。
干净的关机会移除journal目录下的所有文件,脏关机会将journal文件留在journal目录下。这些文件会被用在重启时自动将数据库恢复数据到一个一致的状态。

3、日志目录(Journal Directory)
为了加快当前journal文件的频繁连续写入,你可以确保journal目录与数据库数据文件不在一个文件系统下。
注意:如果你将journal与数据文件放在不同的文件系统下,您不能仅使用文件系统快照来捕获dbPath目录的有效备份。在这种情况下,使用fsyncLock()以确保在快照之前数据库文件是一致的,使用fsyncUnlock() 一旦快照完成。
4、预先分配延迟(Preallocation Lag)
MongoDB 也许会预先分配journal文件如果mongod认为这样做比需要的时候再分配更加有效。
根据你的文件系统,你可能会在第一次启动一个带有journaling 的mongod实例时经历一个预先分配的延迟。预分配的时间有可能会持续几分钟,在此期间,我们将连接不到数据库,这是一次性的预分配,不会在将来的调用中发生。
避免预分配延迟的方法
你可以通过拷贝其他mongod实例的预分配文件来预分配该实例下的journal文件。预分配文件不包含数据。以后把它们移走是安全的。但是如果你用journaling重启数据库实例,数据库实例会再一次创建它们。

三、In-Memory
从MongoDB企业版本3.2.6开始,内存存储引擎成为通用版本的一部分。由于它的数据存储在内存中,所以没有单独的journal,带有写关心j的写操作会被立即确认。如果副本集中的任何一个成员没有开启journaling功能,那必须设置writeConcernMajorityJournalDefault为false。

### 关于MongoDB Journal不可用的解决方案 当遇到MongoDB中的Journal功能不可用时,通常是因为配置错误或者文件权限问题引起的。以下是可能的原因以及对应的解决方法: #### 1. 配置选项未启用 如果在启动MongoDB实例时没有指定`--journal`参数或在配置文件中缺少`storage.journal.enabled=true`设置,则可能导致Journal功能被禁用。 - **解决办法**: 修改MongoDB配置文件(通常是`mongod.conf`),确保启用了日志记录功能。 ```yaml storage: journal: enabled: true ``` - 如果是通过命令行启动MongoDB,请加上`--journal`参数[^1]: ```bash mongod --dbpath=/data/db --logpath=/var/log/mongodb.log --journal ``` #### 2. 文件系统不支持Journaling 某些文件系统(如FAT32)无法支持WAL (Write-Ahead Logging),这会阻止MongoDB正常运行其Journal机制。 - **解决办法**: 使用支持WAL的日志系统的磁盘分区来存储数据目录。推荐使用ext4、XFS或其他现代Linux文件系统[^2]。 #### 3. 权限不足 如果MongoDB进程缺乏写入Journal文件所需的适当权限,也会引发此问题。 - **解决办法**: 检查并调整数据库路径及其子目录下的访问控制列表(ACLs)以允许mongod拥有完全读取和修改的权利。 ```bash chown -R mongodb:mongodb /var/lib/mongodb/ chmod -R u+rwx,g=rx,o-rwx /var/lib/mongodb/ ``` #### 4. 硬件故障或损坏 硬盘驱动器上的坏扇区或者其他形式硬件层面的问题也可能影响到Journals的工作状态。 - **解决办法**: 执行fsck工具扫描修复潜在物理层面上的数据丢失情况;另外考虑更换有问题设备部件作为预防措施的一部分[^3]. #### 5. 日志空间耗尽 长时间运行而没有清理旧日志条目可能会导致可用磁盘空间减少至临界水平之下从而中断新的事务提交过程. - **解决办法**: 定期监控剩余容量状况并通过删除过期备份档案等方式释放更多自由区域给当前操作留有余地; 同时可以增大oplogSize参数值以便容纳更多的历史变更信息[^4]: ```javascript rs.reconfig({ ...currentConfig, members:[...newMembers], settings:{chainingBlockThresholdMB : newNumber} }) ``` 以上就是针对不同场景下如何处理MongoDB journals失效的一些常见策略总结。希望这些指导能够帮助您快速定位具体原因并对症施治恢复正常的业务流程运转效率!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值