MongoDB自动删除过期数据的方法(TTL索引)
前序:
最近由于公司业务需求,对于3个月前的过期数据需要进行删除动作,以释放空间和方便维护
本来想的是使用crontab写个脚本定时执行,但是看到mongo本身就有自动删除过期数据的功能,所以还是用一下吧
这个方法就是使用ttl索引,后续我再写一个脚本定时删除的任务,关于ttl索引的更多使用实例,大家可以参考学习这篇文章:
介绍:
ttl索引是mongodb中一种特殊的索引, 可以支持文档在一定时间之后自动过期删除,目前ttl索引只能在单字段上建立,并且字段类型必须是date类型或者包含有date类型的数组(如果数组中包含多个date类型字段,则取最早时间为过期时间)
官网介绍链接:https://docs.mongodb.com/v3.2/core/index-ttl/
机制:
当你在集合中某一个字段建立ttl索引后,后台会有一个单线程,通过不断查询(默认60s一次)索引的值来判断document是否有过期,并且删除文档的动作还依据mongod实例的负载情况,如果负载很高,可能会稍微延后一段时间再删除。
还有一个需要注意的地方,在复制集成员中,ttl后台线程只删除primary的过期数据,如果此实例变为secondary角色,则后台线程闲置
创建ttl索引方法:
和普通索引的创建方法一样,只是会多加一个属性而已
例:在log_events的集合中,createtime 字段上建立一小时后过期的ttl索引
>db.log_events.createindex( { "createtime": 1 }, ---字段名称 { expireafterseconds: 60*60 } ) ---过期时间(单位秒) >db.log_events.getindexes() ---查看索引 [ { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "tt.t1" }, { "v" : 1, "key" : { "createtime" : 1 }, "name" : "createtime_1", "ns" : "tt.t1", "expireafterseconds" : 3600 } ]
修改ttl索引的expireafterseconds属性值:
注:如果想更改过期时间expireafterseconds,可以使用collmod方法,要不然你只能只用dropindex(),createindex()方法重建索引了,我想这样的方法在亿级数据量下是很头疼的
db.runcommand( { collmod: "log_events", ---集合名 index: { keypattern: { createtime: 1 }, ---createtime为具有ttl索引的字段名 expireafterseconds: 7200 ---修改后的过期时间(秒) }})
虽然上面的方法可以实现自动过期删除,但是如果白天业务很忙,频繁的删除数据势必会增加负载,所以我想着晚上定时删除过期数据(如果晚上业务量少的话)
方法如下:
增加一个expiretime字段(用于指定过期时间),expireafterseconds属性值设置为0,
注:上面的createtime字段就不需要再有ttl索引了,这个expiretime的时间就需要在插入时指定上
>db.log_events.createindex( { "expiretime": 1 }, ---字段名称 { expireafterseconds: 0 } ) ---过期时间(单位秒) >db.log_events.insert( { "expiretime": new date('jan 22, 2016 23:00:00'), ---此文档将在2016-1-22的23点自动删除 "logevent": 2, "logmessage": "success!"} )
这样我们就实现了,指定时间自动删除的动作了
限制条件:
有一下集中情况是无法使用ttl索引的
①ttl索引是单字段索引,混合索引不支持ttl,并且也会忽略expireafterseconds属性
②在_id 主键上不能建立ttl索引
③在capped collection中不能建立ttl索引,因为mongodb不能从capped collection中删除文档
④你不能使用createindex()去更改已经存在的ttl索引的expireafterseconds值,如果想更改expireafterseconds,可以使用collmod命令,否则你只能删除索引,然后重建了
⑤你不能在已有索引的字段上再创建ttl索引了,如果你想把非ttl索引改为ttl索引,那就只能删除重建索引了
验证:
虽然已经实现了晚上集中自动删除的功能,但是还是担心删除过大数量时负荷问题,随进行了简单测试,一查看ttl索引在亿级别集合中删除140万过期数据的消耗
测试配置:
os:vm虚拟机
cpu: 4
内存:8
集合数据量:
> db.t1.count()
104273617
因为我制造测试数据时,_id是顺序增加的,所以我直接查看_id=1500000的那笔数据的createtime,然后自己计算一下此createtime和当前时间的时间差,随后根据这个时间差来更改expireafterseconds的值,以让这150万数据5分钟后过期并删除。
在修改完expireafterseconds后,就严密延时“ vmstat 1 ” 命令的输出数据;
我的测试结果:
删除操作整个过程在90秒左右完成;
cpu最高占用90%,平均在50%
内存占用3g
这个也是特别准确的模拟情况,只是粗略的了解一下ttl索引的资源消耗,以决定是不是需要这样的方式来实现删除过期数据
监控vmstat的截图:
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。