写点什么

腾讯云 MongoDB 智能诊断及性能优化实践

  • 2022-06-20
  • 本文字数:6459 字

    阅读完需:约 21 分钟

腾讯云 MongoDB 智能诊断及性能优化实践

4 月 15 日-16 日,由 InfoQ 主办的 DIVE 全球基础软件创新大会通过云上展厅的形式成功召开。在腾讯云基础软件创新实践专场,来自腾讯云的数据库专家工程师杨亚洲带来了主题为《腾讯云 MongoDB 智能诊断及性能优化实践》的演讲,以下为主要内容。


本次分享,主要分为六个部分展开:



第一部分主要介绍 MongoDB 的核心优势;第二部分介绍使用腾讯云 DBbrain for MongoDB 对 MonogoDB 进行一些诊断和性能优化相关的实践;第三部分介绍 MongoDB 常用的一些异常诊断和处理方法;第四部分介绍腾讯云 MongoDB 智能索引推荐的整个实现流程及其实现原理;第五部分介绍腾讯云在 MongoDB 内核增加的 SQL 限流功能及其实现;最后一个部分结合典型案例,介绍在维护一个千亿级高并发 MongoDB 集群的过程中会遇到哪些问题,并且如何解决这些问题。

MongoDB 有哪些核心优势?


MongoDB 是一个基于分布式文件存储的数据库,由 C++语言编写。首先,我们来看下它有哪些核心优势,下面列举几个:

分布式


MongoDB 是开源的分布式数据库,可以解决传统数据库存储容量上的瓶颈问题,用户不必再提前考虑分库分表等操作。同时,MongoDB 也是一个天然高可用的数据库,比如在一主两从的工作模式下,当主节点意外宕机,从节点就会接替主节点的工作,整个过程无须依赖任何第三方组件。

schema-free


MongoDB 的表结构相对自由,添加字段方便快捷,相比于传统数据库在一张大表里添加字段,运维成本被大大降低。

高性能


MongoDB 早期使用 MMAPv1 存储引擎,后来替换为 WiredTiger 存储引擎,它支持行级粒度锁、热点数据缓存等特性,这给 MongoDB 带来了高性能、低延迟、高吞吐等能力。

高压缩比


在默认配置下,MongoDB 使用 snappy 压缩算法,可达到平均 2 到 4 倍的文本数据压缩能力,如果使用 zlib 压缩算法则可以提升到 3 至 7 倍,但是 zlib 对性能有一定影响,因此线上通常使用默认配置即可。经测试,在默认配置的情况下,同样一份数据写入 MongoDB、MySQL、ES 的真实磁盘消耗比约为 1 : 3 : 6。

完善的客户端访问策略


MongoDB 支持五种均衡访问策略:


  • primary:读主节点,当主节点异常时,可能造成短期内的业务异常。

  • primaryPreferred:主节点优先,当主节点异常时可以读从节点。

  • secondary:读从节点,把流量平均衡分配给多个从节点,实现负载均衡。

  • secondaryPreferred:从节点优先,如果从节点异常,则读取主节点。

  • nearest:就近访问,在多机房场景下,就近访问可以避免出现跨机房访问的情况。

腾讯云 MongoDB 核心优势


相比用户自建 MongoDB 数据库,腾讯云 MongoDB 在智能运维、可用性、安全性、性能等方面更具优势。同时通过 DBbrain 提供一站式监控的诊断分析,并且能给出相应的优化建议,同时也集成了官方的常用工具,让用户使用更方便。


此外,腾讯云 MongoDB 还在内核里做了一些定制化的开发,比如解决表数量达到百万级别时的性能问题、提供 SQL 限流功能减少流量过大导致的集群不可用问题。安全方面,腾讯云 MongoDB 可以将数据恢复到 7 天内的任意时间点,并且提供 24 小时的专业支持服务。除此之外,也天然集成了云上高可用、高性能等通用能力。

DBbrain for MongoDB


