You are on page 1of 49

OPPO万亿级文档数据库MongoDB集群性能

优化实践

OPPO文档数据库MongoDB负责人/杨亚洲
个人介绍
OPPO文档数据库mongodb负责人,前滴滴出行专家工程师,负责万亿
级数据量文档数据库mongodb内核研发及运维工作,mongodb中文社区连续
两期一等奖获得者。
一直专注于分布式缓存、数据库、高性能中间件、KV存储引擎等相
关研发,github账号地址:https://github.com/y123456yz
分享目录
1. 推广经验分享
2. 机房多活实现
3. 性能优化案例
4. 成本优化案例
5. 其他
分享主题一

如何把mongodb从淘汰边缘变为公司主流数据库?
如何把mongodb从淘汰边缘变为公司主流数据库?

入职前mongodb状态:
 集群抖动
 口碑差
 新业务想用不敢用
 业务考虑迁移已有mongodb到其他数据库
 入职一个月内集群数减少15%
如何把mongodb从淘汰边缘变为公司主流数据库?

我做了什么?
 优化集群,解决集群抖动问题
 内部分享性能优化方法
 给重点业务分享mongodb原理
 成立mongodb用户群
 业务痛点问题及其解决方案实时用户群同步
如何把mongodb从淘汰边缘变为公司主流数据库?
入职2月后,mongodb公司内部状态:
 准备迁走的核心业务继续使用mongodb
 大数据量业务开始迁移到mongodb
 越来越多部门开始使用mongodb

入职1年后,mongodb相关数据增长:
 总集群数增长比例:> 700%
 总数据量增长比例:> 2000%
 读写流量增长比例:> 550%
 mongodb用户群用户数增长比例:> 800%

总结:
 mongodb赢得用户信任原因总结: 口碑
分享主题二

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

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

误解一. 丢数据

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

误解三. DBA吐槽mongodb太难维护
谈谈当前国内对mongodb误解(丢数据、不安全、难维护)?

误解原因:
1. mongodb本身很优秀,但是很多DBA和相应开发把控不住
2. 国内系统性的mongodb资料相对欠缺
分享主题三

mongodb机房多活方案-实现成本、性能、一致性"三丰收"
社区mongodb双向同步方案(放弃该方案)

机房A 机房B
客户端 客户端

oppo互联网mongodb:杨亚洲

机房A mongodb 机房B


mongodb集群 同步系统 mongodb集群

放弃该方案原因:
1. 成本高
2. 数据一致性问题
3. 人力原因
方案一:同城三机房多活方案(1mongod+1mongod+1mongod方式)

客户端 A机房Client B机房Client C机房Client


...

代理层 A机房mongos
... B机房mongos C机房mongos...

oppo互联网mongodb:杨亚洲

shard-1 shard-n
存储层 A机房 A机房
mongod(主) mongod(主)

B机房 C机房 B机房 C机房


mongod(从) mongod(从) mongod(从) mongod(从)

1. 代理高可用; 2.任一主机房异常,快速选主
3. nearest就近访问 4. 弊端:异地机房存在跨机房写场景
方案二:同城两机房多活方案(2mongod+2mongod+1arbiter模式)

客户端 A机房Client B机房Client


...

代理层 A机房mongos
... B机房mongos...
oppo互联网mongodb:杨亚洲

shard-1 A机房 A机房 shard-n


存储层 mongod(主) mongod(主)

C机房 C机房
A机房 B机房 B机房 mongod A机房 B机房 B机房 mongod
mongod(从) mongod(从) mongod(从) (arbiter) mongod(从) mongod(从) mongod(从) (arbiter)

1. 代理高可用; 2.任一主机房异常,快速选主
3. nearest就近访问 4. 弊端:异地机房存在跨机房写场景
方案三:异地三机房多活方案(1mongod+1mongod+1mongod方式)-解决跨机房写

客户端 A机房Client B机房Client C机房Client


...

代理层 A机房mongos
... B机房mongos C机房mongos...

oppo互联网mongodb:杨亚洲

shard-1 shard-2 shard-3


A机房 B机房 C机房
mongod(主) mongod(主) mongod(主)
存储层

B机房 C机房 A机房 C机房 B机房 A机房


mongod(从) mongod(从) mongod(从) mongod(从) mongod(从) mongod(从)

1. 每个机房代理通过打标签的方式,代理转发数据到主节点在本机房的分片上去。
2. A机房数据转发到分片shard-1,B机房数据转发到分片shard-2,C机房数据转发到分片
shard-3。
分享主题四

