【ArchSummit架构师峰会】探讨数据与人工智能相互驱动的关系>>> 了解详情
写点什么

搞会这个索引添加法,十亿级时延敏感集群想抖动都难

  • 2021-06-22
  • 本文字数:3994 字

    阅读完需:约 13 分钟

搞会这个索引添加法,十亿级时延敏感集群想抖动都难

线上某 mongodb 集群存储影响公司收入流水的核心数据,本文分享该集群为何多个索引串行后台会引起集群抖动,并且部分节点出现了连接数耗光等问题。同时通过本案例,给出时延敏感业务该最优方式添加索引,做到对业务最小化影响或者无影响。


索引对业务查询性能提升起着至关重要的作用,但是绝大部分 mongodb 程序员和 DBA 对时延敏感业务的索引添加方法是错误的。


本文主要完成一下几个目的:


  • 为何 background 后台加索引会引起时延敏感集群抖动?

  • 为何前面两个索引添加过程没触发告警,第三个索引添加完成后才触发告警?

  • 为何只有从节点抖动,主节点时延一切正常?

  • 为何连接数暴涨?

  • 连接数耗光,mongo shell 无法登陆查看节点内部状态信息,如何破局?

  • 时延敏感型业务如何做到业务无感知索引添加?

一、业务背景

某业务存储公司核心数据,集群异常会影响公司流水收入,该业务对时延非常敏感,稍有抖动就容易引起客户端超时异常,该业务场景如下:


  • 数据量很小,10 亿级

  • 核心业务

  • 时延敏感

  • 分片模式,单个分片

  • 读写分离

  • 读多写少

  • 峰值流量 8-10W/s


该集群对应 mongodb 内核版本:3.6.13,某天业务自己通过 mongodb 管控平台串行方式添加几个索引(background 后台添加),一个索引添加执行完成返回后,业务开始下一个索引的添加。


添加第一个索引和第二个索引完成后,业务没告警,但是当业务添加完第三个索引后,开始收到部分查询时延超过阀值告警。

二、集群架构

2.1 集群部署架构

该集群部署架构如下:



该业务集群对应流量监控曲线如下:



如上图所示,该业务部署只有一个分片,该分片为一主四从结构 5 节点。分片 1 采用 5 节点的原因如下:


  • 核心业务,5 副本方式部署,可以容忍两个节点估值

  • 时延敏感,由于业务优先读从节点,因此可以通过增加分片从节点的方式提升业务的 QPS。

2.2 一个分片为何要选择分片模式?复制集不是可以满足要求吗?

从上面的结构图可以看出,该集群只有一个分片,采用了分片模式架构,为何不选择复制集架构,这样还可以省掉 mongos 代理和 config server 的成本开销。采用分片模式主要基于如下因素考虑:


  • 该业务当前数据比较小,10 亿级别,但是随着时间增长后续可能会增加到百亿级别,考虑到以后可能存在分片扩容的需求,因此采用了分片模式。

  • 该集群当前写入更新比较少,后续可能存在大量写入更新的场景,大量写入更新需要多分片来支撑。

  • 我司在 mongos 代理增加了很多功能,例如限流、流量控制、权限细化控制、监控信息完善等功能,因此默认采用分片模式。

三、问题快速发现及解决

3.1 问题发现

某天,突然告警中心打来电话,突然收到如下告警信息:



几乎四个从节点先后收到同样的告警,节点时延部分请求超过 20ms,由于该业务是非常核心的影响业务营收的核心集群,非常紧张。但是,有一个很奇怪的现象,主节点访问时延正常,只有从节点时延抖动。


此外,还不停收到实例不可用异常告警,对应监控曲线如下:




说明:上图曲线一根代表客户端当前已用连接数,一根曲线代表剩余可用连接数。

3.2 问题排查过程 

收到告警后,发现业务有很多慢日志(时延敏感业务,慢日志打印阀值为 20ms),同时慢日志都走了最优索引。


  • 通过 mongo shell 登陆对应节点后台


于是通过 mongo shell 登陆节点后台,但是登陆不上,出现如下打印:


1.MongoDB shell version v3.6.13  2.connecting to: mongodb://x.x.x.x:20001/test?gssapiServiceName=mongodb  3.2021-04-29T11:09:15.049+0800 E QUERY    [thread1] Error: network error while attempting to run command 'isMaster' on host x.x.x.x:20001'  :  4.connect@src/mongo/shell/mongo.js:263:13  5.@(connect):1:6  6.exception: connect failed  
复制代码


由于节点登陆不上,因此登陆到存储节点查看后台日志,日志中有大量的打印提示连接数耗光了,如下图:



  • 节点系统监控统计分析

从上面的现象可以看出链接耗光了,于是分析节点所在服务器系统监控,发现一个问题,磁盘 IO 非常高,如下:



  • 分析 mongod 实例日志

由于从节点登陆不上,系统磁盘 IO 很高,因此怀疑有慢操作在运行,于是分析实例日志,发现如下现象:



  • 问题确认