DBbrain for MongoDB 是腾讯云开发的数据库智能管家,是为用户提供数据库性能、安全、管理等功能的数据库自治云服务,它不仅支持 MongoDB 数据库,同时也接入了 MySQL 等其它数据库。其拥有的核心能力如下:


  • 丰富的监控指标:除了最初控制台暴露给用户的主要监控指标以外,所有实例维度和节点维度的核心指标同时也被暴露到 DBbrain 上。

  • 丰富的工具集成:一键集成 MongoDB 常用分析工具,如 mongostate、mongotop 等。如果需要查看某个实例或者某个节点的流量、库表分布等信息,直接在控制台界面点击就可以实时输出,无需额外通过客户端登录查看。

  • 实时异常事件诊断与优化建议:很多异常事件可以被 DBbrain 提前发现,并且给出一系列优化建议,除了常规的异常诊断,还包括一些特殊的异常诊断项。

  • 实时 kill 会话:有些查询没有使用到索引,有时需要手动 kill 这些会话,现在这些操作可以直接在 DBbrain 上完成,甚至可以设置一些定时任务来周期性的执行,这样开发或运维人员就不需要自己编写脚本来进行操作。

  • 库表分析:对不通库和表进行详细分析。

  • 慢日志分类汇总:将慢日志进行分类汇总,更清晰直观的展示给用户。

  • 健康报告:每日生成健康报告,数据库状况一目了然。

  • 索引推荐:很多用户自己并不清楚如何创建最优索引,这时就可以采用 DBbrain 推荐的最优索引。腾讯云 MongoDB 索引推荐使用"索引规则"+“代价计算”方案实现,详见后面索引推荐章节。

  • SQL 限流:在流量过高、异常读写等业务场景下,可以使用 SQL 限流来保障核心业务访问的可用性。

MongoDB 常用的异常诊断处理方法


当前,异常诊断已经覆盖了 MongoDB 常见的核心指标,实时对云上所有实例进行异常分析,发现异常后会第一时间触发诊断告警并提出优化建议。


通常我们把异常诊断项分成两种,一种是基础的诊断指标,比如内存、CPU、磁盘、连接数、慢查询、节点连通性、主从延迟、oplog 保存时间等,这些是最常用的数据库诊断指标。


另一种是高级的诊断指标,比如 session 会话数(session 会话数较高的时候,可能会引起集群抖动)、读写活跃队列、前台加索引、读写等待队列、死锁检查(索引还没加完,又去删除索引就会造成死锁)、X 锁(排它锁)检测、路由异常、全表扫描、认证失败(比如一个业务上线时写错了用户名密码,此时就会产生大量的异常报错),还有纯粹的引擎相关的一些参数,如引擎 Cache 使用百分比、引擎脏数据百分比等。

MongoDB 智能索引推荐实现


智能索引推荐主要是基于索引规则和代价估算来实现的,整体架构如下:



智能索引推荐分为四个模块:


  • agent 模块:实时收集 mongod 节点日志,然后输出日志到 kafka 模块。

  • kafka 模块:存储 mongo 节点收集的日志信息。

  • 日志分类模块:kafka 有用慢日志收集,并进行分类处理。

  • 代价估算模块:模拟 MongoDB 内核执行计划过程,进行候选索引代价估算。系统整体的工作流程如下:每个 MongoDB 节点上布署有 agent 节点,它会实时采集所有有用的日志并存储到 Kafka 里,日志分类处理模块会从 Kafka 里把需要的日志提取出来进行分类,然后把分类好的日志交给索引代价计算模块进行计算,最终得到最优索引。


其中,agent 模块和 kafka 模块的逻辑相对简单,这里重点介绍日志分类模块和代价估算模块。

日志分类模块的实现步骤


日志预处理分类


第一步:提取有效的慢日志。


并不是所有的慢查询日志都需要处理,只需提取存在索引问题的慢查询,诸如索引不是最优、全表扫描,这类日志才需要提取。如果判断索引不是最优?


答案是,对比走索引时候数据扫描的行数与实际返回数据的行数,如果差值较大,就判断这个索引不是最优的,需要进一步优化。


第二步:根据 filter 对 SQL 分类。


同一个库表中会有很多查询,查询条件不尽相同,属于同一类的 SQL 需要满足几个条件,即库、表、命令、查询条件完全相同。前三个条件容易区分,比如同库同表情况下,查询条件(包括 find、update、delete 等)相同算一类,而查询条件相同的前提是查询关键字要相同且操作符属于同一类,同时要忽略查询字段顺序。


日志聚合处理


定期从 DB 中获取分类好的 SQL 信息交给代价估算模块进行处理。

