10 月 23 - 25 日,QCon 上海站即将召开,现在购票,享9折优惠 了解详情
写点什么

这 300 条数据变更,引发了十亿级核心集群的罢工惨案!

  • 2021-06-30
  • 本文字数:2406 字

    阅读完需:约 8 分钟

这300条数据变更,引发了十亿级核心集群的罢工惨案!

线上某核心 mongodb 集群数据量很少,单表数据量十亿级,但是该集群比较核心,影响公司收入流水。本文通过分享本次踩坑来分享整个故障经过,该故障为一次经典的 mongodb 分片 sharding 集群踩坑故障,包括变更通知不到位、部署架构不到位、变更考虑不仔细等。

一、问题背景

某核心 mongodb 历史集群(入职前就有的一个集群),在对现在所有 mongodb 集群进行风险梳理过程中,发现该集群存在一些潜在的集群抖动风险,该集群架构及流量时延曲线如下:





如上图所示,该分片集群由 3 个分片组成,集群读写流量很低,峰值 QPS 约 4-6W/s,平均时延 1ms,每个分片采用 mongodb 复制集架构实现高可用。通过巡检发现该集群存在如下几个问题:


  • 该集群只包含两个用户库,userbucket 库和 feeds_content 库,两个库中只有 feeds_xxxxxxx.collection1 启用了分片功能;第一个 userbucket 库存储集群路由信息,第二个 feeds_xxxxxxx 库存储约十亿数据信息;

  • 由于该集群主要是读多写少集群,读流量都是读取 feeds_xxxxxxx 库中的数据,并且客户端做了读写分离,所以几乎大部分读流量都在分片 1。分片 2 和分片 3 只有少量数据。


库表信息如下表所示:


库名

表名

功能说明

userbucket

whitexxx/expxxx

用户路由信息表,约300条数据。用户访问feeds_xxxxxxx库前必须先获取该表得用户路由数据




feeds_xxxxxxx

feeds_xxx_pool

十亿级数据,未启用分片

hardware_xxx_cost

未启用分片,少量数据

news_xxx_profile

数亿数据,未启用分片

resource_xxx_info

数千万数据,启用分片

resource_xxx_info

未启用分片,数亿数据

resource_xxx_info

未启用分片,数亿数据

......

......


上面的描述可以总结为下图:



从上图可以看出,分片 2 和分片 3 几乎没起到任何作用;由于分片 3 有两个节点为低 IO 的 sata 盘,可能影响 userbucket 库的读写,因此考虑直接 removeShard 从集群中剔除分片 3 和分片 2。

二、操作过程

由于分片 3 为低 IO 服务器,有潜在抖动集群抖动分享;同时分片 2 和分片 3 几乎都是浪费的分片,因此打散直接通过如下 removeshad 命令删除分片 3 和分片 2 信息,腾出无用服务器资源,如下图所示:



  • 步骤 1:登陆任一一个代理,假设是代理 mongos1。

  • 步骤 2:由于分片 3(也就是 shard_8D5370B4 分片)为 userbucket 库的主分片,因此报错了,提示"you need to drop or movePrimary these databases",意思是我们需要提前把该库的主分片信息迁移到其他分片。

  • 步骤 3:通过 movePrimary 命令把 userbucket 库的主分片从分片 3 迁移到分片 1。

  • 步骤 4:登陆监控列表中的其他两个代理 mongos2、mongos3,通过 db.adminCommand({"flushRouterConfig":1}) 强制刷新路由信息。


注意事项:由于 movePrimary 过程,其他代理不会感知到该库的主分片变化,因此需要强制刷新路由信息或者重启其他节点的 mongos,参考如下:


三、用户反馈大部分请求业务请求不可用

对含有 300 条数据的 userbucket 库变更后,当我还在若无其事的处理其他集群性能调优的时候,用户突然反馈该核心集群部分访问不可用(注意:是整个 10 亿级表部分访问不可用,不仅仅是变更的 300 条数据访问不可用)。


收到电话后很突然,和业务人员详细对接后可以基本上确定是因为这 300 条数据变更引起。业务获取这 300 条数据的时候,部分请求获取成功,部分请求获取失败,说明肯定和 movePrimary 有关系。


于是,除了对监控列表中的所有代理做 flushRouterConfig 强制路由刷新外,还重启了所有的代理,但是业务反馈,还是有部分请求获取不到数据。比较棘手,我自己通过所有的 mongos 代理查看 userbucket 库下面的 300 条数据,完全可以获取到数据。


于是怀疑是不是还有未刷新路由的 mongos 代理,于是登陆任一 mongos 代理获取 config.mongos 表,查看结果如下:



上面的 config.mongos 表记录了该集群所有的代理信息,同时记录了这些代理和集群最后一次 ping 通信的详细时间信息。很明显,该表中记录的代理原不止集群监控列表中的代理个数,比监控列表中的个数要多。


最终,把 config.mongos 表中罗列的当前在线的所有代理强制通过 flushRouterConfig 刷新路由后,业务恢复。

四、问题总结

通过前面的分析可以得出,由于早期集群监控中漏掉了部分代理,造成这部分代理对应的 userbucket 路由信息是 movePrimary 前的路由信息,也就是指向了错误的分片,因此出现了路由不到数据的情况,如下图所示:



  • 为何用户 userbucket 库对应表中数据有的成功有的失败?

因为部分代理在 moveprimary 后,没有强制刷新该表路由信息,造成部分代理路由获取数据的时候路由错误。


  • 为何该 300 条数据部分路由信息错误会造成整个 10 亿集群部分访问不可用?