mongodb线程模型瓶颈及其优化方法
mongodb默认线程模型(一个链接一个线程)
worker线程
oppo互联网mongodb:杨亚洲
线程1

listener线程

client客户端
.. 线程2
创建
新连接fd-n
.. 新连接
fd1 线程
...
.. ...
线程n

说明:
1. listener线程负责接受所有的客户端链接
2. listener线程每接收到一个新的客户端链接就创建一个线程,该线程只负责处理该链接请求处理。

该网络线程模型缺陷:
1. 一个链接创建一个线程,如果10万个链接,那么就需要10万个线程,系统负责、内存消耗也会很多
2. 当链接关闭的时候,线程销毁,频繁的线程创建和消耗进一步增加系统负载

典型案例:
1. mysql默认方式、mongodb同步线程模型配置,适用于请求处理比较耗时的场景,如数据库服务
mongodb默认线程模型(动态线程模型:单队列方式)

worker动态线程池
oppo互联网mongodb:杨亚洲
线程1

状态机调 全局队列
线程2
度模块 ..
client请求 ...
..
锁竞
调度 任务n 任务1

...
.. 线程n

说明:
1. 该模型把一次请求转换为多个任务:mongodb数据读操作(网络IO)、db层数据访问(磁盘IO)。
2. 任务入队到全局队列,线程池中的线程从队列中获取任务执行。
3. 同一个请求访问被拆分为多个任务,一次请求可能由多个线程处理。
4. 当任务太多,系统压力大的时候,线程池中线程数动态增加;当任务减少,系统压力减少的时候,线程池中线程数动态减少;

该网络线程模型缺陷:
1. 线程池获取任务执行,有全局锁竞争,这里就会成为系统瓶颈

典型案例:
1. mongodb动态adaptive线程模型,适用于请求处理比较耗时的场景,如数据库服务
mongodb优化后线程模型(动态线程模型-多队列方式)
worker动态线程池
队列1 线程1
任务n
... 任务1 锁1
线程2
...

client请求
队列2 ...
调度
... ...
任务n

...
任务1 锁2
...
. ...
hash散列
. oppo互联网mongodb:杨亚洲

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

典型案例:
1. OPPO自研mongodb内核多队列adaptive线程模型优化,特定场景性能有很好的提升,适用于请求处理比较耗时的场景,如数据库服务。
分享主题五

并行迁移-集群扩容速率N倍提升优化实践
集群扩容速率N倍提升优化实践-优化前
client client mongos竞争获取分布式锁 mongod(
client 主)

config

mongod( mongod
从) (从)

mongos1 mongos2 mongos_n


.....

oppo互联网mongodb:杨亚洲

源分片列表 扩容新增分片列表

mongod( mongod( mongod( mongod( mongod( mongod(


主) 主) ..... 主) 主) 主) ..... 主)

新增分 新增分 新增分


shard_n
shard1 shard2 片1 片2 片n

mongod( mongod( mongod( mongod mongod( mongod mongod( mongod( mongod( mongod mongod( mongod
从) 从) 从) (从) 从) (从) 从) 从) 从) (从) 从) (从)

迁移过程:
1. 多个mongos代理竞争分布式锁,获取锁成功的代理选择源分片列表中的一个分片进行moveChunk操作。注意:同一时刻只会迁移一个分片的数据。
2. 缺陷:由于整个集群同一个时刻只能迁移一个分片数据,所以迁移速度很慢。
并行迁移-集群扩容速率N倍提升优化实践(优化后)
clients client client mongod(
主)

config

mongod( mongod
从) (从)
mongos1 mongos2 mongos_n
.....

oppo互联网mongodb:杨亚洲

源分片列表 扩容新增分片列表

mongod( mongod( mongod( mongod( mongod( mongod(


主) 主) ..... 主) 主) 主) ..... 主)

新增分 新增分 新增分


shard_n
shard1 shard2 片1 片2 片n

mongod( mongod( mongod( mongod mongod( mongod mongod( mongod( mongod( mongod mongod( mongod
从) 从) 从) (从) 从) (从) 从) 从) 从) (从) 从) (从)

并行迁移过程:
1. 在特定代理增加并行迁移配置,该代理可以同时触发迁移源分片列表中多个分片的chunk到目标不同分片。
2. 为了避免冲突和提升迁移速度,同一时刻源分片列表中任一分片只能同时迁移一个chunk。同理,目标分片列表中的分片同一时刻只能接受一个chunk。
分享主题六:性能优化案例

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