索引代价计算模块处理流程


  • 抽象语法树生成及分解:从日志分类处理模块中获取对应 SQL,抽象语法树,同时进行分解。

  • 根据索引规则生成候选索引:根据最优候选索引规则生成侯选索引的流程,可以参考腾讯云数据库公众号发布的文章:《云上 MongoDB 常见索引问题及候选索引规则大全》一文。

  • 对候选索引进行代价估算:从源集群随机抽样数据,对候选索引进行代价估算,最终得出最优索引。下面重点介绍候选索引代价计算过程。

候选索引代价计算


代价计算主要步骤:


1、随机采样少量数据:从线上实例随机采样少量数据,为了尽量减少对线上集群影响,优先采集隐藏节点,如果没有隐藏节点则采集从节点。同时控制采样数据量和采样频率,尽力减少对线上集群影响。


2、获取每个字段区分度:根据采样的数据获取查询条件对应字段的区分度。


3、根据裁剪后的子树按照索引规则生成候选索引:这里可以参考腾讯云数据库公众号输出的 MongoDB 索引规则大全。


4、每个候选索引代价计算:对每个候选索引模拟内核执行计划流程确定计算代价成本。


假设有 [{work:1, city:1, province:1}, {city:1,  province:1,  age:1}])这个候选索引,其代价计算过程如下图所示:



上面的候选索引对应的执行计划流程是:如果查询选择该候选索引执行,其执行计划首先进入 index scan stage,然后进入 OR stage,OR stage 执行完成后就会开始做 fetch 操作,最后就会得出整个流程扫描了多少行数据、得到了多少行数据,以及整个流程的执行时间;


腾讯云的代价估算是由一个旁路模块实现的,实现难度较大,需要对整个内核执行计划有较透彻的理解。所以对于自研用户,如果研发人力有限,可以采样数据到新的 MongoDB 集群,根据候选索引规则,同时借助内核已有的能力进行字段区分度、候选索引代价计算,最终得出执行这个索引扫描了多少行、执行多少行、执行了多长时间,最终也可以得到最优索引。



智能索引推荐当前已经服务化,逐步会开放给用户使用,如果大家有兴趣可以去体验。索引推荐基本上能在半小时内发现实例上存在的索引问题,除了推荐最优索引外,还可以把实例上的无用索引和重复索引也找出来,这样能用最少的索引满足用户需求,性能等方面也会更好。

腾讯云 MongoDB 索引推荐总结


  • 快:慢查产生半小时左右推出最优索引

  • 准:推荐索引为候选索引中代价计算最小的最优索引

  • 稳:采样计算过程对云上集群无影响,索引添加过程增加保护措施,同一实例同一时刻最多同时添加一个索引。

MongoDB 内核 SQL 限流实现

为什么要做 SQL 限流?


首先,我们先思考这样一个问题:为什么要做 SQL 限流?



一方面,当流量过大、负载过高,数据库抖动可能造成雪崩时,就可以限制一下流量,保证一些请求能正常返回。另一方面,有些用户为了节约成本,将多个用户的数据写到了同一个实例不同表中,某一时刻可能出现用户新上的接口不对或其它异常情况,导致流量非常高,就会影响这个实例上的其他核心业务,这时就可以通过限流对异常或者不太重要的表做限流处理,保证核心的业务流量能正常访问。此外,还有一些突发扫表,高危操作等都可以通过限流进行限制。

内核哪个位置增加限流功能?


那么,我们在内核哪个地方做了 SQL 限流功能呢?



先捋一下 MongoDB 的整体架构,它是分层的,第一层是网络收发模块,网络收发过后,交由命令处理模块把这些 SQL 解析出来,然后这些 SQL 会进入查询引擎模块、读写模块以及并发控制模块等流程。

SQL 限流核心实现


我们整个 SQL 限流模块是加在命令处理模块之后的,加在这里有什么好处呢?因为在这里已经拿到了详细的 SQL,并且在并发控制之前做到 SQL 限流,避免 SQL 限流里面的操作会影响并发控制和数据库读写访问,防止与下层的并发控制模块产生冲突。



内核 SQL 限流的整体流程如下:



首先,在 DBbrain 界面上可以配置策略规则,比如 SQL 类型、并发数,可以配置定时关闭还是手动关闭,定时关闭是指最多执多少时间,手动关闭就是打开后一直执行,除非人为手动关闭停止。


