暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Mongodb踩坑经历分享

IT那活儿 2022-09-20
339

点击上方“IT那活儿”公众号,关注后了解更多内容,不管IT什么活儿,干就完了!!!


  

背景:

主库dbpath目录使用率96%,剩余空间只有40GB左右,且无法进行磁盘扩容。

经查,其中一个集合占用空间600GB左右,字段timestamp上有TTL索引(Mongodb的一种索引属性,创建在单列时间字段上,可设置数据过期时间,超过时间随即自动删除数据),保留期限31天,经与业务侧确认,可修改数据保留期限为7天。
闲言少叙,直入主题!
数据库架构:复制集1主+2从架构。
修改前索引属性:
PRIMARY:AKTM> db.list***ord.getIndexes();
[
{
"v" : 2,
"key" :{
"timestamp": 1
},
"name" :"timestamp_1",
"background": true,
"ns" :"AKTM.list***ord",
"expireAfterSeconds": NumberLong(2678400)
},
{
"v" : 2,
"key" :{
"_id": 1
},
"name" :"_id_",
"ns" :"AKTM.list***ord"
}
]

修改TTL索引属性无需重建索引,修改命令如下:
db.runCommand( { collMod:"list***ord",
index: { keyPattern: { timestamp:1 },
expireAfterSeconds: 604800
}
})

修改后索引属性:
PRIMARY:AKTM> db.list***ord.getIndexes();
[
{
"v" : 2,
"key" :{
"timestamp": 1
},
"name" :"timestamp_1",
"background": true,
"ns" :"AKTM.list***ord",
"expireAfterSeconds": NumberLong(604800)
},
{
"v" : 2,
"key" :{
"_id": 1
},
"name" :"_id_",
"ns" :"AKTM.list***ord"
}
]

将数据从31天清理到7天,大约会释放400GB左右的空间,但是mongodb机制跟oracle一样,delete数据不会释放给OS(或者表空间),而需要进行compact操作(类似于oracle的高水位回收)后才会释放空间给OS。
compact操作会加库级锁,所以该操作一般在从库实施,实施过程中从库状态会从secondary转换为recovering,此时不再接收oplog(类似于oracle的归档日志,但不是OS文件,而是local库中的一个固定大小的集合,重复写入,达到规定大小就删除最老的记录),compact完成后,重新开始接收oplog然后继续同步。
本次踩坑就发生在compact操作后。
大集合包含20亿+的文档数,TTL删除大概会持续4-5天,修改TTL属性两天后,眼看/data磁盘目录使用率不断上升,所以决定分两次执行compact,先释放一部分空间给其他集合使用。
在一月黑风高的夜晚,哥将compact命令(db.runCommand({compact:"lis***ord"}))放到从库后台就找周公去了(按之前的经验,会耗时2-3小时),第二天一大早起来一看,傻眼了。
主从同步延迟越来越大,后台日志出现如下信息:
2020-07-01T07:17:49.265+0800 IREPL     [replication-147] We are too stale to use10.***.***.83:27017 as a sync source. Blacklisting this sync sourcebecause our last fetched timestamp: Timestamp(1593529482, 5082) isbefore their earliest timestamp: Timestamp(1593553525, 1720) for 1minuntil: 2020-07-01T07:18:49.265+0800
2020-07-01T07:17:49.266+0800 IREPL     [replication-147] sync source candidate: 10.**.***.138:27017
2020-07-01T07:17:49.268+0800 IREPL     [replication-147] We are too stale to use10.25.151.138:27017 as a sync source. Blacklisting this sync sourcebecause our last fetched timestamp: Timestamp(1593529482, 5082) isbefore their earliest timestamp: Timestamp(1593553515, 601) for 1minuntil: 2020-07-01T07:18:49.268+0800

从上面的日志可以看出,oplog丢了几个小时。只能通过重新初始化从库解决了。分析原因,我们发现oplog只能保存不到1.5小时,而compact操作需要耗时2小时以上,所以丢失oplog是必然。
repl1:SECONDARY>rs.printReplicationInfo();
configured oplog size: 10240MB
log length start to end: 4704secs(1.31hrs)
oplog first event time: Wed Jul01 2020 06:30:31 GMT+0800 (CST)
oplog last event time: Wed Jul01 2020 07:48:55 GMT+0800 (CST)
now: Wed Jul01 2020 07:48:56 GMT+0800 (CST)

根据长期运维此数据库的经验,此数据库的oplog至少会保留5小时以上,为什么现在只能保留1小时呢?恍然大悟,此时正在进行TTL删除数据,产生大量的oplog。在oracle数据库中,如果大量的DML操作产生大量归档日志,可从alert日志上看到频繁的redo切换,在mongodb中,不会有任何提示,只能通过rs.printReplicationInfo()检查oplog保留时间。

正确的操作方式应该是:

  • 因为主库空间不足,所以应该在另外一个从节点进行oplog扩容db.adminCommand({replSetResizeOplog:1, size: 40960});
  • 操作前将操作节点的同步源指向扩容了oplog的节点rs.syncFrom(“10.2***.**.138:27017”);
  • 执行compact操作,并随时注意观察oplog保留时间,若oplog大小仍然不够,则继续扩容。



本文作者:刘运彬(上海新炬王翦团队)

本文来源:“IT那活儿”公众号

文章转载自IT那活儿,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论