写点什么

万亿级数据库 MongoDB 集群性能数十倍提升及机房多活容灾实践

发布于: 2021 年 01 月 18 日
万亿级数据库MongoDB集群性能数十倍提升及机房多活容灾实践

本文是 2020 年深圳 Qcon 全球软件开发大会《专题:现代数据架构》专场、dbaplus专场:万亿级数据库MongoDB集群性能优化实践、mongodb2020 年终盛会分享,分享内容如下(体验万亿级 mongodb 服务层、存储引擎、高并发线程模型、异地多活容灾等实现细节):


  1. MongoDB 在 OPPO 互联网推广经验分享-如何把一个淘汰边缘的数据库逐步变为公司主流数据库

  2. 谈谈当前国内对 MongoDB 误解(丢数据、不安全、难维护)?

  3. MongoDB 跨机房多活方案-实现成本、性能、一致性"三丰收"

  4. MongoDB 线程模型瓶颈及其优化方法

  5. 并行迁移:MongoDB 内核扩容迁移速率数倍/数十倍提升优化实践

  6. 百万级高并发读写/千亿级数据量 MongoDB 集群性能数倍提升优化实践

  7. 万亿级数据量 MongoDB 集群性能数十倍提升优化实践

  8. 磁盘 800%节省-记某服务接口千亿级数据迁移 MongoDB,近百台 SSD 服务器节省原理

  9. 展望:借助 MongoDB 完善的分布式、高可用、机房多活等功能,如何实现 NoSQL、NewSQL 融合

10.其他-那些年我们踩过的坑

关于作者


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


分享目录

  • 推广经验分享

  • 机房多活实现

  • 性能优化案例

  • 成本优化案例

  • 其他

分享主题一:如何把 mongodb 从淘汰边缘变为公司主流数据库?


背景:

  • 入职前多个大数据量业务使用 mongodb,使用中经常超时抖动

  • 多个核心业务忍受不了抖动的痛苦,准备迁移回 mysql。

  • mongodb 口碑差,新业务想用不敢用。

  • 入职 1 个月,业务迁移 mongodb 到公司其他数据库,mongodb 总集群数减少 15%


我做了什么?

  • 优化集群,解决集群抖动问题

  • 内部分享性能优化方法

  • 给重点业务分享 mongodb 原理

  • 成立 mongodb 用户群

  • 业务痛点问题及其解决方案实时用户群同步

入职 2 月后,mongodb 公司内部状态:

  1. 准备迁走的核心业务继续使用 mongodb

  2. 大数据量业务开始迁移到 mongodb

  3. 越来越多部门开始使用 mongodb


入职 1 年后,mongodb 相关数据增长:

  • 总集群数增长比例:> 700%

  • 总数据量增长比例:> 2000%

  • 读写流量增长比例:> 550%

  • mongodb 用户群用户数增长比例:> 800%


总结:

  • mongodb 赢得用户信任原因总结:口碑

分享主题二:当前国内对 mongodb 误解(丢数据、不安全、难维护)?



业务接入过程中经常咨询的几个问题:

  • 误解一.丢数据

  • 误解二.不安全,网上一堆说 mongodb 被黑客攻击,截图一堆新闻

  • 误解三. DBA 吐槽 mongodb 太难维护

误解原因:

  • mongodb 本身很优秀,但是很多 DBA 和相应开发把控不住

  • 国内系统性分析 mongodb 内核实现原理相关资料欠缺

  • 网络社会以讹传讹,DBA 或者相关开发自身把控不住演变为 mongodb 的锅

分享主题三:mongodb 机房多活方案-实现成本、性能、一致性"三丰收"

社区 mongodb 双向同步方案(放弃该方案)

放弃该方案原因:

  • 数据两份、集群两份、物理成本高。三机房、五机房等更多机房多活,成本及复杂性更高。

  • 存在一致性问题,两地集群数据不一致,balance 情况下尤为突出

  • 由于人力原因,如果开源同步工具出现问题把控不在。

方案一:同城三机房多活方案(1mongod+1mongod+1mongod 方式)

  • 每个机房代理至少部署 2 个,保证业务访问代理高可用

  • 如果某机房异常,并且该机房节点为主节点,借助 mongodb 天然的高可用机制,其他机房 2 个 mongod 实例会自动选举一个新节点为主节点。

  • 客户端配置 nearest 就近访问,保证读走本机房节点。

  • 弊端:如果是异地机房,B 机房和 C 机房写存在跨机房写场景。如果 A B C 为同城机房,则没用该弊端,同城机房时延可以忽略。

