前言
本文主要讲述公司项目从副本集迁移到分片集群遇到的changeStream延时问题的解决方案,并经过反复验证。供广大的mongoDB用户参考。
公司平台主要是为物联网服务的iot平台,接入项目又处于公司所有项目的最前段,经过讨论,决定尽快迁移分片集群。
由于项目中会用到模糊查询,而且量非常大,负载均衡的考虑,接入团队决定使用changeStream将mongoDB数据同步到ES查询(mongoDB的全文索引其实也比较擅长,这个下一步再做优化,减少ES机器投入)
项目迁移到分片集群后,平均查询时间提升了2.5倍,机器负载也降低了一半,但在开启change stream的时候,发现延时太高,每次基本都是10S以上,项目对这个延时时间最多接受是2S。
经过研究,官方给出的结论是:
Without additional information, I'd speculate that the lack of activity("clusters which don't have a lot of pressure at all") is actuallythe problem. In order to make some guarantees in sharded environments, themongos needs to hear back from all of the shards. If the shards don't havewrite activity from clients then it'll be the periodic no-op that will triggerthe response. That no-op happens every 10 seconds when there is no write load。
大概意思是:由于业务更新写入不是很频繁,所以shard节点不会实时有变更数据,比较闲的时候mongos会等下一次no-op,这个是10s一次,来让订阅得以持续进行。这样等待时间就比较长了。
所以总结了以下3种方案给大家选择:
1.periodicNoopIntervalSecs参数:
注意:这个参数需要重启实例,并且需要修改每个shard副本成员和config server的这个参数。
- 默认值:
- 修改方式:
在参数文件中添加:
代码语言:javascript复制setParameter=periodicNoopIntervalSecs=1
yaml格式:setParameter:
periodicNoopIntervalSecs: 1
- 修改后查看:
上面看到,我将periodicNoopIntervalSecs从10S修改到了1S,并且经过反复测试,确实在mongos上能1S左右收到订阅信息。
2.定时在每个shard的primary写入数据,这个数据可以是空字符串,也可以是数字,字符,个人建议写入的字符尽量简短,mongos订阅的返回时间取决于,每次在每个shard的写入时间,可以是ms级别的。
3.直接在每个shard上订阅,最终将结果聚合,这个完全是副本集的方式。正常都是ms级的返回。
总结
changeStream取代了老版本中需要不断tail oplog获取变更记录,对开发者带来了极大的便利。但在分片集群中,由于官方默认等待shard NO-OP时间为10S,导致订阅同步延时很大,且官方很少有提及这个优化方案。
- 第一种方案,参数修改带来的负面影响,还有待考究。
- 第二种方案,可以直接从mongos订阅,并且返回时间可以通过不断往shard写入数据的时间来定,但需要考虑频繁写入shard带来的额外资源开销。
- 第三种方案,是用原生态的副本集的订阅方式,管理比较复杂,要考虑副本集切换或者重启后,token的重置问题。
关于作者:
陈亮亮 MongoDB中文社区南京分会主席,远景能源集团数据库架构师;曾在UCloud负责UDB MongoDB的研发和运维工作,在数据库架构和调优方面有丰富的经验。