Qcon 现代数据架构 -《万亿级数据库 MongoDB 集群性能数十倍提升优化实践》核心 17 问详细解答
关于作者
前滴滴出行技术专家,现任 OPPO 文档数据库 mongodb 负责人,负责 oppo 千万级峰值 TPS/十万亿级数据量文档数据库 mongodb 内核研发及运维工作,一直专注于分布式缓存、高性能服务端、数据库、中间件等相关研发。Github 账号地址:https://github.com/y123456yz
说明:
本文在 2020 年深圳 Qcon 全球软件开发大会《专题:现代数据架构》专场、mongodb2020 年终盛会、dbaplus 分享后,获得一致好评。本文整理了会后众多 mongodb 数据库用户提的频率最高的 17 个问题,并通过本文对每个问题进行了详细解答,一并整理到本文中。
具体分享内容详见:万亿级数据库MongoDB集群性能数十倍提升及机房多活容灾实践
分享内容回顾如下:
MongoDB 在 OPPO 互联网推广经验分享-如何把一个淘汰边缘的数据库逐步变为公司主流数据库
谈谈当前国内对 MongoDB 误解(丢数据、不安全、难维护)?
MongoDB 跨机房多活方案-实现成本、性能、一致性"三丰收"
MongoDB 线程模型瓶颈及其优化方法
并行迁移:MongoDB 内核扩容迁移速率数倍/数十倍提升优化实践
百万级高并发读写/千亿级数据量 MongoDB 集群性能数倍提升优化实践
万亿级数据量 MongoDB 集群性能数十倍提升优化实践
磁盘 80%节省-记某服务接口千亿级数据迁移 MongoDB,近百台 SSD 服务器节省原理
具体分享内容详见:
万亿级数据库MongoDB集群性能数十倍提升及机房多活容灾实践
关于作者
前滴滴出行技术专家,现任 OPPO 文档数据库 mongodb 负责人,负责数万亿级数据量文档数据库 mongodb 内核研发、性能优化及运维工作,一直专注于分布式缓存、高性能服务端、数据库、中间件等相关研发。后续持续分享《MongoDB 内核源码设计、性能优化、最佳运维实践》,Github 账号地址:https://github.com/y123456yz
提问 1. 性能优化有推荐的分析和监控工具么?
mongodb 常用性能分析主要如下:
1.1 mongodb 自带性能分析工具
mongodb 官方对外工具 mongostat
命令行使用方法(ip:port 为代理 ip 和端口):
mongostat -h ip:port -u 用户名-p 密码 --authenticationDatabase=admin --discover
mongostat 工具带上--discover,可以把所有分片节点信息一起打印出来,直观查看整个集群所有节点实例级监控信息。mongostat 统计信息中最核心的几个影响性能的统计项:
dirty:存储引擎脏数据比例,默认该值为 5%的时候,wiredtiger 存储引擎自带的 evict 现成开始选择脏数据 page 淘汰到磁盘;如果该值达到 20%,客户端请求对应 mongodb 处理现成将会选择脏数据 page 淘汰到磁盘,等 page 淘汰腾出内存空间后,才会处理客户端请求的 DB 访问,所以如果阀值达到 20%客户端访问将会变慢。
used:存储引擎 cacheSize 配置占用百分比,如果配置 cacheSize=10G,存储引擎实际使用了 7G,则 used 赞比为 70%。当该统计值达到 80%,evict 线程将会触发选择涨数据淘汰,如果这个占比提高到 95%,用户请求线程将会触发淘汰,客户端请求将会变慢。
qrw arw:等待队列数,如果该值越大,说明会引起客户端请求排队处理。一般该值会再 dirty 占比超过 20%,used 占比过高超过 95%,或者磁盘 IO 慢会出现。
vsize res:虚拟内存和物理内存真实占用,如果 vsize 过高,远远超过 res,或者 res 过高,远远超过 cachesize 配置,则说明内存碎片,pageheap 等问题,这时候可以通过加速 tcmalloc 内存释放速率来解决问题。
慢日志分析
通过以下命令分析日志文件
找出文件末尾 1000000 行中存在扫表的操作,不包含 oplog,getMore
tail mongod.log -n 1000000 | grep ms |grep COLLSCAN |grep -v "getMore" | grep -v "oplog.rs"
找出文件末尾 1000000 行中所有的慢日志,不包含 oplog,getMore
tail mongodb.log -n 1000000 |grep ms | grep op_msg | grep find | grep -v "oplog.rs" |grep -v "getMore"
找出文件末尾 1000000 行中执行时间 1-10s 的请求,不包含 oplog,getMore
tail mongodb.log -n 1000000 |grep ms | grep op_msg | grep find | grep -v "oplog.rs" |grep -v "getMore" | egrep [1-9][0-9][0-9][0-9]ms
currentOp 正在执行的慢操作分析
慢日志只有当请求执行完毕才会,如果一个表很大,一个查询扫表,则整个执行过程可能需要数小时,可能还没记录慢日志,则可以通过如下命令获取当前执行时间超过 5s 的所有请求,查询请求,command 请求:
db.currentOp({"secs_running":{"$gt":5}})
db.currentOp({"secs_running":{"$gt":1}, "op":"query"})
db.currentOp({"secs_running":{"$gt":5}, "op":"command"})
kill 查询时间超过 5s 的所有请求:
db.currentOp().inprog.forEach(function(item){if(item.secs_running > 5 )db.killOp(item.opid)})
节点存储引擎监控信息
db.serverStatus().wiredTiger 可以获取 mongod 节点对应存储引擎的各自详细统计信息,里面可以完整获取时延消耗在存储引擎哪一个环节。
下面是空余时间分析的 wiredtiger 源码,分析不是很完整,后续等 mongodb server 层单机、复制集、分片等完整模块化分析后,会回头继续分析。
1.2 操作系统性能瓶颈分析
系统层面性能分析工具主要有:top、iostat、pstak、ptress、perf、iotop、isof 等,具体请参考对应工具说明。
1.3 开源 mongodb 详细监控套记
开源方案可以参考以下组件:
Grafana+Prometheus+node_exporter+mongodb_exporter
服务端组件:
Prometheus #服务端
Grafana #前端展示
客户端组件:
node_exporter
mongodb_exporter
提问 2. 会话加标签是怎么指定服务器?
举一个例子形象说明:我们把用户分为三组,20 岁以下(junior),20 到 40 岁(middle)和 40 岁以上(senior),按照下面的几条命令执行以后,我们的数据会按照用户年龄段拆分成若干个 chunk,并分发到不同的 shard cluster 中。
如果对下面的命令不熟悉,可以查看 MongoDB 官方文档关于 Shard Zone/Chunk 的解释。
sh.addShardTag('shard01', 'junior')
sh.addShardTag('shard02', 'middle')
sh.addShardTag('shard03', 'senior')
sh.addTagRange('test.users', {'user.age': MinKey}, {'user.age':20}, 'junior')
sh.addTagRange('test.users', {'user.age': 21}, {'user.age':40}, 'middle')
sh.addTagRange('test.users', {'user.age': 41}, {'user.age': MaxKey}, 'senior')
通过上面的 6 个命令给'test 库的 user 表加标签,20 以下对应标签为'junior',21-40 对应标签为'middle',41 以上对应标签为'senior'。同时把'junior'标签分配给'shard01',也就是 0-20 岁的 user 会全部写到'shard01',21-40 岁的 user 会全部写到'shard01',41 岁以上的 user 会全部写到'shard01'。
这样就可以解决跨机房写的问题,只要对应分片主节点在对应机房即可。
提问 3. 脏数据比例多少算高?
默认 20%算高,如果脏数据比例持续性超过 20%,可以试着提高 wiredtiger 存储引擎后台淘汰线程数:
db.adminCommand( { setParameter : 1, "wiredTigerEngineRuntimeConfig" : "cache_size=35GB, eviction=(threads_min=4, threads_max=12)"})
提问 4. 写分开,会有时延吗,是不是有一致性问题?
一致性默认完全由 mongodb 复制集自带的主从同步机制来保证最终一致性,不存在双向同步两集群的一致性问题。
如果要实现复制集中主从节点的强一致性,可以通过客户端配置 writeconcern 策略来解决。
提问 5. 比如想定位详细的慢查询呢?
和问题 1 雷同,可以通过分析 currentop、日志文件或者 system.profile 慢日志表来获取详细的慢日志信息。
建议平台化收集慢日志,这样界面展示分析更加直观。
提问 6. 如何快速定位 Mongodb 的问题发生在集群中的哪些节点? 在启用读写分离的情况下?
主要通过如下几个步骤来分析:
db.serverStatus().opLatencies 监控 mongod 实例时延
如果由运维研发能力,可以自己收集时延展示,如果没有。则可以借助开源工具系统实现,参考《1.3 开源 mongodb 详细监控套记》
充分利用 mongostat 监控集群所有节点实时脏数据、队列、内存信息
参考《1.1 mongodb 自带性能分析工具》
慢日志分析
参考《比如想定位详细的慢查询呢?》
提问 7. 杨老师,就您经验来讲,您觉得如何保证 MongoDB 的安全性呢?
安全性方面主要由以下几方面保证:
账号鉴权认证,一个库一个账号
readWrite 权限去除删库、删表等危险操作权限
不同业务不混用同一个集群
启用黑白名单功能
我司 mongodb 内核增加审计、流量控制、危险操作控制等功能(注:部分功能是 mongodb 企业级功能,需要付费,可以使用 percona mongodb 版本)
数据定期备份,我司 mongodb 内核增加有热备功能。
注意:
如果数据量很大,建议不要使用 mongodump 备份,mongodump 备份会很慢,同时通过 mongorestore 恢复也是一条数据一条数据恢复,同样很慢。如果有内核研发能力,可以增加热备功能。
如果没有内核研发能力,可以通过如下步骤备份:1.隐藏节点;2.锁库;3.拷贝数据文件。或者采用 percona mongodb 版本来备份。
提问 8. mysql 和 mongodb 双写的话怎么保证事务呢
mysql 我不是很了解,mongodb 不推荐搭两集群双向同步来备份,直接利用 mongodb 原生的复制集功能来完成多活容灾,成本、性能、一致性都可以得到保证。即使是 4.2 分布式事务功能也可以直接利用 mongodb 自身的机制来保证,具体方案参考我在 Qcon 全球软件开发大会的分享:
提问 9. hashnum 的方式来讲数组中的方式来拆分成多个表? 没太明白
分享的案例2:万亿级数据量mongodb集群性能数倍提升优化实践,不是拆分数据到多个表,而是把一条数据(该数据保护一个数组,数组中包含数百万个子文档)通过 hash 的方式散列为多条数据。也就是之前数百万个子文档归属于一条数据,现在把他拆分为归属到多条数据。
通过这样合理的数据合并和拆分,最终平衡磁盘 IO,实现读和写达到一种平衡态,既能满足业务读需求,同时也能满足业务写需求。
提问 10. 对分片键设计要求高吗?
分片集群片建选择非常重要,对分片模式集群性能起着核心至关重要的作用,分片集群片建选择遵循以下几个原则:
首先需要考虑集群部署是否需要分片?
只有以下情况才需要分片功能:1.数据量太大,一个分片撑不住;2.写流量太大,写只能走主节点,一个主节点撑不住,需要扩分片分担写流量。
片建选择原则?
片建选择原则如下: 1.保证数据尽量离散;2.尽量保证更新和查询到同一个分片(如果同一次更新或者查询到多个分片,只要任何一个分片慢,该操作都会慢;同时部分查询会进一步加剧代理聚合负担)。
此外,如果查询注意是范围查询,建议选择范围分片,这样有利于范围数据集中到同一个分片。
提问 11. 大表分片后,写表还是会跨机房吗?
机房多活打标签方式解决跨机房写问题,同样可以对对应 tag 表启用分片功能,保证数据到指定的多个分片,每个分片主节点在指定机房,可以解决跨机房问题。详情参考:《会话加标签是怎么指定服务器?》
提问 12. 老师您好,想请问下:MongoDB 适合做商城 app 数据库吗?一般在哪些场景使用呢?谢谢!
个人觉得完全可以满足要求,同时还有利于业务的快速迭代开发。mongodb 天然的模式自由(加字段方便)、高可用、分布式扩缩容、高压缩存储引擎、机房多活容灾机制,可以快速推进业务迭代开发。以我的经验,至少 90%以上使用 mysql 的场景,mongodb 同样可以满足要求。mongodb 唯一缺点可能是生态没 mysql 健全,研究 mongodb 的人没 mysql 多。
提问 13. 老师能讲讲你们容量预警是怎么做的吗?
容量水位我们分为以下几种:
磁盘容量限制
当一个分片中磁盘使用率超过 80%,我们开始扩容增加分片。
流量超过阀值
读写流量阀值水位如下:1.如果是分片的写流量持续性超过 3.5W/s(ssd 服务器)则扩容分片;2.如果是读流量单节点持续性超过 4W/s(ssd 服务器,所有读走磁盘 IO),则扩容从节点来解决读流量瓶颈,注意需要配置读写分离。
CPU 阀值
我们所有实例容器部署,实例如果 CPU 使用率持续性超过 80%,考虑增加容器 CPU。
提问 14. 数据一致性在迁移过程中同步你们是怎么保证的呢
如果通过 mongoshake 等工具迁移集群,需要提前关闭 blance 功能,否则无法解决一致性问题。
我们线上集群只有把数据从集群迁移到另一个集群的时候才会使用 mongoshake,我们机房多活不是多个集群双写方式,而是同一个集群,通过夫直接的主从同步拉取 oplog 机制实现一致性,所以不存在一致性问题。可以参考 万亿级数据库MongoDB集群性能优化及机房多活容灾实践
提问 15. 我们数据体量不太大,主要是杂,这种环境想做好数据治理,老师你建议把重点放在哪些方面?然后有没有一些比较常见的坑?
数据量不大,比较杂的场景,一般集群搞一个复制集即可满足要求,无需分片模式部署。
我猜测你们的比较杂可能是利用 mongodb 的模式自由,造成每条数据的字段各不相同,数据长度大小各不一致。建议在使用模式自由这一功能的时候,一定不要”滥用”、”乱用”,在使用时代码逻辑需要简单控制。我重节线上遇到的对模式自由的”滥用”、”乱用”引起的集群问题:
同一个表的数据的字段控制在 50 个 KV 以内,这样对应更新、查询等性能分析有利,减少磁盘 IO 消耗。
如果数据字段过多,查询的时候不要返回所有字段,只获取对本次查询有用的字段,减少忘了 IO 开销。
数组别乱用,数组中的文档保持格式统一。
数组中的子文档如果需要查询指定字段,一定记得对数组中嵌套的字段添加子索引。
数组字段中的文档一定要控制在一定范围,避免该数组过大,数组过大有遍历、磁盘 IO 过高等问题。
嵌套子文档层数不宜过多。
......
提问 16. 现在有多大数据量?
公司内部 mongodb 规模已经比较大了,总体几万亿级。
提问 17. 你们对这个大数据平台有多少开发人员?
我们研发+运维人员很少,mongodb 拥有天然的高可用、分布式扩缩容、机房多活容灾等功能,同时存储引擎默认数据高压缩,保证了可以用很少的人力来满足公司快速增长的业务需求。此外,mongodb 的高压缩、高性能存储引擎还可以对成本数倍节省起到保障作用。
18 最后:个人 2021 年规划(为 mongodb 国内推广及影响力提升做点事)
国内真正拥有企业级分布式数据库自研能力的公司主要集中在阿里、腾讯头部几家,即使二三线互联网公司也无法做到真正意义上的企业级分布式数据库研发能力,拥抱开源是一个明智的选择。
mongodb 拥有天然的高可用、分布式扩缩容、机房多活容灾、完善的负载均衡及一致性策略等功能,可以做到最少人力成本满足业务快速增长的需求,个人认为 mongodb 绝对是头部互联网公司以外企业对分布式数据库需求的一个值得信赖的选择。
正如在Qcon专题:现代数据架构、dbaplus、mongodb 中文社区所分享,当前 mongodb 国内影响力待提升最大的问题在于国内真正研究 mongodb 内核实现细节的人太少,造成很多复杂问题无法解决,最终这些”人”的问题演变为“mongodb 问题”。
在此,后续持续性分享业务接入过程中的典型踩坑,同时持续性模块化分析 mongodb 内核设计原理,为 mongodb 国内影响力提升做点实事,具体计划如下(详见:盘点2020 |我要为分布式数据库mongodb在国内影响力提升及推广做点事):
18.1 短期目标
短期目标主要是把我司数万亿级数据量 mongodb 业务接入过程所遇到的核心踩坑过程、性能优化案例、机房多活案例等分享到社区,避免国内其他 mongodb 用户踩同样的坑,这些核心踩坑点也是分享中相关听众最关心的点,主要如下:
300 条数据操作引发的血案-记一次线上 300 条数据变更操作引起某 10 亿级 mongodb 核心集群不可用故障。
主节点持续性 OOM-记一次业务排序操作不合理使用引起的核心 mongodb 集群故障。
千亿级/万亿级集群最优索引添加方法-记一次数十亿级核心集群后台索引添加引起的集群抖动及快速恢复过程。
链接数耗光如何快速恢复集群-记一次百亿级核心集群链接数耗光的快速自救过程。
mongodb 机房多活方案-实现成本、性能、一致性"三丰收"。
mongodb 线程模型瓶颈及其优化方法。
并行迁移-集群扩容速率 N 倍提升优化实践。
千亿级核心元数据 mongodb 集群性能数倍提升优化实践。
万亿级数据量 mongodb 集群性能数十倍提升优化实践。
成本节省-记某服务千亿级数据迁移 mongodb,百台 SSD 服务器节省优化实践。
如何快速完成数千亿数据从 SSD 高 IO 服务器迁移到 SATA 盘低 IO 服务器?
。。。。。。
期望完成时间:2021 年 4-5 月
18.2 中期目标
完成 Qcon、知乎、github、itpub 中专栏《mongodb 内核源码实现、性能调优、最佳运维实践系列》中核心文章的分享。
没有什么比源码更有说明力,完成 github 中 mongodb 内核源码中文注释分析:
期望完成时间:2021 年 11 月
18.3 年度目标
期望通过对 mongodb 核心内核核心技术内幕的分享整理,完成如下系列文章或者书籍的编写整理:
《分布式 mongodb 数据库内核设计与实现》
《分布式 mongodb 数据库最佳运维实践》
期望完成时间:2021 年 12 月底
18.4 公司内部目标
公司自研 mongodb 内核深度优化,最大化解决高并发大流量、大数据量情况下扩容过程的抖动问题。
快速掌握 mongodb-4.2 分布式事务实现原理,开始大力推广分布式事务功能。
持续分享内部推广过程中的集群踩坑、性能优化等案例到社区。
其他
期望完成时间:全
版权声明: 本文为 InfoQ 作者【杨亚洲(专注mongodb及高性能中间件)】的原创文章。
原文链接:【http://xie.infoq.cn/article/0c51f3951f3f10671d7d7123e】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论 (2 条评论)