方案二:同城两机房多活方案(2mongod+2mongod+1arbiter 模式)

  • 每个机房代理至少部署 2 个,保证业务访问代理高可用

  • 如果机房 A 挂掉,则会在 B 机房 mongod 中重新选举一个新的主节点。arbiter 选举节点不消耗资源

  • 客户端配置 nearest 参数,保证读走本机房节点

  • 弊端:如果是异地机房,B 机房和 C 机房写存在跨机房写场景。如果 A B 为同城机房,则没用该弊端,同城机房时延可以忽略。

方案三:异地三机房多活方案(1mongod+1mongod+1mongod 方式)-解决跨机房写

  • 每个机房代理通过打标签的方式,代理转发数据到主节点在本机房的分片上去。

  • A 机房数据通过标签识别转发到分片 shard-1,B 机房数据转发到分片 shard-2,C 机房数据转发到分片 shard-3。

分享主题四:mongodb 线程模型瓶颈及其优化方法

mongodb 默认线程模型(一个链接一个线程)

说明:

  • listener 线程负责接受所有的客户端链接

  • listener 线程每接收到一个新的客户端链接就创建一个线程,该线程只负责处理该链接请求处理。

 

该网络线程模型缺陷:

  • 一个链接创建一个线程,如果 10 万个链接,那么就需要 10 万个线程,系统负责、内存消耗也会很多

  • 当链接关闭的时候,线程销毁,频繁的线程创建和消耗进一步增加系统负载

 

典型案例:

  • mysql 默认方式、mongodb 同步线程模型配置,适用于请求处理比较耗时的场景,如数据库服务

mongodb 默认线程模型(动态线程模型:单队列方式)

说明:

  • 该模型把一次请求转换为多个任务:mongodb 数据读操作(网络 IO)、db 层数据访问(磁盘 IO)。

  • 任务入队到全局队列,线程池中的线程从队列中获取任务执行。

  • 同一个请求访问被拆分为多个任务,大部分情况下通过递归调用同一个请求的多个任务会由同一个线程处理;。

  • 当任务太多,系统压力大的时候,线程池中线程数动态增加;当任务减少,系统压力减少的时候,线程池中线程数动态减少;

 

该网络线程模型缺陷:

  • 线程池获取任务执行,有全局锁竞争,这里就会成为系统瓶颈

 

典型案例:

  • mongodb 动态 adaptive 线程模型,适用于请求处理比较耗时的场景,如数据库服务

mongodb 优化后线程模型(动态线程模型-多队列方式)

说明:

  • 把一个全局队列拆分为多个队列,任务入队的时候按照 session 链接 hash 散列到各自的队列,工作线程获取获取任务的时候,同理通过同样的 hash 算法去对应的队列获取任务,通过这种方式减少锁竞争,同时提升整体性能。

 

典型案例:

  • mongodb 内核多队列 adaptive 线程模型优化,特定场景性能有很好的提升,适用于请求处理比较耗时的场景,如数据库服务。


分享主题五:并行迁移-集群扩容速率 N 倍提升优化实践

并行迁移-集群扩容速率 N 倍提升优化实践(高版本)

并行迁移过程(假设需要迁移的表名为:test, 从 3 节点扩容到 6 节点):

  • 选取需要迁移的块,假设源集群有 M 分片,扩容新增 N 分片,则一般情况需要迁移的块=min(M,N)

  • 迁移步骤:1. configServer-master 选出需要迁移的块;2. config.locks 表中 id=test 这条记录上锁;3.通知需要迁移的源分片开始迁移;4.迁移完成后延时 10s,重复 1-4 步骤实现持续性 chunk 数据迁移

并行迁移步骤:

   说明:假设需要迁移的表名为 test, 源分片数 M,扩容后新增分片数 N

  • configServer-master 选出需要迁移的块,一般 S=min(M, N),也就是 M 和 N 中的最小值;

  • config.locks 表中获取 id=test 这条记录对应的分布式锁;

  • 异步通知需要迁移的 S 个源分片开始迁移;

  • 等待 S 个 chunk 迁移完成

  • 迁移完成后延时 10 秒

  • 重复步骤 1-5

