本文为2020年MongoDB应用案例与解决方案征集活动最佳创新案例:MongoDB在圆通速递的应用,作者徐靖。
最近双11当天临近下班时间点,出现应用定时JOB跑批任务卡死,导致数据没有及时计算出来,影响一次报表数据展示,这个功能跑了几个月基本上没有异常,双11业务增长几倍,数据量稍微有点大。主要包括如下内容:
MongoDB集群架构以及读写分离策略
【集群架构】
MongoDB集群是基于3.6版本,其中底层是三个副本集的PSS架构+三成员的config+3个mongos组成.副本集都是设置tag,用于跑批程序到指定从节点计算数据,降低对主库的影响。其中一个副本集的当前配置如下:
【读写分离策略】
应用端15分钟多线程聚合一次数据,每次按照部门聚合,但是分片规则是基于单号hashed来做,每次40个线程同时跑(几千部门,数据分布不均衡),执行时间几十秒可以运算完成,但cpu瞬间能够达到60%-80%波动。为了降低对主库影响,读写分离策略经过三次变化:
第一阶段, 直接主库运行,但对主库有性能问题
第二阶段,采readPreference=secondaryPreferred&maxStalenessSeconds=120参数,但MongoDB会将聚合任务下发到备库进行执行任务(下发到任一满足条件从库,而不是所有从库,由于多线程执行,所以会出现下发所有从库执行),由于存在从库与主库共用机器的情况,cpu负载还是很高,对主库性能影响降低。
第三阶段,为了解决这个,双11扩容3个物理机器,每个机器跑独立实例,同时对副本集配置tag,将聚合任务分发特定tag实例,从而解决主库cpu高问题,同时能够控制聚合任务分发。MongoDB对外URL连接串如下:
mongodb://username:password@mongodb1.db.com:31051,mongodb2.db.com:31051,mongodb3.db.com:31051/exp?readPreference=secondaryPreferred&maxStalenessSeconds=120&readPreferenceTags=usagef:reportfirst&readPreferenceTags=usages:reportsecond&readPreferenceTags=&retryWrites=true
应用批处理异常时应用与数据库表现
【应用跑批异常】
根据研发反馈,11.11 17.11 跑批程序卡死(提前几分钟跑,其实是慢并没有真的卡死),于是手动kill应用程序,大约几分钟后,程序跑批成功,但是17.15跑批结果是丢失,主要在客户端用于生成曲线图,相当于少一个坐标点数据(影响不是非常大,但毕竟出现小异常)
【数据库端表现】
☐ 数据库主从延迟(副本集中2个从库都有延迟,其中有1个延迟在120s,另外一个超过)
【异常分片监控信息】
☐ mongod实例日志
备注:根据监控来看,tags等于reportfrist节点,在17.10延迟超过120s,所以跑批程序根据配置tag以及延迟时间120s自动切换reportsecond节点,但reportsecond也存在延迟,至少有20s到60s之间,出现应用跑批卡死了,查看SQL执行时间来看,正常执行100ms左右,变成24s,还有更慢的SQL,甚至超过几分钟的。所以应用端表现是卡死,因为后端执行慢。但SQL主要耗时在global锁等待上,而不是正在MongoDB执行时间上,这个是最主要原因(先分析表面的东西),从表现来看,就是延迟导致执行变慢.,17点之前正常的。存在如下问题:
1、SQL执行被阻塞
【图一是tag等于frist节点日志】
【图二是tag等于second节点日志因为切换到这个节点】
2、备库拉起oplog日志一直失败且一直尝试切换数据源
【如下是tag等frist节点日志,一直拉取oplogs超时,因为second节点压力大,进行跑批操作,没有响应备库拉取oplog】
☐ mongod主库慢日志分析
备注:正常节点与异常节点,SQL执行时间基本上差不多,主要是执行次数不一样多。
【异常节点】
【正常节点】
【数据库问题分析】
☐ 主从为什么会延迟
根据官方解释主要包括如下:
备注:因为集群分片集合都是基hashed,数据很均衡,没有出现分片节点数据差别很大的情况,所以目前主从延迟根因很难判断,主从延迟只是双11当天出现过,其他时间没有出现过。因为双11当天有限流,下午开始取消限流,可能导致数据库一瞬间波动造成的延迟(出现偶发的情况)
☐ SQL执行为什么会等待锁,被阻塞
因为我们的聚合SQL对时效不是非常敏感,因为是多线程执行聚合,每一个线程按照部门取聚合的,有几百到几千部门,只是关注总时间,总执行时间在1分钟内(有的SQL都是毫秒级别),双11执行异常,分析具体慢SQL才发现很多主要等待在获取锁上,所以出现异常。查询官方文档以及mongodb官方博客,mongodb 4.0之前版本备库写会阻塞读,平时没有延迟所以备库阻塞读的时间非常短。
《https://www.mongodb.com/blog/post/secondary-reads-mongodb-40》
《https://mongoing.com/archives/13473》
☐ 备库拉取oplog失败
4.4版本之前都是备库主动取获取日志,如果主库忙、网络出现问题以及磁盘等问题,会导致拉取失败的,从而导致从库不能及时应用日志,如果开始级联复制(默认开启),那么此时备库可能从其他备库拉取日志,如果数据源也延迟,那么拉取日志备库延迟概率与时间会更多,我们此次遇到延迟,就是级联复制影响,从失败里面看虽然一直尝试切换数据源,最终还是选择的都是备库,根本没有切换到其他数据源,是否切换数据源(存在一些判断条件),如果主备都满足候选数据源时,其中有一个参数maxSyncSourceLagSecs来触发再次选择同步原,这个值是30s,从监控来看17.20分,同步源本身延迟超过30s,最终重新将同步源到主库,很快恢复延迟。4.4版本中主动推动oplog。相对从库主动拉取能够提高效率。
如何规避与解决这个问题
☐ 读写分离问题
4.0之前版本如果主库压力不大,不建议读写分离,因为写会阻塞读,除非业务对响应时间不是非常关注以及读取历史数据(接受一定时间延迟),本次版本是3.6集群,我们是跑批业务且平时延迟很小,所以目前来看,读写还是可以接受。考虑明年升级到4.4版本。
☐ 备库延迟问题
1. 做好主从延迟监控告警,及时发现潜在的性能问题,比如磁盘问题、主库性能问题等
2. 如果开启级联复制(默认开启),级联数据源压力比较大,那么也会导致拉取日志失败从而造成延迟,根据实际情况是否调整级联复制.
3. 升级到4.4版本,开始支持stream replication,变成主动推oplog,那么复制效率会提升。
作者:徐靖
物流快递行业数据库运维与技术研究,主要是Oracle,MongoDB,Mysql技术。
为了挖掘MongoDB更多应用场景和案例实践,向用户和行业输送有启发、应用价值的思路和经验,MongoDB中文社区携手上海锦木和Tapdata于2020年12月开展MongoDB优秀解决方案暨应用案例征集活动。我们从创新性和应用价值的维度进行评选,评出本次案例征集活动最佳创新案例和优秀应用案例。
本文分享自 Mongoing中文社区 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!