业务背景:
1. 核心元数据
2. 数据量千亿级
3. 前期写多读少,后期读多写少
4. 高峰期读写流量百万级
5. 时延敏感
7. 数据增长快,不定期扩容
8. 同城多活集群
案例1.千亿级数据量mongodb集群性能数倍提升优化实践-优化过程

优化策略1:部署及使用方式优化
1. 预分片,写入负载均衡。

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

3. 读写分离,读从优先。

4. enableMajorityReadConcern关闭,有性能损耗。
案例1.千亿级数据量mongodb集群性能数倍提升优化实践-优化过程
优化策略2:存储引擎cache淘汰策略优化
wiredtiger存储引擎cache淘汰策略相关的几个配置如下:
wiredtiger淘汰相关配置 默认值 工作原理
eviction_target 80% 当用掉的内存超过总内存的百分比
到 eviction_target,后台evict线程开始淘汰
eviction_trigger 95% 当用掉的内存超过总内存的 eviction_trigger,用
户线程也开始淘汰
eviction_dirty_target 5% 当cache中脏数据比例超过 eviction_dirty_target,
后台evict线程开始淘汰
eviction_dirty_trigger 20% 当cache中脏数据比例超过 eviction_dirty_trigger,
用户线程也开始淘汰
evict.threads_min 4 后台evict线程最小线程数
evict.threads_max 4 后台evict线程最小线程数

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淘汰线程数加快脏数据淘汰,避免
用户请求线程进行脏数据淘汰。
案例1.千亿级数据量mongodb集群性能数倍提升优化实践-优化过程
优化策略3:存储引擎checkpoint优化
存储引擎checkpoint检测点,把当前存储引擎脏数据全部记录到磁盘。触发条件如下:
1.固定周期做一次checkpoint快照,默认60s
2.增量journal日志达到2G

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

该优化总体思路:缩短checkpoint周期,减少checkpoint期间积压的脏数据,缓解磁盘IO高问题。
遗留问题:SSD盘只有极少数节点有该问题,原因未知,后续继续跟踪。
案例1.千亿级数据量mongodb集群性能数倍提升优化实践-优化过程
客户端 Client Client Client

代理层 A机房mongos
... B机房mongos C机房mongos...

system.sessions优化:
oppo互联网mongodb:杨亚洲
优化前架构图

存储层
shard-1
A机房mongod .. A机房mongod
shard-n

.
B机房mongod C机房mongod B机房mongod C机房mongod

瓶颈点:
1. 代理缓存所有客户端的链接信息到内存中,并定期更新到config库的system.sessions表中。
2. 大流量大数据量集群客户端链接众多,大量更新sessions表,最终主分片性能下降引起整个集群性能瞬间数倍下
降。
案例1.千亿级数据量mongodb集群性能数倍提升优化实践-优化过程

客户端 Client Client Client

代理层 A机房mongos
... B机房mongos C机房mongos...

system.sessions优化: oppo互联网mongodb:杨亚洲
优化后架构图

存储层
shard-1
A机房mongod .. A机房mongod
shard-n

.
B机房mongod C机房mongod B机房mongod C机房mongod

优化方法:
1. config库的system.sessions表启用分片功能。
2. mongos定期更新优化为散列到不同时间点进行更新。
案例1.千亿级数据量mongodb集群性能数倍提升优化实践-优化过程

优化策略4:sharding集群system.session优化

该优化总体思路:
1. 之前代理集中式更新单个分片,优化为散列到不同时间点更新多个分片。
2. 该优化后system.sessions表更新引起的瞬间性能数倍降低和大量慢日志问题得到了解决。
案例1.千亿级数据量mongodb集群性能数倍提升优化实践-优化过程

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

该优化总体思路:
借助gperftools三方库中tcmalloc内存管理模块,实时动态调整tcmalloc内存Release Rate,
尽早释放内存,避免存储引擎获取cache过程阻塞变慢。
案例2.万亿级数据量mongodb集群性能数倍提升优化实践

业务背景:
1. 集群存储离线数据
2. 集群总数据量万亿级
3. 前期主要为数据写入,要求万亿级数据几周内尽快全部写入集群
4. 后期主要是读流量,单次查询数据条数比较多,要求快速返回
5. 每隔一定时间周期(周为单位)会有持续性大量写入
案例2.万亿级数据量mongodb集群性能数倍提升优化实践