并行迁移瓶颈:

  • 获取分布式锁时间太长,原因:config.locks 表中 id=test 表的分布式锁可能被其他操作锁住

  • configServer 异步通知源分片中的 S 个分片同时开始迁移数据到目的分片,任一个 chunk 迁移慢会拖累整个迁移过程。

  • 本批次确认迁移完成后,还需要延时 10s;一般 SSD 服务器,一个 chunk 迁移都在几百 ms 内完成。

 

优化方法:

  • 避免其他操作占用分布式锁,例如 splite 我们可以关闭 autoSplite 功能,或者调大 chunksize

  • configServer 并行迁移不把多个分片的并行迁移放到同一个逻辑,而是放到各自的逻辑。

  • 延时放到各自分片迁移逻辑里面控制,不受全局延时控制

  • 分片延时可配置,支持实时动态命令行调整

分享主题六:性能优化案例

案例 1.千亿级数据量 mongodb 集群性能数倍提升优化实践-背景

业务背景:

  • 核心元数据

  • 数据量千亿级

  • 前期写多读少,后期读多写少

  • 高峰期读写流量百万级

  • 时延敏感

  • 数据增长快,不定期扩容

  • 同城多活集群

优化策略 1:部署及使用方式优化

  • 预分片,写入负载均衡。

  • WriteConcern:{ w: "majority"},写大部分节点成功才返回客户端 OK

  • 读写分离,读从优先。

  • enableMajorityReadConcern 关闭,有性能损耗。

优化策略 2:存储引擎 cache 淘汰策略优化

   wiredtiger 存储引擎 cache 淘汰策略相关的几个配置如下:

wiredtiger 存储引擎 cache 淘汰策略优化后配置:

eviction_target: 75%,eviction_trigger:97%,eviction_dirty_target: %3,eviction_dirty_trigger:25%,evict.threads_min:4,evict.threads_max:16

 

总体思想:evict 线程尽早淘汰脏页 page 到磁盘,增加 evict 淘汰线程数加快脏数据淘汰,避免用户请求线程进行脏数据淘汰。

优化策略 3:存储引擎 checkpoint 优化

    存储引擎 checkpoint 检测点,把当前存储引擎脏数据全部记录到磁盘。触发条件如下:

  • 固定周期做一次 checkpoint 快照,默认 60s

  • 增量 journal 日志达到 2G

 

少部分实例存在如下现象:一会儿磁盘 IO 几乎空闲 0%,一会儿磁盘 IO 短暂性 100%。进行如下优化后可以缓解该问题:

     checkpoint=(wait=30,log_size=1GB)

 

该优化总体思路:缩短 checkpoint 周期,减少 checkpoint 期间积压的脏数据,缓解磁盘 IO 高问题。

遗留问题:SSD 盘只有极少数节点有该问题,原因未知,后续继续跟踪。

瓶颈点:

  • 代理缓存所有客户端的链接信息到内存中,并定期更新到 config 库的 system.sessions 表中。

  • 大流量大数据量集群客户端链接众多,大量更新 sessions 表,最终主分片性能下降引起整个集群性能瞬间数倍下降。

优化方法:

  • config 库的 system.sessions 表启用分片功能。  

  • mongos 定期更新优化为散列到不同时间点进行更新。

优化策略 4:

  • sharding 集群 system.session 优化

 

该优化总体思路:

  • 之前代理集中式更新单个分片,优化为散列到不同时间点更新多个分片。

  • 该优化后 system.sessions 表更新引起的瞬间性能数倍降低和大量慢日志问题得到了解决。

优化策略 5:tcmalloc 内存优化

  • db.serverStatus().tcmalloc 监控发现部分 mongod 实例 pageheap、内存碎片等消耗过高。通过系统调用分析得出:内存碎片率、pageheap 过高,会引起分配内存过程变慢,引起集群性能严重下降。

 

该优化总体思路:

  • 借助 gperftools 三方库中 tcmalloc 内存管理模块,实时动态调整 tcmalloc 内存 Release Rate,尽早释放内存,避免存储引擎获取 cache 过程阻塞变慢。

案例 2.万亿级数据量 mongodb 集群性能数倍提升优化实践