通过前面的分析可以得出问题根因在于加索引引起从节点磁盘 IO 过高,最终引起业务查询时延上升抖动。


通过和业务沟通,业务这段时间确实通过我们的管控平台串行方式加了几个索引,磁盘 IO 过高由业务加索引引起,同时从节点同一时刻有多个索引添加。加索引过程首先需要读取表数据,然后通过数据构建索引,这个过程都会有多次 IO 操作。磁盘 IO 是公用的,服务器 IO 高会引起该服务器上所有的 IO 操作变慢,因此最终引起从节点读服务抖动。


  • 问题解决过程

到这里,我们已经确定问题是由于加索引引起,只有把索引干掉磁盘 IO 才会恢复正常,因此我们需要尽快干掉索引。然而,由于连接数已经耗光,无法链接从节点,所以我们不能做 killop 操作。


由于无法登陆后台做 killop 操作,于是直接 kill 进程,kill 进程后启动,发现 mongod 还是在构建索引,如下:



重启后,还是需要构建索引,因为之前索引没有执行完成 mongod 进程就挂了,因此需要重建索引来保持与主节点状态一直。


不过,mongod 为了解决类似问题,提供了一个 noIndexBuildRetry 参数来跳过实例加索引中途异常重启后重构索引的流程,该参数功能如下说明:


don't retry any index builds that were interrupted by shutdown    


noIndexBuildRetry 放弃启动从节点 mongod 实例,业务很快恢复:


mongod -f /home/service/mongodb/conf/mongod_20001.conf --noIndexBuildRetry 

四、createIndex 构建索引核心流程及问题暴露过程

4.1 createIndex 构建索引核心流程

业务链接代理通过 createIndex 命令添加 background 后台索引,其运行流程如下图所示:



主节点接受到 createIndex 命令后的执行主要流程如下:


  • 主节点查询对应表数据,然后 build 构建索引。

  • 索引数据构建执行完成后,返回客户端 OK。(注意:主构建完成后就通知 OK 给客户端,实际上这时候从节点还没有开始构建索引)

  • 生成 createIndex 对应 oplog 数据到 oplog 表

  • 从节点获取到 createIndex 对应 oplog 操作,然后重放 createIndex 构建索引。

4.2 问题暴露流程

通过分析日志时间点和告警时间点,和业务确认,发现当业务第三个索引添加完成后(实际上只是主节点构建索引完成),开始触发时延告警阀值。总接时间序列如下:


  • T1 时刻第一个索引主节点构建完成,然后同步到两个从节点构建索引,也就是 T1 时刻两个从节点只有一个索引 index1 在运行。

  • T2 时刻第二个索引主节点构建完成,然后从节点获取到这个索引执行,这时候由于从节点读流量大,因此构建索引比主节点慢,最终 index1 和 index2 都在两个从节点运行。此时,访问时延还没有触发时延告警阀值。

  • 以此类推,T3 时刻第三个索引添加完成,从节点通过 oplog 获取到第三个索引运行,由于此时 index1、index2 都还没有运行完成,因此两个从节点同时构建 index1、index2 和 index3 索引。三个索引的同时运行,进一步加重了磁盘 IO 负载和系统开销,业务访问时延进一步上升,最终造成部分查询时延超过 20ms。


总结如下图所示:


五、疑问解答

  • 为何 background 后台加索引会引起时延敏感集群抖动?

如上面分析,虽然业务是串行的方式一个索引添加成功后再添加下一个 background 后台索引,由于主从索引构建执行时间的长短不同,从节点通过拉取对应 oplog 重放,最终引起某一时刻开始三个索引在所有从节点同时运行,引起 IO 负载很高,最终触发业务访问时延告警。


  • 为何前面两个索引添加过程没触发告警,第三个索引添加完成后才触发告警?

如上,从节点拉取 Oplog 获取到第三个索引执行的时候 IO 负载进一步增加,最终触发了 20ms 访问时延阀值。


  • 为何只有从节点抖动,主节点时延一切正常?

主节点由于业务添加是一个索引后台添加完成后,才添加第二个索引。也就是主节点同一时刻只会有一个索引在执行,IO 负载低,此外由于主节点写流量本身不高,读流量几乎都在从节点,索引加索引执行很快,并且几乎不会影响写流量时延。


  • 为何连接数暴涨?

连接数暴涨实际上是加索引引起业务访问慢的结果,由于三个索引同时在从节点构建索引运行,造成从节点 IO 负载很高,最终造成业务访问变慢。


访问变慢后,会引起客户端链接池中的链接不够用,于是客户端会动态的增加链接池中的连接数来进行后端 DB 访问,最终造成了 mongod 服务端连接数到达配置上线出现无法链接的问题。


  • 连接数耗光,mongo shell 无法登陆查看节点内部状态信息,如何破局?

连接数耗光,mongo shell 将无法连接节点,无法获取节点内部状态。可以对该功能做优化,对指定的客户端(默认 127.0.0.1)设置白名单,取消 max connections 限制,这样我们即可通过节点本机登陆 mongod 后台获取内部状态信息。


