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

l MongoDB 在 OPPO 互联网推广经验分享 - 如何把一个淘汰边缘的数据库逐步变为公司主流数据库
l 谈谈当前国内对MongoDB 误解(丢数据、不安全、难维护)?
l MongoDB 跨机房多活方案 - 实现成本、性能、一致性 " 三丰收 "
l MongoDB 线程模型瓶颈及其优化方法
l 并行迁移:MongoDB 内核扩容迁移速率数倍 / 数十倍提升优化实践
l 百万级高并发读写/ 千亿级数据量 MongoDB 集群性能数倍提升优化实践
l 万亿级数据量MongoDB 集群性能数十倍提升优化实践
l 磁盘800% 节省 - 记某服务接口千亿级数据迁移 MongoDB ,近百台 SSD 服务器节省原理
l 展望:借助MongoDB 完善的分布式、高可用、机房多活等功能,如何实现 NoSQL 、 NewSQL 融合
l 其他- 那些年我们踩过的坑
分享目录

l 推广经验分享
l 机房多活实现
l 性能优化案例
l 成本优化案例
l 其他
分享主题一 :如何把mongodb 从淘汰边缘变为公司主流数据库?


背景:
l 入职前多个大数据量业务使用mongodb ,使用中经常超时抖动
l 多个核心业务忍受不了抖动的痛苦,准备迁移回mysql 。
l mongodb 口碑差,新业务想用不敢用。
l 入职1 个月,业务迁移 mongodb 到公司其他数据库, mongodb 总集群数减少 1 5 %

我做了啥?
l 从服务层优化、存储引擎优化、部署方式优化等方面入手,逐一解决抖业务抖动问题
l 总结各个集群抖动原因及优化方法,公司内部分享。
l 收集公司所有mongodb 集群对应用户,成立 mongodb 用户群

入职2 月后, mongodb 公司内部状态:
l 之前准备迁移到mysql 的几个核心业务继续使用 mongodb
l 对应业务负责人开始考虑把其他大数据量集群迁移到mongodb
l 越来越多的未使用过mongodb 的部门开始使用 mongodb
入职1 年后, mongodb 相关数据增长:
l 总集群数增长比例:> 700%
l 总数据量增长比例:> 2000%
l 读写流量增长比例:> 550%
l mongodb 用户群用户数增长比例: > 800%
总结:
l mongodb 赢得用户信任原因总结: 口碑
分享主题二 :当前国内对mongodb 误解 ( 丢数据、不安全、难维护 ) ?

l 业务接入过程中经常咨询的几个问题:
1. 误解一. 丢数据
2. 误解二. 不安全,网上一堆说 mongodb 被黑客攻击,截图一堆新闻
3. 误解三. DBA 吐槽 mongodb 太难维护

误解原因:
l mongodb 本身很优秀,但是很多 DBA 和相应开发把控不住
l 国内系统性分析mongodb 内核实现原理相关资料欠缺
l 网络社会以讹传讹,DBA 或者相关开发自身把控不住演变为 mongodb 的锅
分享主题三 : mongodb 机房多活方案 - 实现成本、性能、一致性 " 三丰收 "


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

放弃该方案原因:
l 数据两份、集群两份、物理成本高。三机房、五机房等更多机房多活,成本及复杂性更高。
l 存在一致性问题,两地集群数据不一致,balance 情况下尤为突出
l 由于人力原因,如果开源同步工具出现问题把控不在。
方案一:同城三机房多活方案(1mongod+1mongod+1mongod方式)

l 每个机房代理至少部署2 个,保证业务访问代理高可用
l 如果某机房异常,并且该机房节点为主节点,借助mongodb 天然的高可用机制,其他机房 2 个 mongod 实例会自动选举一个新节点为主节点。
l 客户端配置nearest 就近访问,保证读走本机房节点。
l 弊端:如果是异地机房,B 机房和 C 机房写存在跨机房写场景。如果 A B C 为同城机房,则没用该弊端,同城机房时延可以忽略。
方案二:同城两机房多活方案(2mongod+2mongod+1arbiter模式)

l 每个机房代理至少部署2 个,保证业务访问代理高可用
l 如果机房A 挂掉,则会在 B 机房 mongod 中重新选举一个新的主节点。 arbiter 选举节点不消耗资源
l 客户端配置nearest 参数,保证读走本机房节点
l 弊端:如果是异地机房,B 机房和 C 机房写存在跨机房写场景。如果 A B 为同城机房,则没用该弊端,同城机房时延可以忽略。
方案三:异地三机房多活方案(1mongod+1mongod+1mongod方式)-解决跨机房写


l 每个机房代理通过打标签的方式,代理转发数据到主节点在本机房的分片上去。
l A 机房数据通过标签识别转发到分片 shard-1 , B 机房数据转发到分片 shard-2 , C 机房数据转发到分片 shard-3 。
分享主题四 : mongodb 线程模型瓶颈及其优化方法

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

