目录

一、前序

二、TTL索引介绍

三、TTL索引生效机制

四、创建TTL索引

五、修改TTL索引的expireAfterSeconds属性值

六、动态指定TTL索引的过期时间

七、TTL索引使用限制条件

八、验证TTL索引功能


一、前序

        由于公司业务需求,对于1个月前的过期数据需要进行删除,以释放空间和方便维护。
        本来想使用crontab写个脚本定时执行删除操作,但是看到Mongo本身就有自动删除过期数据的功能,就是使用TTL索引。决定使用TTL自动索引,这样就不用再写一个脚本以完成定时删除的任务。


二、TTL索引介绍

       TTL索引是MongoDB中一种特殊的索引, 可以支持文档在一定时间之后自动过期删除。目前,TTL索引只能在单字段上建立,并且字段类型必须是date类型或者包含有date类型的数组(如果数组中包含多个date类型字段,则取最早时间为过期时间)。
        官网介绍链接:https://docs.mongodb.com/v3.2/core/index-ttl/


三、TTL索引生效机制

        当你在集合中某一个字段建立TTL索引后,后台会有一个单线程,通过不断查询(默认60s一次)索引的值来判断document是否有过期,并且删除文档的动作还依据mongod实例的负载情况,如果负载很高,可能会稍微延后一段时间再删除。
        还有一个需要注意的地方:在复制集成员中,TTL后台线程只删除primary实例的过期数据;如果此实例变为secondary角色,则后台线程闲置。
 

四、创建TTL索引

        和普通索引的创建方法一样,只是会多加一个expireAfterSeconds属性而已。
例:在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   ---修改后的过期时间(秒)
}})

虽然上面的方法可以实现自动过期删除,但是频繁删除数据势必会增加负载,所以必须在业务量少的时段,定时删除过期数据和修改超时属性值。

六、动态指定TTL索引的过期时间

增加一个expireTime字段(用于指定过期时间),expireAfterSeconds属性值设置为0。在插入文档时,需要指定expireTime的值。这样,上面的createTime字段就不需要再有TTL索引了。

>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索引是单字段索引,混合索引不支持TTL,并且也会忽略expireAfterSeconds属性。
② 在_id 主键上不能建立TTL索引。
③ 在capped collection中不能建立TTL索引,因为MongoDB不能从capped collection中删除文档。
④ 不能使用createIndex()去更改已经存在的TTL索引的expireAfterSeconds值。如果想更改expireAfterSeconds,可以使用collMod命令;否则,只能删除索引,然后重建。
⑤ 不能在已有索引的字段上再创建TTL索引了。如果想把非TTL索引改为TTL索引,那就只能先删除非TTL索引,然后新建TTL索引。

八、验证TTL索引功能

虽然已经实现了“动态指定过期时间自动删除数据”的功能,但是还是担心大量删除过期数据可能导致mongo服务器负荷问题。于是,进行了简单测试,查看TTL索引在亿级别集合中删除140万过期数据的消耗。
测试机器的配置:
     OS:Vm虚拟机
     CPU: 4
     内存:8
集合数据量:

> db.t1.count()

共有104675629条文档记录。
在制造测试数据时指定_id是顺序增加的,验证步骤:

第1步,直接查看_id=1500000那条数据的createTime;

第2步,计算一下此createTime和当前时间的时间差;

第3步:根据这个时间差,更改expireAfterSeconds的值,以让这150万数据在5分钟后过期;

第4步:在修改完expireAfterSeconds后,等待“ vmstat 1 ” 命令的输出数据。

我的测试结果:
整个删除操作过程在90秒左右完成;
CPU最高占用90%,平均在50%;
内存占用3G。
这个不是特别准确的线上测试,只是粗略了解一下TTL索引的资源消耗,以决定是不是需要使用这种方式来实现删除过期数据
          监控vmstat的截图:

 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