然后,是根据读写 SQL 关键字,配置完规则,就可以对指定库、表或者指定的 SQL 语句做限流。整个流程是首先在 DBbrain 的控制台下发规则,以分片集群为例,就下发给分片集群的 config server,config server 接收到后把这个规则写到 config server 的一个表里,shard server 的每个 mongod 定期从 config server 获取这些规则并加载到自己内存里,所有的 mongod 节点内存里就会有完整的规则数据存在,当发起一个请求,通过客户端到代理,再到 mongod 节点的时候,进行限流规则匹配,触发限流操作。


至于为什么选择在 mongod 上做限流,而不是在 mongos 上。主要是因为,mongos 上面的流量控制是由客户端基于 IP 做哈希的,可能导致流量不均匀。此外,线上有副本集的集群,也有分片集群,在 mongod 上做可以实现代码统一。在 mongos 上做限流,因为 mongos 之间是无状态的,无法保证相互的控制达到一定的级别。最后,瓶颈一般都在 mongod 节点上,所以就选择在 mongod 上面做限流。


SQL 限流规则及规则匹配限流流程


下面继续分享腾讯云 MongoDB SQL 限流的限流规则和规则匹配限流流程。


限流规则:



至于 SQL 限流规则主要包含哪些信息,主要包括 SQL 类型(比如增删改查)、限流时间以及并发数,并发数可以限制某类请求同时访问我们 DB 的并发量,另外就是关键字,可以匹配库,也可以匹配表,甚至可以匹配详细的 SQL,这样就可以实现指定的库、表和某一类型的 SQL 限流。


请求匹配规则流程:



当一个请求到达 MongoDB 后,具体的处理流程是,先看这个实例是否启用了 SQL 限流功能,如果已启用,则提取用户请求中的库、表和 SQL 关键字信息,下一步和配置的限流规则做匹配,判断这类 SQL 是否有可用的 ticket。


ticket 代表并发控制中的并发数,如果没有可用的 ticket,比如 ticket 值为 0,就直接限制这个请求,返回客户端异常。如果有可用的 ticket,就把 ticket 值减 1,同时访问 DB,访问到 DB 后就将数据返回给客户端,同时释放当前 ticket,后面的请求就可以继续复用,这就是整个限流工作流程。

典型案例:千亿级高并发 MongoDB 踩坑及性能优化实践


最后,和大家分享一个典型案例。我们有一个千亿级的高并发 MongoDB 集群,在维护过程中踩了一些坑,我们对它做了一些性能优化,在此给大家讲一下。



这个集群存储了一个金融行业头部客户大概 2000 亿数据,整体采用私有云的解决方案,MongoDB 集群采用分片模式,由于需要长时间高并发读写,写入的数据需要马上可读,所以读写都在主节点完成。



高峰期的读写流量可达几十万每秒,在极端情况下甚至能超过百万每秒。从上图可以看到仅一个分片的流量即可达到 16 万每秒。


我们其中一个踩坑点是主从切换。业务上曾出现过几次主从切换,切换完成后,从节点变为新的主节点时,整个集群出现了几分钟到几十分钟的不可用,而且这个时间是不固定的。另一个踩坑点是集群经常会出现数十秒的抖动,产生慢查询。



先来看主从切换,为什么会发生主从切换?主从切换只发生在主分片,因为主分片压力最大,流量较高,有十几万的写入,可以看到的现象是数据百分比正常,不到 20%。但内存使用率在持续增加,可以达到 95%,读写队列和流量也比较高,流量高是由于用户运行批量任务造成的,批量任务会持续运行数个小时,产生大量的写入和更新。


短期来看,集群是正常的,但长时间的压力导致整体内存持续升高,产生大量排队现象,最终主节点不堪重负,保活检测超时,进行了主从切换。


针对这个问题,短期的解决方案是让业务进行改造,在批量任务并发写入的时候减少并发量,拉长写入时间,控制在业务可以接受的范围内。但长时间的批处理作业依然会产生一定的积压现象,所以对于长期的优化方案来说,我们看到的物理现象是主分片压力很大,但是其它分片压力不大,集群的 chunks 数又比较均衡,这说明集群中存在热点 chunk。分析 oplog 写入 oplog,找出对应热点 chunk,然后手动 moveChunk 到其他分片,保证数据均衡,从而避免流量全写入一个分片。