说明:
l listener 线程负责接受所有的客户端链接
l listener 线程每接收到一个新的客户端链接就创建一个线程,该线程只负责处理该链接请求处理。
该网络线程模型缺陷:
l 一个链接创建一个线程,如果10 万个链接,那么就需要 10 万个线程,系统负责、内存消耗也会很多
l 当链接关闭的时候,线程销毁,频繁的线程创建和消耗进一步增加系统负载
典型案例:
l mysql 默认方式、 mongodb 同步线程模型配置,适用于请求处理比较耗时的场景,如数据库服务
mongodb默认线程模型(动态线程模型:单队列方式)

说明:
l 该模型把一次请求转换为多个任务:mongodb 数据读操作 ( 网络 IO) 、 db 层数据访问 ( 磁盘 IO) 。
l 任务入队到全局队列,线程池中的线程从队列中获取任务执行。
l 同一个请求访问被拆分为多个任务,大部分情况下通过递归调用同一个请求的多个任务会由同一个线程处理;。
l 当任务太多,系统压力大的时候,线程池中线程数动态增加;当任务减少,系统压力减少的时候,线程池中线程数动态减少;
该网络线程模型缺陷:
l 线程池获取任务执行,有全局锁竞争,这里就会成为系统瓶颈
典型案例:
l mongodb 动态 adaptive 线程模型,适用于请求处理比较耗时的场景,如数据库服务
mongodb优化后线程模型(动态线程模型-多队列方式)

说明:
l 把一个全局队列拆分为多个队列,任务入队的时候按照session 链接 hash 散列到各自的队列,工作线程获取获取任务的时候,同理通过同样的 hash 算法去对应的队列获取任务,通过这种方式减少锁竞争,同时提升整体性能。
典型案例:
l mongodb 内核多队列 adaptive 线程模型优化,特定场景性能有很好的提升,适用于请求处理比较耗时的场景,如数据库服务。
分享主题五 : 并行迁移- 集群扩容速率 N 倍提升优化实践

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

并行迁移过程(假设需要迁移的表名为:test , 从 3 节点扩容到 6 节点):
l 选取需要迁移的块,假设源集群有M 分片,扩容新增 N 分片,则一般情况需要迁移的块 =min(M,N)
l 迁移步骤:1. configServer-master 选出需要迁移的块; 2. config.locks 表中 id=test 这条记录上锁; 3. 通知需要迁移的源分片开始迁移; 4. 迁移完成后延时 10s ,重复 1-4 步骤实现持续性 chunk 数据迁移

并行迁移步骤:
说明: 假设需要迁移的表名为test , 源分片数 M ,扩容后新增分片数 N
l configServer-master 选出需要迁移的块,一般 S=min(M, N) ,也就是 M 和 N 中的最小值;
l config.locks 表中获取 id=test 这条记录对应的分布式锁;
l 异步通知需要迁移的S 个源分片开始迁移;
l 等待S 个 chunk 迁移完成
l 迁移完成后延时10 秒
l 重复步骤1-5

并行迁移瓶颈:
l 获取分布式锁时间太长,原因:config.locks 表中 id=test 表的分布式锁可能被其他操作锁住
l configServer 异步通知源分片中的 S 个分片同时开始迁移数据到目的分片,任一个 chunk 迁移慢会拖累整个迁移过程。
l 本批次确认迁移完成后,还需要延时10s ;一般 SSD 服务器,一个 chunk 迁移都在几百 ms 内完成。
优化方法:
l 避免其他操作占用分布式锁,例如splite 我们可以关闭 autoSplite 功能,或者调大 chunksize
l configServer 并行迁移不把多个分片的并行迁移放到同一个逻辑,而是放到各自的逻辑。
l 延时放到各自分片迁移逻辑里面控制,不受全局延时控制
l 分片延时可配置,支持实时动态命令行调整
分享主题六: 性能优化案例

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

业务背景:
l 核心元数据
l 数据量千亿级
l 前期写多读少,后期读多写少
l 高峰期读写流量百万级
l 时延敏感
l 数据增长快,不定期扩容
l 同城多活集群

优化策略1 :部署及使用方式优化
l 预分片,写入负载均衡。
l WriteConcern : { w: "majority"} ,写大部分节点成功才返回客户端 OK
l 读写分离,读从优先。
l 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 检测点,把当前存储引擎脏数据全部记录到磁盘。触发条件如下 :
l 固定周期做一次checkpoint 快照,默认 60s
l 增量journal 日志达到 2G
少部分实例存在如下现象: 一会儿磁盘IO 几乎空闲 0% ,一会儿磁盘 IO 短暂性 100% 。进行如下优化后可以缓解该问题 :
checkpoint=(wait=30,log_size=1GB)
该优化总体思路: 缩短checkpoint 周期,减少 checkpoint 期间积压的脏数据,缓解磁盘 IO 高问题。
遗留问题: SSD 盘只有极少数节点有该问题,原因未知,后续继续跟踪。

