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

京东亿园抢宝系统数据库架构优化

时间:2023-03-14 08:27:25 科技观察

本文基于开明在京东内部进行的#京东技术节#《一元抢宝分库分别策略与实现》技术分享。一元抢宝系统是京东虚拟的新兴业务系统,上线以来订单量持续增长。618前两个月,京东商城虚拟研发部对系统进行了整体预估。订单量的快速增长和618大促的到来,将带来订单量的激增,势必会影响数据库的容量和负载。造成压力。分析结果表明数据库很可能成为影响性能的瓶颈,决定将数据库底层改造为分库分表,保证数据层次动态扩展的能力,满足需求数据容量持续增长,订单效率不断提升。一、业务介绍上图为一元钱宝商品详情页。从图中可以看出,益元钱宝的产品是商品。与京东其他产品不同的是,它有时段、总人数、剩余人数的概念。;假设一个商品项目有100个库存,将分100批出售,每批出售一次为一个库存;总人数就是每期抢宝的价格。假设1000人,产品总价为1000元(每人1元);当剩余人数为0时,本期抢宝结束,然后根据相应的算法生成抢宝者;然后进行下一期的抢宝。通过技术改造,总体上实现了三个目标:1.底层路由策略的实现;2、历史数据迁移;3.业务转型。下面详细描述这种转变的过程。2、数据库容器预估最重要的是先预估容器,根据数据量和业务特点预估容器/库/表的个数和分库分表的规则。假设每天100万个订单,一年就会产生3.6亿个订单;假设数据结构是这样的:订单表有10个字段,每个字段有50个字符;一个订单需要500字节的存储空间,那么3.6亿个订单需要大约170GB的存储空间;假设每台机器有200GB的存储空间,每年增加一台机器就可以满足容量需求。实际需求根据压力测试结果确定;比如压力测试其他指标是否满足需求,比如QPS,响应时间等。3.底层路由策略选择和实现分库分表路由策略是基础,影响整个系统架构,后期的业务需求是否得到满足和支持,使用是否方便,都与此有关。路由策略设计合理,上层业务使用起来会很方便。亿元钱宝项目的路由策略适配实现是在DAO层实现的,对上层业务透明,不需要关心具体实现,路由策略不涉及结构变化,并且不会影响上层。我们知道常见的分表策略有两种:hash路由优势:可以实现数据分散和热点分散;缺点:增加数据库节点时,会影响路由策略,需要做数据迁移;partitionrouting(incrementalintervalrouting)优点:策略支持动态扩展,理论上可以扩展。缺点:存在数据热点,新生成的表读写频率高;每个查询都需要经过路由策略表。当然,每种策略都不是完美的,只有最适合业务场景的策略才是好的。该项目结合使用了两种方法。首先按照抢宝物品的hash分库,然后按照抢宝周期间隔分表,如下图:周期的路由策略表规则如下:为什么用这个战略?抢宝物品是业务的上层维度,可以理解为商品,大部分表都有这个字段;这个id在生成的时候是连续的,从长远来看,hash分库后数据会平衡。抢宝期是抢宝道具下的一个维度。比如某件商品的库存为100,在不间断销售的前提下,会产生100期,只有一期在售。为什么选择periodidinterval作为分表路由策略?有的朋友认为还可以选择orderid。从路由策略来看,没有问题。但是在一元抢宝项目的业务场景中,有一个根据itemid和periodid查询订单参与情况。录制的场景,所以需要考虑通过这两个维度可以找到顺序。另外,使用区间作为表分区策略可以动态扩展。即使每次查询都经过路由表,这个开销也可以忽略不计,全部通过缓存加载。以上策略可以路由到哪些维度?1.orderid路由:订单号是按照一定的规则生成的,里面存储了库和表的信息,可以根据订单号直接定位到对应的库和表;2.通过寻宝物品id和寻宝期id进行路由:寻宝物品的hash位于库中,寻宝期查询路由策略表位于在表中。具体图如下:4.聚合查询和聚合数据同步的实现涉及到聚合查询,我们是如何实现的呢?先看下面的架构图:上图是数据层改造后的架构图。之前是单表主从模式,改成多个分库和基础库。聚合使用elasticsearch(以下简称ES)。为什么要使用它?第一,简单、方便、容易获取;二是支持动态扩容和分片,对业务层透明。系统中的聚合查询主要使用ES。当然,我们有很多降级方案,后面会提到。ES不能作为库使用,不能完全保证数据的完整性,所以必须要有数据备份。我们使用聚合表来保存一段时间的数据,以备降级使用。一旦ES延迟或者集群不可用,就会降级查询聚合表。我们如何同步ES?我们使用运河。可能有朋友会说,直接插入代码为什么不同步,可以这样,但是有两个问题,一个是如何处理同步失败,如何保证事务,另一个是和业务代码的强耦合,借用条款,不美化。使用canal,代码解耦,不侵入代码。它实际上模拟了数据库的主从复制机制,伪装成一个从库。当数据库的binlog(为了不影响主库的生产,我们监控从库)发生变化时,canal对其进行监控,并通过分析服务对binlog进行解析和过滤。筛选出所需的日志。解析后,我们发送MQ消息。消息体是表名和主键id,不是整条数据。消费端收到变化后的表名和id,实时从数据库中查询***数据,同步到ES和聚合表中。为什么要传递MQ消息?也可以用以上两点来解释。一是消息支持失败重试,存储失败后抛出异常,等待下一步处理。另一个是系统之间的解耦。细心的朋友可以看到,一个消息队列是由多个消费者订阅的(可以理解为每个消费者的队列是镜像的)。这样做是为了在存放时不互相干扰;如果使用一个订阅者处理,存储ES失败,另外两个聚合存储成功,那么也应该抛出异常或者其他处理方式,另外两个聚合下次消费一次时也会存储.以上就是我们聚合和同步聚合的设计。查询时,有些服务会先查询缓存,如果不存在再查询ES。如果降级了,会去查数据库,正常的聚合查询是找不到数据库的。5、历史数据的迁移由于我们的系统上线时是单库,而分库是上线后几个月的技术改进,所以需要进行数据迁移。主要迁移步骤如下:前半部分,从扫描到同步到分库是新的代码,后面复用了canal到同步ES和聚合表上面的逻辑。这样的设计减少了我们整体的工作量,保证了数据迁移的完整性。具体迁移细节如下:可以看出主要分为两部分,关机前和关机后。宕机前迁移历史数据,支持重复迁移;宕机后只迁移增量部分,大大缩短了我们的在线时间。中断后只需要迁移少量数据。迁移涉及数据校验,校验逻辑整体比较简单:将三个维度与基础数据库进行对比,不同则重新迁移某一天的数据。6、关键系统节点的降级也很重要。我们的降级主要有两点,一是canal同步延迟降级,二是ES不可用降级。第一种如下:如果canal同步延迟,或者从库挂了,打开开关,扫描主库数据(最近几个小时),直接同步到ES和聚合表;这样即使从库挂了,也不会影响业务数据,这个很重要,我们在实际业务场景中也遇到过。当ES降级,ES不可用时,关闭ES开关,直接查询聚合表。7、总结一个系统从设计到最终完成,取决于整个团队,每个人的想法,不同想法的碰撞和贡献;前期合理细致的设计尤为重要,每个时间点和具体的上线步骤和回滚计划都做好了详细的计划;此外,细致深入的测试、测试环境和多轮上线测试回归也是正常上线的重要保障。以上就是京东亿源钱宝项目分库分表的主要思路。希望有相同想法的朋友可以深入交流,共同完善彼此的系统架构。作者:邵开明,京东高级开发工程师,负责京东亿元钱宝系统架构及开发;多年互联网从业经验,对系统架构和设计有自己的见解和经验。【本文来自专栏作者张凯涛微信公众号(凯涛博客)公众号id:kaitao-1234567】点此查看作者更多好文