和业务实现逻辑有关系,因为业务在获取这 10 亿条数据前首先需要获取业务的路由信息,刚好业务路由信息存在了 userbucket 库对应表中,业务在获取数据前必须要获取到业务的路由信息数据,如果 userbucket 数据获取不到,用户就无法确定指向 feeds_xxxxxxx 数据。


  • 为何会遗漏部分代理重启或者强制路由刷新?

历史原因,造成部分代理业务代码有配置,但是服务端集群监控元数据遗漏了,也就是服务端集群监控漏掉了部分代理,这部分代理没有监控起来。也有可能是 mongos 代理扩容,但是集群监控列表中没有加入元数据。


  • movePrimary 操作最安全的操作方法?

官方建议 movePrimary 操作成功后需要强制路由刷新或者重启 mongos,但是 movePrimary 操作成功和 mongos 重启这个过程中有个中间状态,如果中间状态业务读或者些该迁移的库下面的表,还是可能路由错误。


因此,最佳安全的 moveprimary 可以通过如下两个方法操作:


方法一:shutdown 所有代理,只留下一个代理,等该代理 moveprimary 成功后在重启其他 mongos 代理。切记别遗漏代理,出现本文踩坑类似情况,提前检查 config.mongos 表。


方法二:如果某些库的主分片在需要 removeShard 下掉的分片的时候,对该库的表启用分片功能,启用分片功能后会有 chunk 信息,当 removeShard 某个分片的时候会自动迁移该分片的 chunk 到其他分片,整个过程可以保证所有代理获取最新最完整的路由信息(所有代理通过 chunk version 版本管理机制来实时更新最新的路由信息)。


作者介绍

杨亚洲,前滴滴出行专家工程师,现任 OPPO 文档数据库 mongodb 负责人,负责数万亿级数据量文档数据库 mongodb 内核研发、性能优化及运维工作,一直专注于分布式缓存、高性能服务端、数据库、中间件等相关研发。后续持续分享《MongoDB 内核源码设计、性能优化、最佳运维实践》,Github 账号地址:https://github.com/y123456yz


本文转载自:dbaplus 社群(ID:dbaplus)

原文链接:这300条数据变更,引发了十亿级核心集群的罢工惨案!

2021-06-30 08:001342

评论

发布
暂无评论
发现更多内容

区块链药品溯源解决方案-区块链技术监管医药溯源

13530558032

《不看后悔》38个JVM精选问答,让你变成专家

Java 架构 面试 JVM虚拟机原理

总结近期腾讯+阿里+百度Java岗高频面试题,提问率高达98%,看到这篇文章基本offer稳了

Java架构之路

Java 程序员 架构 面试 编程语言

两会热词“区块链”,打开传统溯源的一扇大门!

源中瑞-龙先生

区块链 两会

阿里面经最新分享:Java面试指南/成长笔记(金三银四程序员必备)

比伯

Java 编程 程序员 架构 面试

进程调度算法

鲁米

算法

Git 常用记录

Leo

git 大前端

Elasticsearch Index Types and Mappings

escray

elastic 七日更 28天写作 死磕Elasticsearch 60天通过Elastic认证考试 3月日更

mock 请求分发

blueju

JavaScript React Mock umi umijs

该死的端口占用!教你用 Shell 脚本一键干掉它!

星安果

Shell 脚本 shell脚本编写 端口 端口占用

【回溯算法】借助最后一道「组合总和」问题来总结一下回溯算法 ...

宫水三叶的刷题日记

面试 LeetCode 数据结构与算法

5个身份和访问管理的最佳实践

龙归科技

数字身份 身份认证 身份安全 统一身份认证

架构大作业1

J

【LeetCode】下一个更大元素 II Java题解

Albert

算法 LeetCode 28天写作

聊聊交易中台系统设计与思考

架构精进之路

中台 七日更

2021年阿里巴巴Java百亿级并发系统设计笔记(全彩版)

Java架构追梦

Java 阿里巴巴 面试 架构师 百亿级并发

架构大作业2

J

该不该签竞业协议?

石云升

程序员 话题讨论 28天写作 职场经验 3月日更

互联网信贷风险与大数据 风险管理&信贷准入

张老蔫

28天写作

饿了么刚给我确认了p7的职位,对自己的经历,做一个面试总结。

Java架构之路

Java 程序员 架构 面试 编程语言

区块链电子合同应用平台-助力企业数字化转型

13530558032

【金三银四】这才是打开Java面试的正确方式,吃透这份【Java面试手册】offer稳了

Java 编程 面试

如何写 Go 代码

Rayjun

Go 语言

说完列表说字典,说完字典说集合,滚雪球学 Python

梦想橡皮擦

28天写作 3月日更

LARAVEL SMTP 服务泄露,laravel env暴露

kaer

laravel 信息安全 漏洞 ENV SMTP

智慧党建系统开发,智慧组工平台建设

13530558032

Flutter 2 来了

SamGo

flutter

正则表达式.01 - 元字符

insight

正则表达式 3月日更

微信团队分享:微信直播聊天室单房间1500万在线的消息架构演进之路

JackJiang

微信 架构设计 即时通讯

Spark性能调优-RDD算子调优篇(深度好文,面试常问,建议收藏)

五分钟学大数据

大数据 spark 28天写作 3月日更

程序员之禅(四)

每天读本书

读书笔记 每天读本书

这300条数据变更,引发了十亿级核心集群的罢工惨案!_大数据_dbaplus社群_InfoQ精选文章