例如增加了链接限制白名单后,就可以通过 127.0.0.1 登陆到节点内部,然后通过 killOp 操作把从节点正在构建索引的操作干掉。

六、时延敏感型业务如何做到业务无感知索引添加?

方法一:所有主从确保索引执行完成后添加下一个索引(影响相对较小)后台 background 加索引,确保所有主从索引构建完成后,才开始下一个索引的创建,避免出现本文所说的多个索引同时在从节点执行引起业务抖动。


说明:mongodb 高版本中对后台添加索引做了优化,从节点拉取建索引对应 oplog 重放的时候,只有第一个索引执行完成,才会执行第二个索引,从而避免了同时多个索引同时执行引起的抖动。


方法二:单机启动,然后加索引,加完索引后再加入到副本集(业务无任何感知)无感知添加索引步骤如下:


  • 从复制集中移除某个从节点

  • 单机方式启动该节点

  • 阻塞方式(不带 background)加索引,这样索引构建速度更快

  • 索引添加完成后,副本集方式启动该节点

  • 把该节点加入复制集


通过以上步骤,即可无感知方式完成一个从节点的索引添加,其他节点添加过程重复该操作过程即可。


作者介绍

杨亚洲,前滴滴出行专家工程师,现任 OPPO 文档数据库 mongodb 负责人,负责数万亿级数据量文档数据库 mongodb 内核研发、性能优化及运维工作,一直专注于分布式缓存、高性能服务端、数据库、中间件等相关研发。


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

原文链接:搞会这个索引添加法,十亿级时延敏感集群想抖动都难

2021-06-22 07:001238

评论

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

极速上手使用Docker,这篇文章就够了!

浅羽技术

Java Docker centos 容器化 三周年连更

挑战 30 天学完 Python:Day15 错误类型

MegaQi

挑战30天学完Python 三周年连更

爱在日落黄昏时 | 我有话要说

后台技术汇

三周年连更

火山引擎云原生数据仓库ByteHouse技术白皮书V1.0 (Ⅵ)

字节跳动数据平台

大数据 数据仓库 云原生 元数据 企业号 4 月 PK 榜

云资源提供技术

阿泽🧸

云资源 三周年连更

CDH安装与部署

乌龟哥哥

三周年连更

自动化运维工具一览

穿过生命散发芬芳

自动化运维 三周年连更

音视频八股文(9)-- flv的h264六层结构和aac六层结构

福大大架构师每日一题

音视频 ffmpeg 福大大

什么是软件开发领域的 obsolete 或者 deprecated 含义

Jerry Wang

软件工程 软件开发 三周年连更

深入探讨Go语言中Semaphore信号量的机制原理

Jack

我们如何将 Amazon Snowcone 送入轨道

亚马逊云科技 (Amazon Web Services)

Qz学算法-数据结构篇(二分查找、删除)

浅辄

三周年连更

Matlab实现最优化

Shine

三周年连更

【Python实战】Python采集代理IP信息

BROKEN

三周年连更

C++ STL容器和算法:详解和实例演示

小万哥

c++ 容器 算法 后端 stl

《底层逻辑2:理解商业世界的本质》

石云升

读书笔记 三周年连更

如何评价 ChatGPT 回答策略的 ensure only ethical usage 特质

Jerry Wang

ChatGPT ChatGPT4 三周年连更

Matlab实现机器学习

袁袁袁袁满

三周年连更

读书笔记:如何成为某个领域的前1%

老张

读书笔记 方法 写作技巧

算法题每日一练:螺旋矩阵 II

知心宝贝

数据结构 算法 前端 后端 三周年连更

通过华为云ECS云服务器搭建安防视频监控平台

DS小龙哥

三周年连更

手撕代码系列(三)

控心つcrazy

JavaScript 前端面试题 手撕代码 ES6-ES12 面试必考

Django笔记十九之manager用法介绍

Hunter熊

Python django Manager

轻松处理pdf文件:Acrobat Pro DC 2023 中文激活版

真大的脸盆

Mac Mac 软件 PDF编辑 pdf编辑工具

粉丝提问:区块链与大数据开发读研方向怎么选?

千与编程

区块链、 大数据 开源

2023-04-29:一个序列的 宽度 定义为该序列中最大元素和最小元素的差值。 给你一个整数数组 nums ,返回 nums 的所有非空 子序列 的 宽度之和 由于答案可能非常大,请返回对 109

福大大架构师每日一题

golang 算法 rust 福大大

挑战 30 天学完 Python:Day14 高阶函数

MegaQi

挑战30天学完Python 三周年连更

Windows下 IDE工具常见编译错误FAQ

鸿蒙之旅

OpenHarmony 三周年连更

切片的其他妙用

宇宙之一粟

Go 切片 三周年连更

高效理解机器学习

俞凡

机器学习 算法

10分钟打造基于ChatGPT的Markdown智能文档

俞凡

人工智能

搞会这个索引添加法,十亿级时延敏感集群想抖动都难_大数据_dbaplus社群_InfoQ精选文章