业务背景:

  • 集群存储离线数据

  • 集群总数据量万亿级

  • 前期主要为数据写入,要求万亿级数据几周内尽快全部写入集群

  • 后期主要是读流量,单次查询数据条数比较多,要求快速返回

  • 每隔一定时间周期(周为单位)会有持续性大量写入

优化策略 1:基础性优化

  • 分享主题六中读写分离、预分片、wiredtiger 存储引擎优化、session 优化、tcmalloc 使用优化等基础性优化策略同样适用于该集群,具体详见《分享主题六:百万级高并发读写/千亿级数据量 mongodb 集群性能数倍提升优化实践》

优化策略 2:存储模型优化前状况

    优化前数据模型结构如下:

1.{  2.    "_id": ObjectId("5fh2ebd18856960dbac31abc"),  3.    "characteristic": "xxxx",  4.    "key1": "***",  5.    ......  6.    "keyn": "***",  7.}  
复制代码
  • 以上为单条数据的数据模型,该集群总数据量万亿级。

  • 数十万条数据拥有同样的 characteristic 特性,总特性数总计数百万个。

  • 一次性查询数十个 characteristic 很慢。


瓶颈点: 一次性查询数十个 characteristic 特征条件的数据,每个特征拥有数百万数据,一次查询总计千万行数据。由于数据量很大,每行数据几乎全在磁盘,一次查询需要千万次 IO 操作,查询成为瓶颈。  

优化策略 2:第一轮数据存储模型优化:

