1 Compact 命令概述
官网对compact的说明如下:
https://www.mongodb.com/docs/v4.4/reference/command/compact/
compact 以MongoDB 集合为操作对象,重新和整理集合中所有的数据和索引。 对于WiredTiger 引擎,compact命令还会释放不需要的磁盘空间给操作系统。
Compact只能在mongod 实例上运行,不能在mongos实例上执行,对于sharded cluster环境,需要分别在每个shard上执行。
在compact 操作完成后,mongod 会并行的重建所有索引。
1.1 Compact 命令格式
Compact 语法格式:
use somedb
db.runCommnd({compact: "somecollection"})
db.runCommnd({compact: "somecollection", force: true})
Compact 命令有3个选项:
- Compact:指定操作集合的名称。
- Force:可选项。从MongoDB 4.4 开始改成flag类型,指定该选项后,将在副本集的primary 节点执行命令。在4.4 之前的版本,该选项是布尔型,仅当该选项设置为true时才可以在副本集的primary 节点执行compact 命令,当该选项设置为false时,在primary 执行将报错。 因为该命令会block 所有其他的操作。从4.4 开始,compact 不会block MongoDB 的CRUD操作。在副本集的从库执行时可以不加该选项。
- Comment:4.4 版本的新增可选项。该注释会附加到compact命令上,一旦设置,该注释可以会出现在3个位置:
1) mongod的log日志:attr.command.cursor.comment 列。
2) database profiler的输出结果的command.comment列。
3) currentOp 输出结果的command.comment列。
MongoDB 4.4 数据库分析器(Database Profiler)
https://www.cndba.cn/dave/article/107982
1.2 Compact 的阻塞问题
从4.4 版本开始,在WiredTiger 引擎上执行compact命令,仅block 如下元数据操作,不在block MongoDB CRUD 操作:
- db.collection.drop()
- db.collection.createIndex() 和db.collection.createIndexes()
- db.collection.dropIndex() 和db.collection.dropIndexes()
在4.4 版本之前,compact 命令在压缩时会block 数据库上的所有操作,包括CRUD操作,因为建议在维护窗口内执行compact命令,而从4.4 开始,可以在任意时间执行。
可以通过mongod的日志文件或者在mongo shell中执行 db.currentOp() 方法来查看compact的进程
1.3 Compact 异常中断处理
如果在compact 操作执行完成之前通过db.killOp()方法或者重启mongod 来终端了compact操作,那么需要关注以下事项:
- 如果启用了journaling,那么数据会依然有效并且可用,不用关心compact 操作的状态,可能仅仅需要手工重建一下相关索引。
- 如果没有启用journaling,并且在compact 操作进行时终端了mongod或者compact命令,那么无法保证处于有效状态。
- 不管是以上的哪一种情况,集合中的大部分空闲空间都将变成不可用状态,因此需要重新执行compact命令来完成压缩,从而重用这些空闲空间。
MongoDB 4.4 中 journal 和 oplog 日志 说明
https://www.cndba.cn/dave/article/107979
1.4 Compact 的磁盘空间
可以通过在compact 之前和之后分别执行collStats命令来查看集合占用的存储空间。
MongoDB 查看 数据库 和 集合 的 大小
https://www.cndba.cn/dave/article/107983
在WiredTiger 引擎中,compact 会尝试减少集合中data和 indexes 占用的存储空间,并释放不需要的磁盘空间给操作系统。当删除了集合中的大量数据后,执行该命令会效果更明显。
1.5 副本集中执行compact命令
在副本集的主库执行Compact命令不会同步到从库,因此需要分别在副本集的每个成员上分别执行。副本集的从库也可以执行compact命令,并且不需要指定force 选项。
从MongoDB 4.4.9和4.2.18 开始,在secondary 节点上执行compact命令时,从库只是变成不可用,不会进入RECOVERING 状态。在之前的版本则是进入RECOVERING 状态。当操作compact 结束,从节点恢复成SECONDARY 状态。
2 操作示例
2.1 主节点操作
查看集合信息:
shard1:PRIMARY> db.user.totalSize()
2109440
shard1:PRIMARY> db.user.totalIndexSize()
1572864
shard1:PRIMARY> db.user.stats()
{
"ns" : "cndba.user",
"size" : 1147670,
"count" : 33755,
"avgObjSize" : 34,
"storageSize" : 536576,
"freeStorageSize" : 0,
"capped" : false,
……
"nindexes" : 2,
"indexBuilds" : [ ],
"totalIndexSize" : 1572864,
"totalSize" : 2109440,
"indexSizes" : {
"_id_" : 954368,
"_id_hashed" : 618496
},
"scaleFactor" : 1,
……
执行compact,在副本集主库执行,这里提示必须加force 选项:
shard1:PRIMARY> db.runCommand({compact:"user"})
{
"ok" : 0,
"errmsg" : "will not run compact on an active replica set primary as this is a slow blocking operation. use force:true to force",
……
}
shard1:PRIMARY> db.runCommand({compact:"user",force:true})
{
"bytesFreed" : 0,
"ok" : 1,
……
查看压缩后的集合大小信息:
shard1:PRIMARY> db.user.totalSize()
2142208
shard1:PRIMARY> db.user.totalIndexSize()
1593344
shard1:PRIMARY> db.user.stats()
{
"ns" : "cndba.user",
"size" : 1147670,
"count" : 33755,
"avgObjSize" : 34,
"storageSize" : 548864,
"freeStorageSize" : 12288,
"capped" : false,
……
"nindexes" : 2,
"indexBuilds" : [ ],
"totalIndexSize" : 1593344,
"totalSize" : 2142208,
"indexSizes" : {
"_id_" : 962560,
"_id_hashed" : 630784
},
……
因为我们操作之前没有删除文档,所以这里看到文档的大小是有减少,但索引的大小是增加了的。
2.2 从节点操作
在从库操作之前,我们先删除文档的内容。 在进行操作。 因为是副本集环境,我们现在主库上进行删除操作。
shard1:PRIMARY> db.user.count()
33755
shard1:PRIMARY>
shard1:PRIMARY> db.user.count()
33755
shard1:PRIMARY> db.user.findOne()
{ "_id" : 44, "name" : "cndba" }
shard1:PRIMARY> db.user.remove({_id:{$gt:10}})
WriteResult({ "nRemoved" : 33753 })
shard1:PRIMARY> db.user.count()
2
shard1:PRIMARY>
shard1:PRIMARY> rs.printSlaveReplicationInfo()
WARNING: printSlaveReplicationInfo is deprecated and may be removed in the next major release. Please use printSecondaryReplicationInfo instead.
source: 172.31.185.120:27018
syncedTo: Tue May 10 2022 09:07:07 GMT+0800 (CST)
0 secs (0 hrs) behind the primary
source: 172.31.185.131:27018
syncedTo: Tue May 10 2022 09:07:07 GMT+0800 (CST)
0 secs (0 hrs) behind the primary
shard1:PRIMARY>
这里同步正常,我们到从库进行操作。
shard1:SECONDARY> rs.secondaryOk()
shard1:SECONDARY> db.user.count()
2
shard1:SECONDARY> db.user.totalSize()
3694592
shard1:SECONDARY> db.user.totalIndexSize()
2695168
shard1:SECONDARY> db.user.stats()
{
"ns" : "cndba.user",
"size" : 68,
"count" : 2,
"avgObjSize" : 34,
"storageSize" : 999424,
"freeStorageSize" : 954368,
"capped" : false,
……
"nindexes" : 2,
"indexBuilds" : [ ],
"totalIndexSize" : 2695168,
"totalSize" : 3694592,
"indexSizes" : {
"_id_" : 1544192,
"_id_hashed" : 1150976
},
"scaleFactor" : 1,
……
进行压缩: 在副本集的从库执行时,可以不加force 选项:
shard1:SECONDARY> db.runCommand({compact:"user"})
{
"bytesFreed" : 1114112,
"ok" : 1,
shard1:SECONDARY> db.runCommand({compact:"user",force:true})
查看集合信息:
shard1:SECONDARY> db.user.count()
2
shard1:SECONDARY> db.user.totalSize()
1560576
shard1:SECONDARY> db.user.totalIndexSize()
978944
shard1:SECONDARY> db.user.stats()
{
"ns" : "cndba.user",
"size" : 68,
"count" : 2,
"avgObjSize" : 34,
"storageSize" : 581632,
"freeStorageSize" : 536576,
"capped" : false,
……
"nindexes" : 2,
"indexBuilds" : [ ],
"totalIndexSize" : 978944,
"totalSize" : 1560576,
"indexSizes" : {
"_id_" : 942080,
"_id_hashed" : 36864
},
"scaleFactor" : 1,
"ok" : 1,
……
已经看到totalSize 和 totalIndexSize 都明显变小了。
查看节点状态:
shard1:SECONDARY> rs.status()
……
"stateStr" : "SECONDARY",
……
版权声明:本文为博主原创文章,未经博主允许不得转载。