优化策略1:基础性优化
分享主题六中读写分离、预分片、wiredtiger存储引擎优化、session优化、tcmalloc
使用优化等基础性优化策略同样适用于该集群,具体详见《分享主题六:百万级高并发读写/千
亿级数据量mongodb集群性能数倍提升优化实践》
案例2.万亿级数据量mongodb集群性能数倍提升优化实践
优化策略2:存储模型优化前状况
优化前数据模型结构如下:
{
"_id": ObjectId("5fh2ebd18856960dbac31abc"),
"characteristic": "xxxx",
"key1": "***",
......
"keyn": "***",
}
1. 以上为单条数据的数据模型,该集群总数据量万亿级。
2. 数十万条数据拥有同样的characteristic特性,总特性数总计数百万个。
3. 一次性查询数十个characteristic很慢。

瓶颈点: 一次性查询数十个characteristic特征条件的数据,每个特征拥有数百万数据,一次查询总计千万行数据。由于数据量很
大,每行数据几乎全在磁盘,一次查询需要千万次IO操作,查询成为瓶颈。
案例2.万亿级数据量mongodb集群性能数倍提升优化实践

优化策略2:第一轮数据存储模型优化:
{
"_id": ObjectId("5f29ebd18856960dbac31abc"),
"characteristic": "xxxx"
"group": [
{
"key1": "***"
......
"keyn": "***"
}, #该characteristic下第一条数据
......
{
"key1": "***"
......
"keyn": "***"
} #该characteristic下第n条数据
]
}
该数据模型把相同characteristic特性的数十万数据合并到为一条数据,减少磁盘IO操作,整个读性能会有近百倍提升。

瓶颈点:该轮优化解决了读瓶颈,却引入了新的写瓶颈。
1. 通过$addToSet方式向group数组中去重追加数据,去重遍历过程越来越慢,数据长度越来越长,写性能成为新的瓶颈。
案例2.万亿级数据量mongodb集群性能数倍提升优化实践
优化策略2:第二轮数据存储模型优化:
{
"_id": ObjectId("5f29ebd18856960dbac31abc"),
"characteristic": "xxxx",
"heshNum": num,
"group": [
{
"key1": "***",
......
"keyn": "***",
}, #该characteristic下第一条数据
......
{
"key1": "***",
......
"keyn": "***",
} #该characteristic下第n条数据
]
}
如上,把同一个characteristic特征的数十万数据散列为500份,这样合并后group数组中也就只包含数百条数据信息,这
样$addToSet去重遍历、合并后单条数据过大、mongodb单条数据64M限制问题等瓶颈问题都可以得到解决。

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

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

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

迁移难点:
 如何快速完成数据迁移?
成本节省-千亿级数据迁移mongodb,百台SSD服务器节省优化实践

写入快
Client 源集群/SSD

单向同步系统 迁移慢

目的mongo集群/SATA

瓶颈点:
 由于目的集群为低io大容量sata盘,迁移太慢,源集群磁盘有写满风险
成本节省-千亿级数据迁移mongodb,百台SSD服务器节省优化实践
写入快
Client 源集群/SSD

单向同步系统 同步快
加载数据
拷贝数
据文件
中转mongo集群/大容量SSD 目标mongo大容量SATA集群

优化策略:
 同步数据到大容量SSD中转集群
 拷贝中转集群数据到目标大容量SATA盘服务器
 加载数据
成本节省-千亿级数据迁移mongodb,百台SSD服务器节省优化实践

成本节省:
 mongodb默认的snappy压缩算法压缩比约为2.2-3.5倍
 zlib压缩算法压缩比约为4.5-7.5倍(本次迁移采用zlib高压缩算法)

千亿级数据迁移mongodb收益:
 源集群磁盘消耗:目的集群磁盘消耗 = 8:1(即使目的mongo集群也用SSD服务器,成本也可以节省七倍)
 源集群物理资源:百台SSD服务器
 目的mongodb集群资源消耗:6台SATA盘服务器
分享主题八

展望-如何实现mongodb与SQL融合
展望:如何实现mongodb与SQL融合

问题背景:
随着mongodb-4.2版本中对分布式事务的支持,以及mongodb-4.4版本产品规划路线图可以看出,
mongodb除了保持nosql特性外,还在朝着newSql方向前行。但是在实际业务接入中发现以下现象:
1. 开发习惯了SQL,转mongodb语法各种不习惯。
2. 运营和数据分析岗位人员只会写SQL,不会mongo语句。

我们能做什么?
1. mongos代理增加mongodb协议和SQL转换支持,用最小开发成本满足业务SQL需求。
2. 5%-10%左右的SQL协议支持,满足90%的用户需求。
分享主题九

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

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

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

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

You might also like