说明

针对搭建的容器集群进行一些分析,问题的表现是存储的空间过大(和单机Mongo对比)。内容牵扯的比较多,所以我就按处理问题的思路一步步写。

内容

针对相同的数据集

集群空间现状:

docker FFmpeg 切片服务 docker分片_linux

单机版现状:

docker FFmpeg 切片服务 docker分片_docker_02


把配置服务器,副本和仲裁都不算,单是两个分片加起来,数据量是 2.3G, 几乎是单机的2.4倍。

1 Compact

关于Compact可以参考这篇文章,因为以前也发生过,所以我想是否是因为Balance后开启导致的物理空间不释放。

Mongos不可以执行Compact操作,要到对应分片的主节点操作

docker exec -it shardsvr10 bash
# 估计一下执行Compact会带来的收益
db.test.stats().wiredTiger["block-manager"]["file bytes available for reuse"]
377339904(大约300M,其实可以stats(1024*1024)这样直接就是M了 )
# 执行compact, 对应的集合会阻塞访问
db.runCommand({compact:'test', force:true})

释放只会,shard1变为1.2G,所以总体上数据是2G,是单机版的两倍

docker FFmpeg 切片服务 docker分片_数据_03


结论:Compact不是导致集群存储空间大的主要原因

2 查看数据库大小

之前分别打开过集群和单机各个分片的数据库描述,结论是关于核心数据的表大小,两边也是一致的

rs_shardsvr1:PRIMARY> db.test.stats()
{
	"ns" : "test.test",
	"size" : 637257701,
	"count" : 674086,
	"avgObjSize" : 945,
	"storageSize" : 619929600,
	"freeStorageSize" : 377339904,
	"capped" : false,

然后我用show dbs,发现集群的local特别大而单机版的local为0:

shard1的

rs_shardsvr1:PRIMARY> show dbs;
admin   0.000GB
config  0.001GB
local   0.553GB
test    0.608GB

单机的

> show dbs;
admin   0.000GB
config  0.000GB
local   0.000GB
test    0.442GB

其中单机teset比较小的原因我猜是因为启动时并未使用配置文件,关于test库的一些相关大小没有统计,而是归于共享的部分。


tips

如果没有挂载配置,那么mongod会使用默认的配置启动/etc/mongod.conf.orig,长这个样子

# mongod.conf

# for documentation of all options, see:
#   http://docs.mongodb.org/manual/reference/configuration-options/

# Where and how to store data.
storage:
  dbPath: /var/lib/mongodb
  journal:
    enabled: true
#  engine:
#  wiredTiger:
# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /var/log/mongodb/mongod.log

# network interfaces
net:
  port: 27017
  bindIp: 127.0.0.1
# how the process runs
processManagement:
  timeZoneInfo: /usr/share/zoneinfo
#security:
#operationProfiling:
#replication:
#sharding:
## Enterprise-Only Options:
#auditLog:
#snmp:

而本次集群启动时挂载(… mongo -f /etc/mongod.conf)的配置长这样:

# Where and how to store data.
storage:
  dbPath: /home/mongod/db #分片数据库路径
  journal:
    enabled: true
  directoryPerDB: true
#  engine:
#  mmapv1:
#  wiredTiger:
# where to write logging data.
systemLog:
  destination: file
  logAppend: true
  path: /home/mongod/log/mongod.log # 分片日志
 
# network interfaces
net:
  bindIpAll: true
 
# how the process runs
#processManagement:
#  fork: true
# set auth?
setParameter:
  enableLocalhostAuthBypass: false
#operationProfiling:
 
replication:
  replSetName: rs_shardsvr1 #分片服务名称
 
sharding: 
   clusterRole: shardsvr

其中directoryPerDB参数会按数据库区分,其中一个replication参数后续会讨论到。


言归正传,发现集群的shard,local库占据了几乎和数据一样大的空间,查看里面的内容如下

rs_shardsvr1:PRIMARY> use local
switched to db local
rs_shardsvr1:PRIMARY> show collections;
oplog.rs
replset.election
replset.initialSyncId
replset.minvalid
replset.oplogTruncateAfterPoint
startup_log
system.replset
system.rollback.id
system.tenantMigration.oplogView
system.views

可以看到,oplog相关的表特别大, 存储接近565M,基本上和dbs的空间对上了(0.553G),有点小差距不知道是为啥。

rs_shardsvr1:PRIMARY> db.oplog.rs.dataSize()
1631615139
rs_shardsvr1:PRIMARY> db.oplog.rs.storageSize()
593305600

所以问题出在oplog上,关于这个可以参考

参考1参考2,里面有提到 oplog是Replica set模式中的核心部分,通过它来同步不同服务器之间的数据,以日志的形式保存数据,默认是采用空闲空间的5%来存储,也就是说,如果你又100G的空间,他默认会划分5G来存储这个部分的日志空间,不过这个参数是可以直接设置的。如果超过你直接设置的百分比,他会反复使用,不会新增空间。参考3如何去设置oplog

我查看了一下当前机器分配的大小(26G), 目前空闲的空间大约515G,差不多。

rs_shardsvr1:PRIMARY>  db.getReplicationInfo()
{
	"logSizeMB" : 26518.6025390625,
	"usedMB" : 1556.01,
	"timeDiff" : 71040,
	"timeDiffHours" : 19.73,
	"tFirst" : "Tue Jun 28 2022 07:36:24 GMT+0000 (UTC)",
	"tLast" : "Wed Jun 29 2022 03:20:24 GMT+0000 (UTC)",
	"now" : "Wed Jun 29 2022 03:20:26 GMT+0000 (UTC)"
}
rs_shardsvr1:PRIMARY>  db.printReplicationInfo()
configured oplog size:   26518.6025390625MB
log length start to end: 71080secs (19.74hrs)
oplog first event time:  Tue Jun 28 2022 07:36:24 GMT+0000 (UTC)
oplog last event time:   Wed Jun 29 2022 03:21:04 GMT+0000 (UTC)
now:                     Wed Jun 29 2022 03:21:09 GMT+0000 (UTC)

参考3其中有提到,在配置文件中指定大小(也就是启动时指定的那个文件)

#配置文件中指定oplog大小
replication:
  oplogSizeMB: 4096
  replSetName: repset

当然,后续的实验我计划会给容器限制内存、磁盘,所以不设置没关系。但是oplog不能太小,否则会出问题。

结论:oplog解释了翻倍的原因,而且随着业务增长,不会出现一直翻倍的情况。

3 数据整体还是比数据大一倍

其实可以看到,数据库文件中,journal的体积和数据文件(440M)差不多大小

docker FFmpeg 切片服务 docker分片_bash_04

journal文件存储的是对数据库文件(dbname.ns、dbname.<#>系列文件)的修改日志,包括写操作和创建文件操作。对数据库文件的写操作会记录一个WriteIntent,创建数据库文件会记录一个DurOp。WriteIntent记录了写操作的指针和长度,可以定位到修改的数据文件的位置和长度。DurOp由一个操作码来确定是什么操作,不同的操作,日志的格式不一样。每个WriteIntent或者DurOp都会形成一个JEntry。

简单来说,journal有两个作用,一方面用于数据故障保护,另一方面似乎是可以驻留内存中加速的。

总体上疑问解开了