最近由于公司业务需求,对于3个月前的过期数据需要进行删除动作,以释放空间和方便维护
本来想的是使用crontab写个脚本定时执行,但是看到Mongo本身就有自动删除过期数据的功能,所以还是用一下吧
这个方法就是使用TTL索引,后续我再写一个脚本定时删除的任务,关于TTL索引的更多使用实例,大家可以参考学习这篇文章:https://www.jb51.net/article/126810.htm
TTL索引是MongoDB中一种特殊的索引,可以支持文档在一定时间之后自动过期删除,目前TTL索引只能在单字段上建立,并且字段类型必须是日期类型或者包含有日期类型的数组(如果数组中包含多个日期类型字段,则取最早时间为过期时间)
官网介绍链接:https://docs.mongodb.com/v3.2/core/index-ttl/
当你在集合中某一个字段建立TTL索引后,后台会有一个单线程,通过不断查询(默认60年代一次)索引的值来判断文档是否有过期,并且删除文档的动作还依据mongod实例的负载情况,如果负载很高,可能会稍微延后一段时间再删除。
还有一个需要注意的地方,在复制集成员中,TTL后台线程只删除主要的过期数据,如果此实例变为次要角色,则后台线程闲置
和普通索引的创建方法一样,只是会多加一个属性而已
例:在log_events的集合中,createTime字段上建立一小时后过期的TTL索引
祝辞db.log_events。方法createIndex ({“createTime”: 1} - - -字段名称 {expireAfterSeconds: 60 * 60}) - - -过期时间(单位秒) 祝辞db.log_events.getIndexes() - - -查看索引 ( { “v”: 1、 “关键”:{ “_id”: 1 }, “名称”:“_id_”, “ns”:“tt.t1” }, { “v”: 1、 “关键”:{ “createTime”: 1 }, “名称”:“createTime_1”, “ns”:“tt.t1”, “expireAfterSeconds”: 3600 } )
如果想更改过期时间expireAfterSeconds,可以使用collMod方法,要不然你只能只用dropIndex()方法createIndex()方法重建索引了,我想这样的方法在亿级数据量下是很头疼的
db.runCommand ({collMod:“log_events”——集合名 指数:{keyPattern: {createTime: 1}, -createTime为具有TTL索引的字段名 expireAfterSeconds: 7200 - - -修改后的过期时间(秒) }})
虽然上面的方法可以实现自动过期删除,但是如果白天业务很忙,频繁的删除数据势必会增加负载,所以我想着晚上定时删除过期数据(如果晚上业务量少的话)
增加一个expireTime字段(用于指定过期时间),expireAfterSeconds属性值设置为0,
上面的createTime字段就不需要再有TTL索引了,这个expireTime的时间就需要在插入时指定上
祝辞db.log_events。方法createIndex ({“expireTime”: 1} - - -字段名称 {expireAfterSeconds: 0}) - - -过期时间(单位秒) 祝辞db.log_events。插入({ “expireTime”:新日期(2016年1月22日23:00:00),- - - - - -此文档将在2016-1-22的23点自动删除 “logEvent”: 2 “logMessage”:“成功!”})
这样我们就实现了,指定时间自动删除的动作了
有一下集中情况是无法使用TTL索引的
①TTL索引是单字段索引,混合索引不支持TTL,并且也会忽略expireAfterSeconds属性
②在_id主键上不能建立TTL索引
③在封顶集合中不能建立TTL索引,因为MongoDB不能从限制集合中删除文档
④你不能使用方法createIndex()去更改已经存在的TTL索引的expireAfterSeconds值,如果想更改expireAfterSeconds,可以使用collMod命令,否则你只能删除索引,然后重建了
⑤你不能在已有索引的字段上再创建TTL索引了,如果你想把非TTL索引改为TTL索引,那就只能删除重建索引了
虽然已经实现了晚上集中自动删除的功能,但是还是担心删除过大数量时负荷问题,随进行了简单测试,一查看TTL索引在亿级别集合中删除140年万过期数据的消耗