当前位置: 首页 > 科技观察

上千亿的数据搞不定,三思而后从MySQL搬走了...

时间:2023-03-13 19:03:30 科技观察

前言上线某IOT核心业务集群,之前使用MySQL作为主存储数据库。随着业务规模的不断扩大,MySQL已经不能满足海量数据的存储需求,业务面临容量痛点、成本痛点、数据不均衡等问题。400亿业务迁移到MongoDB后,同样的数据保存大量的内存、CPU、磁盘成本,同时完美解决了容量和数据不平衡的痛点,取得了一定的性能提升。另外,迁移时的MySQL数据是400亿条。三个月后,对应的MongoDB集群数据已经增长到1000亿。如果按照1000亿数据规模的比例计算成本,实际节省成本的比例会更高。迁移MongoDB后,除了解决业务痛点,也促进了业务的快速迭代发展。企业不再关心数据库容量痛点、数据不平衡痛点、成本痛点。目前国内很多mongod文档和性能数据还停留在早期的MMAP_V1存储引擎。事实上,从MongoDB-3.x版本开始,MongoDB默认的存储引擎就采用了高性能、高压缩比、锁粒度更小的wiredtiger存储。引擎,因此其性能、成本等优势较之前的MMAP_V1存储引擎更为明显。一、业务迁移背景业务在迁移MongoDB之前有大约400亿条数据,申请了64套MySQL集群。业务通过shardingjdbc分库分表,提前分库分库64个,每个分库100张表。master-slave高可用选举是依赖开源的orchestrator建立的。MySQL架构图如下图所示:注:上图中红色代表磁盘告警,磁盘使用率即将达到100%。如上图所示,业务一年多前一次性申请了64套MySQL集群。单个集群节点数为一主三从。各节点规格如下:cpu:4mem:16Gdisk:500G节点总数:64*4=256台SSD服务器本业务运行一年多后,集群总数据量达到40亿,并以每月200亿的速度增长。由于数据不均衡等原因,部分集群存在数据量大,持续消耗所有磁盘的问题。由于节点数量众多,越来越多的集群节点磁盘突破了瓶颈。为了解决磁盘瓶颈,DBA不断增加节点磁盘容量。业务和DBA都面临着严重的痛点,主要表现为:数据不平衡问题节点容量问题成本持续增加DBA工作量剧增(部分磁盘无法升级,数据需要迁移到新节点),商家也很担心。2、为什么选择MongoDB附十大核心优势总结业务遇到瓶颈后,基于MongoDB在公司已有的影响力,业务开始考察MongoDB。通过接触业务了解到,业务使用场景是常见的增删改查、查询、排序等操作,查询条件比较固定,用MongoDB完全没有问题。此外,与传统开源数据库相比,MongoDB还有以下核心优势:优势一:SchemaFreeMongoDB是无模式结构,数据格式没有严格限制。业务数据结构相对固定。该功能业务未使用,但不影响业务使用MongoDB存储结构化数据。优势二:天然高可用支持MySQL高可用依赖第三方组件实现高可用。MongoDB副本集中的多副本通过Raft协议天然支持高可用,相比MySQL减少了对第三方组件的依赖。优势三:分布式——解决分库分表、海量数据存储痛点MongoDB是分布式数据库,完美解决了MySQL分库分表、海量数据存储痛点。业务不需要评估在使用数据库之前需要拆除多少个数据库。表,MongoDB对业务来说是一个无限大的表(目前我们最大的表存储了上千亿的数据,查询性能没有影响)。另外在业务初期,一般数据比较少,只能申请分片的MongoDB集群。但是如果使用MySQL,就像这次迁移的IOT业务一样,需要提前申请一个容量最大的集群,在前期数据量不大的情况下会严重浪费资源。优势四:完善的数据平衡机制,不同的分片策略,支持多种分片类型。关于余额:支持自动余额、手动余额、任意时间段余额。关于分片策略:支持范围分片,哈希分片,也支持预分片。关于分片构建类型:支持单自动分片构建和多字段分片构建优势5:不同级别的数据一致性和安全保障MongoDB在设计中根据不同的一致性级别要求支持不同类型的ReadConcern和WriteConcern读写对于相关配置,客户可根据实际情况进行设置。此外,MongoDB核心设计有完善的回滚机制,保证数据的安全性和一致性。优势六:高并发、高性能为了适应大规模高并发业务读写,MongoDB在线程模型设计、并发控制、高性能存储引擎等方面做了很多细节优化。优势七:Wiredtiger高性能存储引擎设计网上很多评论还停留在早期的MMAPv1存储引擎。与MMAPv1相比,wiredtiger引擎性能更好,压缩比更高,锁粒度更小。详情如下:WiredTiger提供低延迟和高吞吐量处理比内存大得多的数据,而不会降低性能或资源。系统故障可以快速恢复到最新的检查点。支持PB级数据存储多线程架构。尽量使用乐观锁并发控制算法来减少锁操作。Hot-最大化利用cachescapacitydiskIO提高磁盘IO能力其他优势八:节省成本-WT引擎高压缩比支持MongoDB数据压缩支持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的磁盘消耗比。优势九:自然N个机房(无论同城还是异地)多活容灾,支持MongoDB天然的高可用机制和agent标签自动识别转发功能,可以部署在不同机房满足同城异地N机房多活容灾需求,实现成本、性能、一致性“三丰收”。更多机房多活容灾案例请参考Qcon分享:优势10:完善的客户端均衡访问策略MongoDB客户端访问路由策略由客户端自行指定。该功能通过ReadPreference实现,支持primary、primaryPreferred、secondary、secondaryPreferred、nearest五种客户端均衡访问策略。分布式事务支持MongoDB-4.2版本已经支持分布式事务功能,当前外部文档版本迭代到4.2.11版本,分布式事务功能进一步增强。此外,从MongoDB-4.4的产品规划路线图可以看出,MongoDB官方将继续投入查询能力和可用性增强的开发,例如union多表联合查询、索引隐藏等。3.MongoDB资源评估及部署架构业务开始迁移MongoDB时,集群规模及业务需求总结如下:现有数据量约400亿,数据磁盘总消耗量约30T,读写高峰流量是4-5W左右/s,流量很小。同城两机房多活、容灾、读写分离,预计每月新增200亿数据,满足几个月内新增1500亿数据的需求。注:数据规模和磁盘消耗均按单副本计算,如MySQL64个分片,256个副本,数据大小和磁盘消耗的计算方法为:64个主节点数据量之和,磁盘之和消耗64个分片主节点。一、MongoDB资源评估分片数量和存储节点包规格的选择评估过程如下:内存评估我们公司都是容器化部署。根据以往的经验,MongoDB并不会消耗多少内存,历史超过100亿的MongoDB集群的单个容器最大内存基本是64Gb,所以内存规格确定为64G。分片评估业务流量峰值在3-5W/s。考虑到后期可能会有更大的峰值流量,按照写入峰值10W/s,读取5W/s估计需要4个分片,即峰值15W/s用于评估。磁盘评测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规格测评由于容器调度包的限制,CPU只能限制在16CPU(实际上用不了那么多CPU)。mongosproxy和configserver规格评估另外,由于shardedcluster也有mongosproxy和configserver副本集,所以也需要对mongosproxy和configserver节点规格进行评估。由于configserver主要存储路由相关的元数据,因此对磁盘、CUP、MEM的消耗非常低;mongosproxy只消耗CPU进行路由转发,所以对内存和磁盘的消耗并不高。最后,为了最大限度地节省成本,我们决定为代理和配置服务器重用同一个容器。容器规格如下:8CPU/8G内存/50G磁盘,一个agent和一个configserver节点复用同一个容器。Sharding和存储节点规格汇总:4个shards/16CPU,64G内存,7T磁盘。mongos和configserver规格汇总:8CPU/8G内存/50G磁盘2.集群部署架构由于业务所在城市只有两个机房,我们采用2+2+1(2mongod+2mongod+1arbiter模式)在A机房部署2个mongod节点,B机房部署2个mongod节点,C机房部署一个规格最低的选举节点,如下图:说明:每个机房agent部署2个mongos代理,保证业务接入代理的高可用。挂机,对应机房业务不受影响;如果A机房挂了,B机房和C机房还剩下2个mongod+1个arbiter,在B机房的mongod中重新选举一个新的master节点,arbiter选举节点不消耗资源;client配置nearest实现就近读,保证请求通过proxy转发时,转发到最近的网络延时节点,即同一机房对应的存储节点读取数据;缺点:如果是异地机房,有B机房和C机房跨机房写的场景,如果ABC是同城机房,这个缺点没啥用,电脑的延迟同城的房间可以忽略。4、全业务+增量迁移的迁移过程由业务自己完成,通过阿里巴巴开源的datax工具实现。更详细的迁移工具请参考:https://github.com/alibaba/DataX五、性能优化过程集群优化过程按照以下两个步骤进行优化:数据迁移开始前的预优化,迁移过程中的瓶颈分析和优化,以及迁移完成后的性能优化。1、确定数据迁移开始前的前期操作和业务沟通。每条业务数据都带有一个设备标识ssoid。同时,业务查询更新是基于ssoid维度查询设备下的单条或一批数据。因此,切片构建选择ssoid。sharding的方式是将数据完全hash成4个shard,所以选择hashsharding的方式,这样可以最大程度的对数据进行hash,同时可以让相同的ssoid数据落入同一个shard以保证查询效率。预分片如果MongoDB的分片构建为哈希分片,可以提前进行预分片,这样在写入数据时,多个分片相对均衡的写入。预分片的好处是可以避免非预分片情况下的chunk迁移问题,最大化写入性能。sh.shardCollection("xxx.xxx",{ssoid:"hashed"},false,{numInitialChunks:8192})注意事项:记得提前为ssoid创建一个hashed索引,否则会影响后续的shard扩容。最近的配置被添加到最近的读取客户端从离自己最近的节点读取,从而保证了读取性能。mongos代理配置只对A机房的业务配置A机房的代理,对B机房的业务只配置B机房的代理,同时带上最近的配置,从而实现最大限度实现机房就近读取,防止客户端跨机房访问代理。DisableenableMajorityReadConcern禁用该功能后,ReadConcernmajority会报错。ReadConcern的作用大部分是避免脏读,不需要业务通信,直接关闭即可。存储引擎cacheSize规格选择单个容器规格:16CPU,64G内存,7T磁盘。考虑到全量迁移过程中内存压力和内存碎片会比较大,为避免OOM,设置cacheSize=42G。2.全量数据迁移过程优化。全量数据迁移过程中,迁移速度慢,内存中脏数据较多。当脏数据比例达到一定比例时,用户的读写请求对应的线程就会被阻塞,用户线程也会被淘汰。对于内存中的脏数据页,最终的写入性能会大幅下降。wiredtiger存储引擎的缓存淘汰策略相关的几个配置如下:由于业务全量迁移数据是连续大写而不是突发大写,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服务器层和操作系统开销。2-4W/秒。也就是说,在之前的量迁移完成后,缓存中的脏数据比例几乎很小,基本不会达到20%的门槛,业务读流量比之前多了很多(读流量数据迁移过程中转到原来的MySQL集群)。为了提高读取性能,做了如下性能调整(已经提前建好了索引):节点cacheSize由之前的42G调整为55G,尽可能多的热点数据缓存在商业阅读内存,最大化读取性能;高峰期,做一个缓存内存,加速释放,避免OOM。经过上述内核优化后,业务延时监控曲线发生变化,延时更加稳定,平均延时好转25%左右,如下图所示:6.迁移前后业务延时统计对比(MySQLvsMongoDB)迁移前业务延迟监控曲线(平均延迟7ms,2月1日数据,此时mysql集群只有300亿数据):MongoDB迁移后业务流量全部切换到MongoDB,业务延迟监控曲线(平均6ms,3月6日的数据,此时MongoDB集群大约有500亿条数据)总结:MySQL(300亿条数据)延迟:7msMongoDB(500亿条数据)延迟:6ms七、迁移成本效益对比1、MySQL集群规格及最大存储数据量原mysql集群共有64组,每组集群有4个副本,每个副本容器规格:4CPU,16Gmem,500Gdisk,可存储400亿条数据总的来说,大部分节点已经启动了90%的磁盘水位报警,DBA增加了部分节点的磁盘容量。总结如下:集群总数:64单集群副本数:4每个节点规格:4CPU,16Gmem,500Gdisk64个集群最大数据存储量:400亿二、MongoDB集群规格而存储数据量最大的MongoDB从MySQL迁移后,数据量从400亿增加到1000亿,数据量每月增加200亿。MongoDB集群规格和存储数据量汇总如下:分片数量:4单分片副本数:4每个节点规格:16CPU,64G内存,7T磁盘四个分片存储数据量:当前存储1000亿,最大可以存储1500亿条数据。3、成本对比计算过程说明:MySQL迁移到MongoDB后,数据不再写入MySQL。当流量切换到MongoDB时,MySQL中存储了大约400亿条数据。因此,我们将这个时间点作为对比时间点。基于400亿条数据,资源消耗对比如下表(每个shard只计算master节点资源消耗,因为MySQL和MongoDB都是4副本):由于MongoDB的四个shard仍然有很多磁盘redundancy,四个和400亿数据相比,sharding也可以写入1100亿数据。如果按1500亿条数据计算,如果仍然沿用MySQL之前的封装规格,则需要将MySQL集群数增加三倍,即集群总数需要64*4=256套。资源占用对比如下:4.收益总结(客观对比)从以上内容可以看出,业务迁移到MongoDB后,除了解决了业务容量的痛点,促进了快速迭代开发业务,性能提升的同时,成本也节省了数倍。成本节省总结如下:400亿维计算(mysql和MongoDB都存储相同的400亿数据):CPU和内存成本比:4:1磁盘成本比:3.3:11500亿维计算(假设mysql集群采用之前的规格等比例换算):CPU和内存成本比:16:1磁盘成本比:3.3:1从上面的分析可以看出,数据量越大,MongoDB的存储成本越低按等比换算的原则。原因如下:CPU/内存节省原因:主要是因为MongoDB海量数据存储和高性能。建好索引后,即使单实例单表百亿数据,读写也会回到ms级别(注意:记得查询更新建索引)。另外,由于MongoDB的分布式功能,更方便评估容量,因此无需提前一次性申请多套mysql,但可以根据实际需要随时添加sharding.节省磁盘的原因:MongoDB存储引擎wiredtiger默认高压缩高性能。最后,鉴于客观的成本评估,CPU/内存成本部分可能存在争议,比如申请时mysql内存和CPU是否过大。MongoDB对应的CPU也有这个问题。比如申请的单个容器是16CPU,实际只消耗了几个CPU。但是,磁盘节省是真实的,这是mysql和MongoDB在相同数据条件下的真实磁盘消耗对比。目前集群总数据量已接近1000亿,并以每月200亿的规模递增。仅从容器计费角度来看,1000亿数据等比例折算,有望节约10倍成本。8、最后:千亿级中型MongoDB集群注意事项MongoDB不需要分库分表,单表可以无限大,但是随着数据量的增加,单表会造成以下问题问题:记得提前建立索引,否则查询更新会影响性能(数据越多,无索引查询扫描越慢)。记得提前评估业务需要的指标。单节点单表百亿数据,加索引执行时间长。服务器异常时节点更换时间会更长。切记不要使用mongodump/mongorestore进行数据备份,而是使用热备份或文件复制备份。节点更换应该尽量从备份中通过复制数据加载的方式恢复,而不是通过主从全同步的方式,全同步过程耗时较长。9、未来挑战(集群未来万亿级实时数据规模挑战)随着时间的推移,业务数据会越来越多,月数据量增长曲线有望呈线性增长(目前月度数据volume增加200亿预计未来2-3年集群总数据量将达到万亿,分片数量将达到20个左右,可能会遇到各种各样的问题。但是有一个明显的IOT业务数据冷数据问题,一年前的数据用户基本不会访问,因此我们考虑做如下优化,进一步提升性能和成本:将冷数据归档到低成本SATA盘,提高冷数据压缩率到minimizediskconsumption如何解决冷数据归档sata磁盘过程中的性能问题十、最终解释(业务场景)千亿级IOT业务使用场景总结化如下:共享业务数据的读取、更新、排序等。所有的索引都可以使用,包括单字段索引、多字段索引、数组索引。所有的查询和更新都可以确定一个特定的最优索引。所有查询均为单表查询,不涉及多表联合查询。数据库场景很重要,离开业务场景谈数据库的优劣是没有意义的。比如本文的业务场景,业务可以确定需要建立哪些索引,所有的更新、查询、排序都可以对应到具体的最优索引,所以这个场景非常适合MongoDB。每个数据库都有适合的业务场景,没有万能的数据库。另外,也不能因为不适合某个场景就完全否定没有数据库。主流的数据库有它自己的意义,不能因为某个数据库不适合某个场景就完全否定它。笔者介绍杨亚洲,原滴滴出行专家级工程师,现任OPPO文档数据库MongoDB负责人。负责万亿级数据量文档数据库MongoDB核心开发、性能优化和运维。他一直专注于分布式缓存和高性能服务。终端、数据库、中间件等相关研发。以后继续分享《MongoDB内核源码设计、性能优化、最佳运维实践》。