此外,腾讯云 MongoDB 团队结合 MongoDB 内核源码对 FTDC 生成的数据进行了反解析,包括全量的和增量的。有一些疑难问题通过日志是看不出来的,比如可以看到慢,但不知道慢的原因,这时候就需要解析诊断数据。


举个例子,一个集群在低峰期的时候没有什么流量,却发生了主从切换并产生了大量慢查询,这明显是有问题的。日志里只能看出数据库慢,做了主从切换,但不知道原因。这时把诊断数据解析出来,可以分析出数据库内核模块每个流程的执行时间消耗,可以看到时间都消耗在 tcmalloc 这个模块上,用了 17 秒,这样就能明确问题出现在 tcmalloc 模块。解析出的 pageheap_free_bytes 内容如下:



进一步分析,将 diagnose.data 中的增量数据解析出来,可以看到 tcmalloc 在某个时间点一次性释放了几十 G 的内存,一次性释放大量内存就会引起业务卡顿,解决方案是在平峰期实时的释放 tcmalloc 的内存,不要积压在一起统一释放。

2022-06-20 10:083194

评论

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

App Deploy as Code! SAE & Terraform 实现 IaC 式部署应用

Serverless Devs

三个Spring的问题把我问懵逼了

知识浅谈

spring 9月月更

性能之巅-优化你的程序

Java-fenn

Java

MobPush开发过程常见问题

MobTech袤博科技

ios android 开发者

用typescript类型来实现快排

Java-fenn

Java

边缘计算和云计算之间的区别

Java-fenn

Java

Java 流处理之收集器

Java-fenn

Java

前端食堂技术周刊第 52 期:Babel 7.19.0、Fresh 1.1、React Native 0.70、新的 Web 性能指标 INP

童欧巴

聊聊如何利用p6spy进行sql监控

Java-fenn

Java

SQL 嵌套 N 层太长太难写怎么办?

陈橘又青

9月月更

利用AndroidNativeEmu完成多层jni调用的模拟

Java-fenn

Java

开源是什么意思?开源软件优缺点有哪些?

行云管家

开源 软件 开源软件 开源协议

多云管理的挑战以及如何克服这些挑战

Java-fenn

Java

【1-2 Golang】Go语言快速入门—数组与切片

Java-fenn

Java

一个不用写代码的案例,来看看Flowable到底给我们提供了哪些功能?

江南一点雨

Java springboot flowable

如何设计一个面向未来的云原生数据库?

Zilliz

深度学习 数据库 云原生 信息检索 向量数据库

实战指南 | Serverless 架构下的应用开发

Serverless Devs

Java基础知识(一些需要注意的点)

自然

9月日更 Java core 9月月更

供应链金融能否成为汽车行业发展的驱动力?

旺链科技

区块链 产业区块链 汽车 供应链金融 企业号九月金秋榜

leetcode 1110. Delete Nodes And Return Forest 删点成林(中等)

okokabcd

LeetCode 算法与数据结构

C++ 学习 ------cmath 头文件的源码学习 02

Java-fenn

Java

JavaScript 闭包难点剖析

Java-fenn

Java

中小企业如何有效应对计算资源的弹性变化需求?

Serverless Devs

面试重点:建立Java并发知识体系(含工具全图鉴)

Java-fenn

Java

Java基础之Java枚举

自然

9月日更 Java core

不是吧,还有人不知道三目运算符的BUG

自然

Java core 9月月更

2022年云堡垒机采购就选行云管家五大理由

行云管家

云计算 网络安全 数据安全 云堡垒机

现代应用参考架构之 OpenTelemetry 集成进展报告

NGINX开源社区

nginx 软件架构 Serverless Kubernetes

敏捷发版:让灰度发布像commit一样简单

Speedoooo

小程序 灰度发布 小程序容器 A/B 测试

CSS 有了:has伪类可以做些什么?

Java-fenn

Java

以软件定义物联网芯片,以技术融合推动LPWAN2.0泛在物联

ZETA开发者

芯片 物联网, LoRa LPWA DSP

腾讯云 MongoDB 智能诊断及性能优化实践_文化 & 方法_杨亚洲_InfoQ精选文章