1.{  2.    "_id": ObjectId("5f29ebd18856960dbac31abc"),  3.    "characteristic": "xxxx"  4.    "group": [  5.           {  6.            "key1": "***"  7.            ......  8.            "keyn": "***"  9.        },   #该characteristic下第一条数据  10.            ......  11.        {  12.            "key1": "***"  13.            ......  14.            "keyn": "***"  15.        } #该characteristic下第n条数据  16.    ]  17.} 
复制代码
  • 该数据模型把相同 characteristic 特性的数十万数据合并到为一条数据,减少磁盘 IO 操作,整个读性能会有近百倍提升。

 

瓶颈点:该轮优化解决了读瓶颈,却引入了新的写瓶颈。

  • 通过 $addToSet 方式向 group 数组中去重追加数据,数据长度越来越长,磁盘 IO 压力越来越大、写性能成为新的瓶颈。

优化策略 2:第二轮数据存储模型优化:

1.{  2.    "_id": ObjectId("5f29ebd18856960dbac31abc"),  3.    "characteristic": "xxxx",  4.    "hashNum": num,     5.    "group": [  6.           {  7.            "key1": "***",  8.            ......  9.            "keyn": "***",  10.        },   #该characteristic下第一条数据  11.            ......  12.        {  13.            "key1": "***",  14.            ......  15.            "keyn": "***",  16.        } #该characteristic下第n条数据  17.    ]  }  
复制代码

   如上,把同一个 characteristic 特征的数十万/数百万数据散列为 500 份,这样合并后 group 数组中也就只包含数百条数据信息,这样合并后单条数据过大、mongodb 单条数据 64M 限制问题、磁盘 IO 过高等瓶颈问题都可以得到解决。

 

总体数据模型优化思路:通过合理的数据合并操作来减少网络 IO、磁盘 IO、mongodb 内核处理时间,最终使读和写达到平衡。


分享主题七:成本节省-记某服务千亿级数据迁移 mongodb,百台 SSD 服务器节省优化实践

成本节省-千亿级数据迁移 mongodb,百台 SSD 服务器节省优化实践

迁移背景:

  • 需要迁移的数据量数千亿级

  • 源集群磁盘紧张,业务写入快,需要快速完成数据迁移

  • 源集群数据存储于高 io ssd 服务器

  • 业务对性能没太高要求

  • 目的 mongodb 集群采用低 io 大容量 sata 盘

 

迁移难点:

  • 如何快速完成数据迁移?

瓶颈点:

  • 由于目的集群为低 io 大容量 sata 盘,迁移太慢,源集群磁盘有写满风险

优化策略:

  • 同步数据到大容量 SSD 中转集群

  • 拷贝中转集群数据到目标大容量 SATA 盘服务器

  • 加载数据

成本节省:

  • mongodb 默认的 snappy 压缩算法压缩比约为 2.2-3.5 倍

  • zlib 压缩算法压缩比约为 4.5-7.5 倍(本次迁移采用 zlib 高压缩算法)

 

千亿级数据迁移 mongodb 收益:

  • 源集群磁盘消耗:目的集群磁盘消耗= 8:1(即使目的 mongo 集群也用 SSD 服务器,成本也可以节省七倍)

  • 源集群物理资源:百台 SSD 服务器

  • 目的 mongodb 集群资源消耗:6 台 SATA 盘服务器

分享主题八:展望-如何实现 mongodb 与 SQL 融合


问题背景:

     随着 mongodb-4.2 版本中对分布式事务的支持,以及 mongodb-4.4 版本产品规划路线图可以看出,mongodb 除了保持 nosql 特性外,还在朝着 newSql 方向前行。但是在实际业务接入中发现以下现象:

  • 开发习惯了 SQL,转 mongodb 语法各种不习惯。

  • 运营和数据分析岗位人员只会写 SQL,不会 mongo 语句。

 

我们能做什么?

  • mongos 代理增加 mongodb 协议和 SQL 转换支持,用最小开发成本满足业务 SQL 需求。

  • 5%-10%左右的 SQL 协议支持,满足 90%的用户需求。

分享主题九:其他-那些年我们踩过的坑


“那些年我们踩过的坑” :      

     实际业务接入 mongodb 数据库过程中,我们踩过很多坑,包括业务不合理使用、不合理运维、集群不合理配置、mongodb 内核踩坑、误操作等,甚至出现过同一个核心业务几次抖动。

 

      本次分享中集群优化只列举了主要的优化过程,实际优化过程比本次分享内容更加复杂,集群更多优化细节及数十例典型踩坑过程将逐步在 Qconf 平台、OPPO 互联网、mongodb 中文社区发布。

 

踩坑不可怕,在踩坑过程中学习,学习过程中减少踩坑

2021 规划:

  国内真正拥有企业级分布式数据库自研能力的公司主要集中在阿里、腾讯头部几家,即使二三线互联网公司也无法做到真正意义上的企业级分布式数据库研发能力,拥抱开源是一个明智的选择。

     mongodb 拥有天然的高可用、分布式扩缩容、机房多活容灾、完善的负载均衡及一致性策略等功能,可以做到最少人力成本满足业务快速增长的需求,个人认为 mongodb 绝对是头部公司以外企业会分布式数据库需求的一个值得信赖的选择。    

正如在Qcon专题:现代数据架构dbaplus、mongodb 中文社区所分享,当前 mongodb 国内影响力待提升最大的问题在于国内真正研究 mongodb 内核实现细节的人太少,造成很多复杂问题无法解决,最终这些”人”的问题演变为“mongodb 问题”。

在此,后续持续性分享业务接入过程中的典型踩坑,同时持续性模块化分析 mongodb 内核设计原理,为 mongodb 国内影响力提升做点实事,具体计划如下(详见:盘点2020 |我要为分布式数据库mongodb在国内影响力提升及推广做点事):

 

代码最能说明 mongo 实现细节,21 年持续分析及优化 mongodb 内核源码:

《mongodb内核设计与实现、性能优化》

https://github.com/y123456yz/reading-and-annotate-mongodb-3.6


发布于: 2021 年 01 月 18 日阅读数: 2130
用户头像

万亿级mongodb集群性能优化实践 2020.10.13 加入

Qcon、Gdevops、dbaplus等讲师,滴滴出行专家工程师/OPPO-mongodb负责人,负责数万亿级mongodb内核研发、性能优化及运维工作。持续分享《MongoDB内核源码设计、性能优化、最佳实践》,https://github.com/y123456yz

评论 (5 条评论)

发布
用户头像
多队列的线程模型是怎么做的?改 MongoDB 的源码么?还是官方已提供配置?
2021 年 01 月 24 日 15:04
回复
需要自己改源码,官方版本只支持一个链接一个线程,和单队列动态线程模型
2021 年 01 月 25 日 09:44
回复
改造的方案有开源的计划么?期待:)
2021 年 01 月 30 日 00:46
回复
近期太忙,等空了,这几个线程模型我做一个demo放社区下,这样不仅仅是mongodb可以用,其他数据库、KV存储等都可以用,这样可以效率最大化
2021 年 02 月 03 日 19:01
回复
用户头像
不错
2021 年 01 月 20 日 09:58
回复
没有更多了
万亿级数据库MongoDB集群性能数十倍提升及机房多活容灾实践