瓶颈点:
l 代理缓存所有客户端的链接信息到内存中,并定期更新到config 库的 system.sessions 表中。
l 大流量大数据量集群客户端链接众多,大量更新sessions 表,最终主分片性能下降引起整个集群性能瞬间数倍下降。

优化方法:
l config 库的 system.sessions 表启用分片功能。
l mongos 定期更新优化为散列到不同时间点进行更新。

优化策略4 :
l sharding 集群 system.session 优化
该优化总体思路:
l 之前代理集中式更新单个分片,优化为散列到不同时间点更新多个分片。
l 该优化后system.sessions 表更新引起的瞬间性能数倍降低和大量慢日志问题得到了解决。

优化策略5 : tcmalloc 内存优化
l db.serverStatus().tcmalloc 监控发现部分 mongod 实例 pageheap 、内存碎片等消耗过高。通过系统调用分析得出:内存碎片率、 pageheap 过高,会引起分配内存过程变慢,引起集群性能严重下降。
该优化总体思路:
l 借助gperftools 三方库中 tcmalloc 内存管理模块,实时动态调整 tcmalloc 内存 Release Rate ,尽早释放内存,避免存储引擎获取 cache 过程阻塞变慢。
案例2.万亿级数据量mongodb集群性能数倍提升优化实践

业务背景:
l 集群存储离线数据
l 集群总数据量万亿级
l 前期主要为数据写入,要求万亿级数据几周内尽快全部写入集群
l 后期主要是读流量,单次查询数据条数比较多,要求快速返回
l 每隔一定时间周期( 周为单位 ) 会有持续性大量写入

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

优化策略2 :存储模型优化前状况
优化前数据模型结构如下:
1. {
2. "_id": ObjectId("5fh2ebd18856960dbac31abc"),
3. "characteristic": "xxxx",
4. "key1": "***",
5. ......
6. "keyn": "***",
7. }
l 以上为单条数据的数据模型,该集群总数据量万亿级。
l 数十万条数据拥有同样的characteristic 特性,总特性数总计数百万个。
l 一次性查询数十个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. ]
}
l 该数据模型把相同characteristic 特性的数十万数据合并到为一条数据,减少磁盘 IO 操作,整个读性能会有近百倍提升。
瓶颈点: 该轮优化解决了读瓶颈,却引入了新的写瓶颈。
l 通过$ 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. ]
18. }
如上,把同一个characteristic 特征的数十万 / 数百万 数据散列为500 份,这样合并后 group 数组中也就只包含数百条数据信息,这样合并后单条数据过大、 mongodb 单条数据 64M 限制问题 、 磁盘IO 过高 等瓶颈问题都可以得到解决。
总体数据模型优化思路: 通过合理的数据合并操作来减少网络IO 、磁盘 IO 、 mongodb 内核处理时间,最终使读和写达到平衡。
分享主题七 : 成本节省- 记某服务千亿级数据迁移 mongodb ,百台 SSD 服务器节省优化实践

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

迁移背景:
l 需要迁移的数据量数千亿级
l 源集群磁盘紧张,业务写入快,需要快速完成数据迁移
l 源集群数据存储于高io ssd 服务器
l 业务对性能没太高要求
l 目的mongodb 集群采用低 io 大容量 sata 盘
迁移难点:
l 如何快速完成数据迁移?

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

优化策略:
l 同步数据到大容量SSD 中转集群
l 拷贝中转集群数据到目标大容量SATA 盘服务器
l 加载数据

成本节省:
l mongodb 默认的 snappy 压缩算法压缩比约为 2.2-3.5 倍
l zlib 压缩算法压缩比约为 4.5-7.5 倍 ( 本次迁移采用 zlib 高压缩算法 )
千亿级数据迁移mongodb 收益:
l 源集群磁盘消耗: 目的集群磁盘消耗 = 8:1( 即使目的 mongo 集群也用 SSD 服务器,成本也可以节省七倍 )
l 源集群物理资源: 百台SSD 服务器
l 目的mongodb 集群资源消耗: 6 台 SATA 盘服务器
分享主题八 : 展望- 如何实现 mongodb 与 SQL 融合

问题背景:
随着mongodb-4.2 版本中对分布式事务的支持,以及 mongodb-4.4 版本产品规划路线图可以看出, mongodb 除了保持 nosql 特性外,还在朝着 newSql 方向前行。但是在实际业务接入中发现以下现象 :
l 开发习惯了SQL ,转 mongodb 语法各种不习惯。
l 运营和数据分析岗位人员只会写SQL ,不会 mongo 语句。
我们能做什么?
l mongos 代理增加 mongodb 协议和 SQL 转换支持,用最小开发成本满足业务 SQL 需求。
l 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 内核源码 :
https://github.com/y123456yz/reading-and-annotate-mongodb-3.6