前言
线上某 IOT 核心业务集群之前采用 MySQL 作为主存储数据库,随着业务规模的不断增加,MySQL 已无法满足海量数据存储需求,业务面临着容量痛点、成本痛点问题、数据不均衡问题等。
400 亿该业务迁移 MongoDB 后,同样的数据节省了极大的内存、CPU、磁盘成本,同时完美解决了容量痛点、数据不均衡痛点,并且实现了一定的性能提升。
此外,迁移时候的 MySQL 数据为 400 亿,3 个月后的现在对应 MongoDB 集群数据已增长到 1000 亿,如果以 1000 亿数据规模等比例计算成本,实际成本节省比例会更高。迁移 MongoDB 后,除了解决业务痛点问题,同时也促进了业务的快速迭代开发,业务不在关心数据库容量痛点、数据不均衡痛点、成本痛点等问题。
当前国内很多 mongod 文档资料、性能数据等还停留在早期的 MMAP_V1 存储引擎,实际上从 MongoDB-3.x 版本开始,MongoDB 默认存储引擎已经采用高性能、高压缩比、更小锁粒度的 wiredtiger 存储引擎,因此其性能、成本等优势相比之前的 MMAP_V1 存储引擎更加明显。
一、业务迁移背景
该业务在迁移 MongoDB 前已有约 400 亿数据,申请了 64 套 MySQL 集群,由业务通过 shardingjdbc 做分库分表,提前拆分为 64 个库,每个库 100 张表。主从高可用选举通过依赖开源 orchestrator 组建,MySQL 架构图如下图所示:
说明: 上图中红色代表磁盘告警,磁盘使用水位即将 100%。如上图所示,业务一年多前一次性申请了 64 套 MySQL 集群,单个集群节点数一主三从,每个节点规格如下:
该业务运行一年多时间后,总集群数据量达到了 400 亿,并以每月 200 亿速度增长,由于数据不均衡等原因,造成部分集群数据量大,持续性耗光磁盘问题。由于节点众多,越来越多的集群节点磁盘突破瓶颈,为了解决磁盘瓶颈,DBA 不停的提升节点磁盘容量。业务和 DBA 都面临严重痛点,主要如下:
二、为何选择 MongoDB-附十大核心优势总结
业务遇到瓶颈后,基于 MongoDB 在公司已有的影响力,业务开始调研 MongoDB,通过和业务接触了解到,业务使用场景都是普通的增、删、改、查、排序等操作,同时查询条件都比较固定,用 MongoDB 完全没任何问题。
此外,MongoDB 相比传统开源数据库拥有如下核心优索:
MongoDB 为 schema-free 结构,数据格式没有严格限制。业务数据结构比较固定,该功能业务不用,但是并不影响业务使用 MongoDB 存储结构化的数据。
MySQL 高可用依赖第三方组件来实现高可用,MongoDB 副本集内部多副本通过 raft 协议天然支持高可用,相比 MySQL 减少了对第三方组件的依赖。
MongoDB 是分布式数据库,完美解决 MySQL 分库分表及海量数据存储痛点,业务无需在使用数据库前评估需要提前拆多少个库多少个表,MongoDB 对业务来说就是一个无限大的表(当前我司最大的表存储数千亿数据,查询性能无任何影响)。
此外,业务在早期的时候一般数据都比较少,可以只申请一个分片 MongoDB 集群。而如果采用 MySQL,就和本次迁移的 IOT 业务一样,需要提前申请最大容量的集群,早期数据量少的时候严重浪费资源。
关于 balance:支持自动 balance、手动 balance、时间段任意配置 balance.
关于分片策略:支持范围分片、hash 分片,同时支持预分片。
关于片建类型:支持单自动片建、多字段片建
MongoDB 在设计上根据不同一致性等级需求,支持不同类型的 Read Concern 、Write Concern 读写相关配置,客户端可以根据实际情况设置。此外,MongoDB 内核设计拥有完善的 rollback 机制来保证数据安全性和一致性。
为了适应大规模高并发业务读写,MongoDB 在线程模型设计、并发控制、高性能存储引擎等方面做了很多细致化优化。
网上很多评论还停留在早期 MMAPv1 存储引擎,相比 MMAPv1,wiredtiger 引擎性能更好,压缩比更高,锁粒度更小,具体如下:
更多 WT 存储引擎设计细节可以参考:
对数据的压缩支持 snappy、zlib 算法,在以往线上真实的数据空间大小与真实磁盘空间消耗进行对比,可以得出以下结论:
MongoDB 默认的 snappy 压缩算法压缩比约为 2.2-4.5 倍
zlib 压缩算法压缩比约为 4.5-7.5 倍(本次迁移采用 zlib 高压缩算法)
此外,以线上已有的从 MySQL、Es 迁移到 MongoDB 的真实业务磁盘消耗统计对比,同样的数据,存储在 MongoDB、MySQL、Es 的磁盘占比≈1:3.5:6。
后续会有数千亿 hbase 数据迁移 MongoDB,到时候总结同样数据 MongoDB 和 Hbase 的磁盘消耗比。
MongoDB 天然高可用机制及代理标签自动识别转发功能的支持,可以通过节点不同机房部署来满足同城和异地 N 机房多活容灾需求,从而实现成本、性能、一致性的“三丰收”。更多机房多活容灾的案例详见 Qcon 分享:
MongoDB 客户端访问路由策略由客户端自己指定,该功能通过 Read Preference 实现,支持 primary 、primaryPreferred 、secondary 、secondaryPreferred 、nearest 五种客户端均衡访问策略。
MongoDB-4.2 版本开始已经支持分布式事务功能,当前对外文档版本已经迭代到 version-4.2.11,分布式事务功能也进一步增强。此外,从 MongoDB-4.4 版本产品规划路线图可以看出,MongoDB 官方将会持续投入开发查询能力和易用性增强功能,例如 union 多表联合查询、索引隐藏等。
更多 MongoDB 核心优势细节详见我分享的一篇文章,也欢迎各位参加讨论:
mongodb 源码分析、更多实践案例细节:
话题讨论 | MongoDB 拥有十大核心优势,为何国内知名度远不如 MySQL 高?
top="4384">三、MongoDB 资源评估及部署架构
业务开始迁移 MongoDB 的时候,通过和业务对接梳理,该集群规模及业务需求总结如下:
说明: 数据规模和磁盘消耗按照单副本计算,例如 MySQL 64 个分片,256 个副本,数据规模和磁盘消耗计算方式为:64 个主节点数据量之和、64 个分片主节点磁盘消耗之和。
1、MongoDB 资源评估
分片数及存储节点套餐规格选定评估过程如下:
我司都是容器化部署,以往经验来看,MongoDB 对内存消耗不高,历史百亿级以上 MongoDB 集群单个容器最大内存基本上都是 64Gb,因此内存规格确定为 64G。
业务流量峰值 3-5W/s,考虑到可能后期有更大峰值流量,因此按照峰值 10W/s 写,5w/s 读,也就是峰值 15W/s 评估,预计需要 4 个分片。
MySQL 中已有数据 400 亿,磁盘消耗 30T。按照以网线上迁移经验,MongoDB 默认配置磁盘消耗约为 mysql 的 1/3-1/5,400 亿数据对应 MongoDB 磁盘消耗预计 8T。考虑到 1500 亿数据,预计 4 个分片,按照每个分片 400 亿规模,预计每个分片磁盘消耗 8T。
线上单台物理机 10 多 T 磁盘,几百 G 内存,几十个 CPU,为了最大化利用服务器资源,我们需要预留一部分磁盘给其他容器使用。另外,因为容器组套餐化限制,最终确定确定单个节点磁盘在 7T。预计 7T 节点,4 个分片存储约 1500 亿数据。
由于容器调度套餐化限制,因此 CPU 只能限定为 16CPU(实际上用不了这么多 CPU)。
此外,由于分片集群还有 mongos 代理和 config server 复制集,因此还需要评估 mongos 代理和 config server 节点规格。由于 config server 只主要存储路由相关元数据,因此对磁盘、CUP、MEM 消耗都很低;mongos 代理只做路由转发只消耗 CPU,因此对内存和磁盘消耗都不高。最终,为了最大化节省成本,我们决定让一个代理和一个 config server 复用同一个容器,容器规格如下:
8CPU/8G 内存/50G 磁盘,一个代理和一个 config server 节点复用同一个容器。
2、集群部署架构
由于该业务所在城市只有两个机房,因此我们采用 2+2+1(2mongod+2mongod+1arbiter 模式),在 A 机房部署 2 个 mongod 节点,B 机房部署 2 个 mongod 节点,C 机房部署一个最低规格的选举节点,如下图所示:
说明:
四、业务全量+增量迁移方式
迁移过程由业务自己完成,通过阿里开源的 target="_blank"> top="6470">五、性能优化过程
该集群优化过程按照如下两个步骤优化:数据迁移开始前的提前预优化、迁移过程中瓶颈分析及优化、迁移完成后性能优化。
1、数据迁移开始前的提前预操作
和业务沟通确定,业务每条数据都携带有一个设备标识 ssoid,同时业务查询更新等都是根据 ssoid 维度查询该设备下面的单条或者一批数据,因此片建选择 ssoid。
为了充分散列数据到 4 个分片,因此选择 hash 分片方式,这样数据可以最大化散列,同时可以满足同一个 ssoid 数据落到同一个分片,保证查询效率。
MongoDB 如果分片片建为 hashed 分片,则可以提前做预分片,这样就可以保证数据写进来的时候比较均衡的写入多个分片。预分片的好处可以规避非预分片情况下的 chunk 迁移问题,最大化提升写入性能。
sh.shardCollection("xxx.xxx", {ssoid:"hashed"}, false, { numInitialChunks: 8192} )
复制代码
注意事项: 切记提前对 ssoid 创建 hashed 索引,否则对后续分片扩容有影响。
客户端增加 nearest 配置,从离自己最近的节点读,保证了读的性能。
A 机房业务只配置 A 机房的代理,B 机房业务只配置 B 机房代理,同时带上 nearest 配置,最大化的实现本机房就近读,同时避免客户端跨机房访问代理。
禁用该功能后 ReadConcern majority 将会报错,ReadConcern majority 功能注意是避免脏读,和业务沟通业务没该需求,因此可以直接关闭。
MongoDB 默认使能了 enableMajorityReadConcern,该功能开启对性能有一定影响,参考:
MongoDB readConcern 原理解析
百万级高并发 MongoDB 集群性能数十倍提升优化实践单个容器规格:16CPU、64G 内存、7T 磁盘,考虑到全量迁移过程中对内存压力,内存碎片等压力会比较大,为了避免 OOM,设置 cacheSize=42G。
2、数据全量迁移过程中优化过程
全量数据迁移过程中,迁移速度较块,内存脏数据较多,当脏数据比例达到一定比例后用户读写请求对应线程将会阻塞,用户线程也会去淘汰内存中的脏数据 page,最终写性能下降明显。
wiredtiger 存储引擎 cache 淘汰策略相关的几个配置如下:
由于业务全量迁移数据是持续性的大流量写,而不是突发性的大流量写,因此 eviction_target、eviction_trigger、eviction_dirty_target、eviction_dirty_trigger 几个配置用处不大,这几个参数阀值只是在短时间突发流量情况下调整才有用。
但是,在持续性长时间大流量写的情况下,我们可以通过提高 wiredtiger 存储引擎后台线程数来解决脏数据比例过高引起的用户请求阻塞问题,淘汰脏数据的任务最终交由 evict 模块后台线程来完成。
全量大流量持续性写存储引擎优化如下:
db.adminCommand( { setParameter : 1, "wiredTigerEngineRuntimeConfig" : "eviction=(threads_min=4, threads_max=20)"})
复制代码
3、全量迁移完成后,业务流量读写优化
前面章节我们提到,在容器资源评估的时候,我们最终确定选择单个容器套餐规格为如下:
16CPU、64G 内存、7T 磁盘。
全量迁移过程中为了避免 OOM,预留了约 1/3 内存给 MongoDB server 层、操作系统开销等,当全量数据迁移完后,业务写流量相比全量迁移过程小了很多,峰值读写 OPS 约 2-4W/s。
也就是说,前量迁移完成后,cache 中脏数据比例几乎很少,基本上不会达到 20%阀值,业务读流量相比之前多了很多(数据迁移过程中读流量走原 MySQL 集群)。为了提升读性能,因此做了如下性能调整(提前建好索引):
上面的内核优后后,业务测时延监控曲线变化,时延更加平稳,平均时延也有 25%左右的性能优后,如下图所示:
六、迁移前后,业务测时延统计对比(MySQL vs MongoDB)
总结:
七、迁移成本收益对比
1、MySQL 集群规格及存储数据最大量
原 mysql 集群一共 64 套,每套集群 4 副本,每个副本容器规格:4CPU、16G mem、500G 磁盘,总共可以存储 400 亿数据,这时候大部分节点已经开始磁盘 90%水位告警,DBA 对部分节点做了磁盘容量提升。
总结如下:
2、MongoDB 集群规格及存储数据最大量
MongoDB 从 MySQL 迁移过来后,数据量已从 400 亿增加到 1000 亿,并以每个月增加 200 亿数据。MongoDB 集群规格及存储数据量总结如下:
3、成本对比计算过程
说明: 由于 MySQL 迁移 MongoDB 后,数据不在往 MySQL 中写入,流量切到 MongoDB 时候 MySQL 中大约存储有 400 亿数据,因此我们以这个时间点做为对比时间点。以 400 亿数据为基准,资源消耗对比如下表(每个分片只计算主节点资源消耗,因为 MySQL 和 MongoDB 都是 4 副本):
由于 MongoDB 四个分片还有很多磁盘冗余,该四个分片相比 400 亿数据,还可以写 1100 亿数据。如果按照 1500 亿数据计算,如果还是按照 MySQL 之前套餐规格,则 MySQL 集群数需要再增加三倍,也就是总集群套数需要 64*4=256 套,资源占用对比如下:
4、收益总结(客观性对比)
从上面的内容可以看出,该业务迁移 MongoDB 后,除了解决了业务容量痛点、促进业务快速迭代开发、性能提升外,成本还节省了数倍。成本节省总结如下:
CPU 和内存成本比例:4:1
磁盘成本比例:3.3:1
CPU 和内存成本比例:16:1
磁盘成本比例:3.3:1
从上面的分析可以看出,数据量越大,按照等比例换算原则,MongoDB 存储成本会更低,原因如下:
主要是因为 MongoDB 海量数据存储及高性能原因,索引建好后,单实例单表即使几百亿数据,读写也是 ms 级返回(注意:切记查询更新建好索引)。
此外,由于 MongoDB 分布式功能,对容量评估更加方便,就无需提前一次性申请很多套 mysql,而是根据实际需要可以随时加分片。
MongoDB 存储引擎 wiredtiger 默认高压缩、高性能。
最后,鉴于客观性成本评价,CPU/内存成本部分可能会有争议, 比如 mysql 内存和 CPU 是否申请的时候就申请过大。MongoDB 对应 CPU 也同样存在该问题,例如申请的单个容器是 16CPU,实际上真实只消耗了几个 CPU。
但是,磁盘节省是实实在在的, 是相同数据情况下 mysql 和 MongoDB 的真实磁盘消耗对比。
当前该集群总数据量已经达到近千亿,并以每个月 200 亿规模增加,单从容器计费层面上换算,1000 亿数据按照等比例换算,预计节省成本 10 倍。
八、最后:千亿级中等规模 MongoDB 集群注意事项
九、未来挑战(该集群未来万亿级实时数据规模挑战)
随着时间推移,业务数据增长也会越来越多,单月数据量增长曲线预计会直线增加(当前每月数据量增加 200 亿左右),预计未来 2-3 年该集群总数据量会达到万亿级,分片数也会达到 20 个分片左右,可能会遇到各自各样的问题。
冷热归档存储可以参考之前在 dbaplus 分享的另一篇文章:
1.《用最少人力玩转万亿级数据,我用的就是MongoDB!
2.MongoDB 源码分析、更多实践案例细节
top="12358">九、最后说明(业务场景)
本千亿级 IOT 业务使用场景总结如下:
作者介绍
杨亚洲, 前滴滴出行专家工程师,现任 OPPO 文档数据库 MongoDB 负责人,负责数万亿级数据量文档数据库 MongoDB 内核研发、性能优化及运维工作,一直专注于分布式缓存、高性能服务端、数据库、中间件等相关研发。后续持续分享《MongoDB 内核源码设计、性能优化、最佳运维实践》。
原文链接:千亿数据扛不住,三思后还是从MySQL迁走了……