生产环境MongoDB文档expireAt已过期未删除,本地无法复现该问题
导致该问题的可能原因如下:
- 生产环境未成功创建TTL索引
很多团队会在生产环境关闭Mongoose的autoIndex配置来避免启动时的性能开销,这会导致你在Schema中定义的TTL索引不会自动同步到生产库。可以在生产MongoDB中执行db.sessions.getIndexes()检查是否存在expireAt字段的升序索引,且expireAfterSeconds属性为0。 - 部分文档的
expireAt字段类型不符合要求
TTL索引仅对字段类型为Date的文档生效,如果你从JWT中取出的时间戳未正确转换为Date类型,或者格式错误导致Mongoose隐式类型转换失败,最终存储的是字符串/数字类型的时间值,对应文档就不会被TTL机制删除。可以排查未删除的文档中expireAt的实际存储类型,执行db.sessions.find({expireAt: {$not: {$type: "date"}}})就能筛出类型异常的文档。 - 数据库与应用服务器时间不同步
TTL索引判断过期时间以MongoDB所在服务器的系统时间为准,如果你的应用服务器生成expireAt时用的本地时间和数据库服务器时间不一致(比如数据库时间比应用慢几个小时),就会出现你认为已经过期的文档,在数据库侧还没到过期时间的情况。需要检查两边服务器的NTP时间同步配置。 - 生产库负载过高导致TTL删除线程滞后
MongoDB的TTL删除是后台单线程运行,默认每60秒执行一次。如果生产库的写入压力大、集合文档数量多,或者系统CPU/IO负载长期处于高位,TTL删除任务会被调度滞后,导致过期文档积压。如果过期后几小时仍未删除可排除该原因。 - 集合属性或集群配置异常
- 如果你的会话集合是capped固定大小集合,TTL索引会直接失效,因为capped集合不允许主动删除文档
- 如果生产用的是分片集群,需要确认所有分片都成功创建了TTL索引,避免部分分片的文档没有过期删除逻辑
- 确认数据库未关闭TTL功能,执行
db.adminCommand({getParameter: 1, ttlMonitorEnabled: 1})检查返回值是否为true
- MongoDB版本已知Bug
你使用的MongoDB 5.0.3属于早期迭代版本,存在多个TTL索引相关的已知故障,比如在特定写入场景下TTL线程会漏扫部分文档,可以考虑升级到最新的5.0稳定版修复该问题。
内容的提问来源于stack exchange,提问作者Soroush Hakami
相关产品推荐
相关产品推荐

