作者简介:曾任职于阿里巴巴,每日优鲜等互联网公司,任技术总监。
最近很多读者朋友留言,希望“二马”多写一些实际工作经历以及工作中遇到的问题和技术解决方案。应大家要求,本文介绍一次订单中心重构的经历。
背景
几年前我曾经服务过的一家电商公司,随着业务增长我们每天的订单量很快从30万单增长到了100万单,订单总量也突破了一亿。当时用的Mysql数据库。根据监控,我们的每秒最高订单量已经达到了2000笔(不包括秒杀,秒杀TPS已经上万了。秒杀我们有一套专门的解决方案,详见《秒杀系统设计~亿级用户》)。不过,直到此时,订单系统还是单库单表,幸好当时数据库服务器配置不错,我们的系统才能撑住这么大的压力。
重构?说这么高大上,不就是分库分表吗?的确,就是分库分表。不过除了分库分表,还包括管理端的解决方案,比如运营,客服和商务需要从多维度查询订单数据,分库分表后,怎么满足大家的需求?分库分表后,上线方案和数据不停机迁移方案都需要慎重考虑。为了保证系统稳定,还需要考虑相应的降级方案。
为什么要分库分表?
当数据库产生性能瓶颈:IO瓶颈或CPU瓶颈。两种瓶颈最终都会导致数据库的活跃连接数增加,进而达到数据库可承受的最大活跃连接数阈值。终会导致应用服务无连接可用,造成灾难性后果。可以先从代码,sql,索引几方面进行优化。如果这几方面已经没有太多优化的余地,就该考虑分库分表了。
磁盘读IO瓶颈。由于热点数据太多,数据库缓存完全放不下,查询时会产生大量的磁盘IO,查询速度会比较慢,这样会导致产生大量活跃连接,最终可能会发展成无连接可用的后果。可以采用一主多从,读写分离的方案,用多个从库分摊查询流量。或者采用分库+水平分表(把一张表的数据拆成多张表来存放,比如订单表可以按user_id来拆分)的方案。
第二种:磁盘写IO瓶颈。由于数据库写入频繁,会产生频繁的磁盘写入IO操作,频繁的磁盘IO操作导致产生大量活跃连接,最终同样会发展成无连接可用的后果。这时只能采用分库方案,用多个库来分摊写入压力。再加上水平分表的策略,分表后,单表存储的数据量会更小,插入数据时索引查找和更新的成本会更低,插入速度自然会更快。
SQL问题。如果SQL中包含join,groupby,orderby,非索引字段条件查询等增加CPU运算的操作,会对CPU产生明显的压力。这时可以考虑SQL优化,创建适当的索引,也可以把一些计算量大的SQL逻辑放到应用中处理。
单表数据量太大。由于单张表数据量过大,比如超过一亿,查询时遍历树的层次太深或者扫描的行太多,SQL效率会很低,也会非常消耗CPU。这时可以根据业务场景水平分表。
分库分表方案
分库分表主要有两种方案:
利用Sharding-Jdbc,TSharding等以Jar包形式呈现的轻量级组件分库分表。缺点是,会有一定的代码开发工作量,对业务有一些侵入性。好处是对程序员透明,程序员对分库分表逻辑的把控会更强,一旦发生故障,排查问题会比较容易。
稳妥起见,我们选用了第二种方案,使用更轻量级的Sharding-Jdbc。
根据上面的数据,我们分成了16个数据库。按日订单量1000万来算,每个库平均的日订单量就是62.5万(1000万/16),每秒最高订单量理论上在1250左右(2000*(62.5/100))。这样数据库的压力基本上是可控的,而且基本不会浪费服务器资源。
每个库分了16张表,即便按照每天1000万的订单量,两年总单量是73亿(73亿=1000万*365*2),每个库的数据量平均是4.56亿(4.56亿=73亿/16),每张表的数据量平均是2850万(2850万=4.56亿/16)。可以看到未来两到三年每张表的数据量也不算多,完全在可控范围。
分库分表主要是为了用户端下单和查询使用,按user_id的查询频率最高,其次是order_id。所以我们选择user_id做为shardingcolumn,按user_id做hash,将相同用户的订单数据存储到同一个数据库的同一张表中。这样用户在网页或者App上查询订单时只需要路由到一张表就可以获取用户的所有订单了,这样就保证了查询性能。
另外我们在订单ID(order_id)里掺杂了用户ID(user_id)信息。简单来说,order_id的设计思路就是,将order_id分为前后两部分,前面的部分是user_id,后面的部分是具体的订单编号,两部分组合在一起就构成了order_id。这样我们很容易从order_id解析出user_id。通过order_id查询订单时,先从order_id中解析出user_id,然后就可以根据user_id路由到具体的库表了。
另外,数据库分成16个,每个库分16张表还有一个好处。16是2的N次幂,所以hash值对16取模的结果与hash值和16按位“与运算”的结果是一样的。我们知道位运算基于二进制,跨过各种编译和转化直接到最底层的机器语言,效率自然远高于取模运算。
有读者可能会问,查询直接查数据库,会不会有性能问题?是的。所以我们在上层加了Redis,Redis做了分片集群,用于存储活跃用户最近50条订单。这样一来,只有少部分在Redis查不到订单的用户请求才会到数据库查询订单,这样就减小了数据库查询压力,而且每个分库还有两个从库,查询操作只走从库,进一步分摊了每个分库的压力。
有读者可能会问,为什么没采用一致性hash方案?用户查询最近50条之前的订单怎么办?请继续往后看!
管理端技术方案
分库分表后,不同用户的订单数据散落在不同的库和表中,如果需要根据用户ID之外的其他条件查询订单。例如,运营同学想从后台查出某天iphone7的订单量,就需要从所有数据库的表中查出数据然后在聚合到一起。这样代码实现非常复杂,而且查询性能也会很差。所以我们需要一种更好的方案来解决这个问题。
我们采用了ES(ElasticSearch)+HBase组合的方案,将索引与数据存储隔离。可能参与条件检索的字段都会在ES中建一份索引,例如商家,商品名称,订单日期等。所有订单数据全量保存到HBase中。我们知道HBase支持海量存储,而且根据rowkey查询速度超快。而ES的多条件检索能力非常强大。可以说,这个方案把ES和HBase的优点发挥地淋漓尽致。
该方案,解决了管理端通过各种字段条件查询订单的业务需求,同时也解决了商家端按商家ID和其他条件查询订单的需求。如果用户希望查询最近50条订单之前的历史订单,也同样可以用这个方案。
每天产生数百万的订单数据,如果管理后台想查到最新的订单数据,就需要频繁更新ES索引。在海量订单数据的场景下,索引频繁更新会不会对ES产生太大压力?
Mysql中的订单数据需要实时同步到Hbase和ES中。同步方案是什么?
我们利用Canal实时获取Mysql库表中的增量订单数据,然后把订单数据推到消息队列RocketMQ中,消费端获取消息后把数据写到Hbase,并在ES更新索引。
上面是Canal的原理图,
1,Canal模拟mysqlslave的交互协议,把自己伪装成mysql的从库
2,向mysqlmaster发送dump协议
3.mysqlmaster收到dump协议,发送binarylog给slave(Canal)
4.Canal解析binarylog字节流对象,根据应用场景对binarylog字节流做相应的处理
为了保证数据一致性,不丢失数据。我们使用了RocketMQ的事务型消息,保证消息一定能成功发送。另外,在Hbase和ES都操作成功后才做ack操作,保证消息正常消费。
不停机数据迁移
在互联网行业,很多系统的访问量很高,即便在凌晨两三点也有一定的访问量。由于数据迁移导致服务暂停,是很难被业务方接受的!下面就聊一下在用户无感知的前提下,我们的不停机数据迁移方案!
数据迁移过程我们要注意哪些关键点呢?第一,保证迁移后数据准确不丢失,即每条记录准确而且不丢失记录;第二,不影响用户体验,尤其是访问量高的C端业务需要不停机平滑迁移;第三,保证迁移后的系统性能和稳定性。
常用的数据迁移方案主要包括:挂从库,双写以及利用数据同步工具三种方案。下面分别做一下介绍。
挂从库
在主库上建一个从库。从库数据同步完成后,将从库升级成主库(新库),再将流量切到新库。
1,新建从库(新数据库),数据开始从主库向从库同步。
3,最后启动服务,整个迁移过程完成。
这种迁移方案的优势是迁移成本低,迁移周期短。缺点是,切换数据库过程需要停止服务。我们的并发量比较高,而且又做了分库分表,表结构也变了,所以不能采取这种方案!
双写
老库和新库同时写入,然后将老数据批量迁移到新库,最后流量切换到新库并关闭老库读写。
聊一下我们的具体迁移方案,步骤如下:
代码准备。在服务层对订单表进行增删改的地方,要同时操作新库(分库分表后的数据库表)和老库,需要修改相应的代码(同时写新库和老库)。准备迁移程序脚本,用于做老数据迁移。准备校验程序脚本,用于校验新库和老库的数据是否一致。
第3步完成后,我们还需要通过脚本程序检验数据,看新库数据是否准确以及有没有漏掉的数据
数据校验没问题后,开启双读,起初给新库放少部分流量,新库和老库同时读取。由于延时问题,新库和老库可能会有少量数据记录不一致的情况,所以新库读不到时需要再读一遍老库。然后再逐步将读流量切到新库,相当于灰度上线的过程。遇到问题可以及时把流量切回老库
读流量全部切到新库后,关闭老库写入(可以在代码里加上热配置开关),只写新库
利用数据同步工具
我们可以看到上面双写的方案比较麻烦,很多数据库写入的地方都需要修改代码。有没有更好的方案呢?
我们还可以利用Canal,DataBus等工具做数据同步。以阿里开源的Canal为例。
利用同步工具,就不需要开启双写了,服务层也不需要编写双写的代码,直接用Canal做增量数据同步即可。相应的步骤就变成了:
代码准备。准备Canal代码,解析binarylog字节流对象,并把解析好的订单数据写入新库。准备迁移程序脚本,用于做老数据迁移。准备校验程序脚本,用于校验新库和老库的数据是否一致。
运行Canal代码,开始增量数据(线上产生的新数据)从老库到新库的同步。
数据校验没问题后,开启双读,起初给新库放少部分流量,新库和老库同时读取。由于延时问题,新库和老库可能会有少量数据记录不一致的情况,所以新库读不到时需要再读一遍老库。逐步将读流量切到新库,相当于灰度上线的过程。遇到问题可以及时把流量切回老库
读流量全部切到新库后,将写入流量切到新库(可以在代码里加上热配置开关。注:由于切换过程Canal程序还在运行,仍然能够获取老库的数据变化并同步到新库,所以切换过程不会导致部分老库数据无法同步新库的情况)
关闭Canal程序
迁移完成。
扩容缩容方案
需要对数据重新hash取模,再将原来多个库表的数据写入扩容后的库表中。整体扩容方案和上面的不停机迁移方案基本一致。采用双写或者Canal等数据同步方案都可以。
更好的分库分表方案
通过前面的描述,不难看出我们的分库分表方案有一些缺陷,比如采用hash取模的方式会产生数据分布不均匀的情况,扩容缩容也非常麻烦。
这些问题可以用一致性hash方案解决。基于虚拟节点设计原理的一致性hash可以让数据分布更均匀。
而且一致性hash采用环形设计思路,在增减节点时,使得数据迁移的成本会更低,只需要迁移临近节点的数据。不过需要扩容时基本上要成倍扩容,在hash环上每个节点间隙都增加新的节点,这样才能分摊所有原有节点的访问和存储压力。
降级方案
在大促期间订单服务压力过大时,可以将同步调用改为异步消息队列方式,来减小订单服务压力并提高吞吐量。
9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。
加利福尼亚州圣克拉拉县2024年8月30日/美通社/--数字化转型技术解决方案公司Trianz今天宣布,该公司与AmazonWebServices(AWS)签订了...
伦敦2024年8月29日/美通社/--英国汽车技术公司SODA.Auto推出其旗舰产品SODAV,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。SODAV工具的开发耗时1.5...
北京2024年8月28日/美通社/--越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...
8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。
8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。
8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。
要点:有效应对环境变化,经营业绩稳中有升落实提质增效举措,毛利润率延续升势战略布局成效显著,战新业务引领增长以科技创新为引领,提升企业核心竞争力坚持高质量发展策略,塑强核心竞争优势...
北京2024年8月27日/美通社/--8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。活动现场NVI技术创新联...
北京2024年8月27日/美通社/--在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...
山海路引岚悦新程三亚2024年8月27日/美通社/--近日,海南地区六家凯悦系酒店与中国高端新能源车企岚图汽车(VOYAH)正式达成战略合作协议。这一合作标志着两大品牌在高端出行体验和环保理念上的深度融合,将...
上海2024年8月28日/美通社/--8月26日至8月28日,AHNLAN安岚与股神巴菲特的孙女妮可巴菲特共同开启了一场自然和艺术的疗愈之旅。妮可·巴菲特在疗愈之旅活动现场合影...
8月29日消息,近日,华为董事、质量流程IT总裁陶景文在中国国际大数据产业博览会开幕式上表示,中国科技企业不应怕美国对其封锁。
上海2024年8月26日/美通社/--近日,全球领先的消费者研究与零售监测公司尼尔森IQ(NielsenIQ)迎来进入中国市场四十周年的重要里程碑,正式翻开在华发展新篇章。自改革开放以来,中国市场不断展现出前所未有...
上海2024年8月26日/美通社/--今日,高端全合成润滑油品牌美孚1号携手品牌体验官周冠宇,开启全新旅程,助力广大车主通过驾驶去探索更广阔的世界。在全新发布的品牌视频中,周冠宇及不同背景的消费者表达了对驾驶的热爱...
此次发布标志着Cision首次为亚太市场量身定制全方位的媒体监测服务。芝加哥2024年8月27日/美通社/--消费者和媒体情报、互动及传播解决方案的全球领导者Cis...
上海2024年8月27日/美通社/--近来,具有强大学习、理解和多模态处理能力的大模型迅猛发展,正在给人类的生产、生活带来革命性的变化。在这一变革浪潮中,物联网成为了大模型技术发挥作用的重要阵地。作为全球领先的...
北京2024年8月27日/美通社/--高途教育科技公司(纽约证券交易所股票代码:GOTU)("高途"或"公司"),一家技术驱动的在线直播大班培训机构,今日发布截至2024年6月30日第二季度未经审计财务报告。2...
8月26日消息,华为公司最近正式启动了“华为AI百校计划”,向国内高校提供基于昇腾云服务的AI计算资源。