欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

凯叔解密京东千亿商品系统核心架构

程序员文章站 2022-04-06 20:50:56
...

作者:尤凤凯, 京东商城研发-交易平台-商品研发负责人。2010年加入京东,先后参与设计研发京东第一代监控、消息、EDM等系统。12年开始致力于商品系统SOA化、商品系统的持续架构演进。现主要负责商品中台及组件化建设。

 

商品,黄金交易流程最基础、最核心的环节,无商品不电商。商品数据无处不在,商家(采销、供应商)发布管理、供应商下采购单、仓储配送、促销、搜索、商详页展现、购物支付、财务结算、售后服务等,都离不开商品。商品信息要准确传导于京东整个供应链的各节点,必须要有一套稳健、可靠的商品服务体系支撑。

 

原本并没有统一的商品服务及存储。DBA搭建了一套包含若干层级的SqlServer数据库复制结构,各系统从各级从库读取数据。复制延迟严重的时候,超过12小时,从库还没有更新,严重影响用户体验。写入口不止一个,获取到写账号就可以写入。erp商品管理系统、POP商品系统、BIP甚至也开发了一个商品管理系统,都在写同一个库的同一套表,数据一致性无法得到保障。在那个阶段京东的订单量、用户量相对较少,基于数据库的架构一定程度上也能支撑日常流量,但是无法应对大型促销活动。

凯叔解密京东千亿商品系统核心架构
            
    
    博客分类: 架构

 

在此背景下,2012年3月商品组从网站组独立出来,孙歌临危受命组建团队,启动商品技术架构升级项目。京东618年中狂欢购物节,系统(特别是0点)会承受平时无法比拟的压力。2012年之前的大促都会出现系统问题系统经常出现问题,甚至图书抢购活动时直接系统宕机。基于数据库提供读服务的架构,显然已经无法支撑业务前行,升级改造势在必行。12年初NoSQL还是新鲜事物,交易架构师龚杰开始实践Redis,他在一封邮件中介绍自主封装的客户端以及API。商品团队开始基于redis内存数据库搭建商品读服务,并对开源Jedis做了深度封装,扩展了ShardedJedisPool,实现了更加细粒度的多分片连接池管理,并且将一个请求中命中到同一个分片的redis命令由串行改成pipeline并行执行,性能提升较大。

 

架构1.0 读服务化

由Redis存储全量商品数据,作为内存数据库使用。商品信息变动时增量更新,一主多备模式容灾,同时全量刷新程序作为最后保障,一旦Redis中数据全部丢失,可以将商品库中数据恢复到Redis。

 

交易系统直面用户,为保证用户选品、下单结算的顺畅,提升用户体验。交易系统对高性能、高可用的商品读服务需求最迫切。此时架构升级采取了一种“轻模式”,所谓轻是指尽量减少外部系统的改造,这样更利于工作的快速推进。首先在通知模式上,各种商品系统写入Sqlserver主库后,通过HttpHTTP服务通知Rcat -server(采取尽量做的策略,能通知就通知到,有异常也不去重试,这种策略对相关系统的改造最小)。Rcat-server的职责就是接收通知,之后查询主库中的商品信息,将其更新到Redis中。因为写入系统是尽量做,不保证成功的模式,因此需要补偿机制去弥补遗漏。异步Worker会定期扫描数据库,把当日更新的,从刷新到Redis中。整体架构如图1-1所示:

凯叔解密京东千亿商品系统核心架构
            
    
    博客分类: 架构

图1-1 商品架构V1.0

 

V1.0版架构非常不完美,只是读服务这个点进行了改造,但是却在当年618中完美的完成了任务。618当天像往年一样,研发工程师售后守候在运维同学周围,时刻准备着!整个过程波澜不惊,只有过个别应用过载重启,整体非常顺利扛过了大流量的考验。有了这个经验,研发工程师们开始将Rcat(应用名称,商品读服务)推广,依赖Sqlserver从库的系统都逐步切换到读服务上。

 

架构2.0 全面服务化

POP商品系统和自营商品系统都是写入Oracle,在通过异步worker将数据写会Sqlserver。京东商品的独特之处在于最初是自采自销的自营类商品,有自己的商品模型和对应的erp管理系统。后续有了POP开放平台,该平台的商品模型和系统是独立搭建的,适应于第三方商家的商品发布管理。而所有下游的系统(单品、搜索、订单生产、仓库等)都是基于最初Sqlserver自营skuSKU模型做的系统设计。所以POP商品有自己的Oracle存储,也必须京东经过一步异步程序转化,写到Sqlserver商品库中。而自营商品系统在2011年架构升级时,计划由.Net+Sqlserver的技术体系升级外Java+Oracle技术体系。

 

孙歌作为研发负责人,基于技术前瞻性和成本考虑,果断决策放弃既昂贵又没有DBA团队良好支持的Oracle数据库。转而直接基于SqlServer实现商品的全面服务化,相比其他系统的去O足足早了一年。当时的整体思路是先实现服务化,再进行存储升级(Mysql集群),最终完成彻底的技术架构升级。全面服务化过程:

 

1). 全面读服务体系:

将下游系统读取的信息刷新到Redis中,由读服务Rcat统一支持根据skuId查询的需求。对于检索需求,例如根据分类id查询SkuSKU列表,搭建Solr索引服务。基于各系统的需求收集已经当前SQL的分析,搭建了读服务体系,并逐步推广,去掉各系统对Sqlserver数据库的读取依赖。

 

2).写服务化

接管所有商品写操作,提供商品相关的基本读写服务,建立商品主数据中心,服务于自营商品管理、POP平台、图书音像商品管理等系统。京东起家于3C自营产品, SKU化管理。后发展的POP平台,是商品化发布管理。写服务必须兼容两套模型,平滑过渡。研发工程师最终设计为统一到商品-skuSKU模型,自营商品与SkuSKU一对一,而POP商品与SkuSKU是一对多。自营商品每发布一个商品有且仅有一个SKUSku,pop商家发布一个商品可以有多个SkuSKU。自营商品沟通通过后期的颜色尺码绑定,实现销售关系捆绑。这样展现给用户的效果是一样的,同时对于京东采销、POP商家都可以按各自的习惯去操作商品。

写服务设计时架构师尤凤凯充分考虑了扩展性、可复用性,实现了模块可配置化。基于商品介绍、扩展属性、规格参数、特殊属性等基础组件,可灵活组配不同的业务流程。使用了京东自主研发的SAF中间件,其支持负载均衡、自动故障切换、流量控制、黑白名单等特性,并且在性能方面表现优异。

 

3).去O:去掉自营商品系统的Oracle,直接写Sqlserver降低延迟,缩短商家发布到展现给最终用户的时间。

 

4).异步引擎:建立下发服务系统,统一化消息通知网站、WMS等下游系统。

最初的商品变动时,只需要通知WMS系统, 因为采购入库时,仓库需要核实商品信息。随着整个京东服务化进程的推进,搜索、单品页等系统都希望得到通知。因此规划了下发服务,在商品信息变动后,异步通知这些系统。将商品信息入库后,同步写”操作日志”到Redis队列,再由worker异步从Redis中取日志,拿到变动变更的skuSKU,组装信息化发MQ消息出去。此时的消息采取通用化设计,例如基本信息MQ、特殊属性MQ等。

 

5).存储升级:商品主数据存储由Sqlserver单库,升级为MySQL集群,并进行垂直、水平划分, 分库解决单库吞吐量瓶颈,分表控制单表数据量。自主研发数据中间件,可以实现主库的路由、从库的负载均衡、故障的切换等,统一负责数据访问,使得底层存储规则对应用层透明。结合当前数据总量及增长率,预计3年后达到的数据量,做存储容量规划,并且做了Pre-Sharding方式,方便后续扩容。对于非片键外的查询,使用二级路由或者搜索服务来解决。

 

整体架构如图1-2所示

凯叔解密京东千亿商品系统核心架构
            
    
    博客分类: 架构

图1-2 商品架构v2.0

 

随着商品及SKU数量显著增长、TPS逐步走高。写服务、下发服务耦合的弊端越来越突出显现。如1-2图中红色线条形成的环状所示,写服务和下发服务是相互影响的。假设写Redis变慢,会影响整体写入性能;如果DB遇到瓶颈,反过来又回会影响到下发服务,回查DB变慢,下发服务处理变慢。因此写服务经常会出现抖动,写变慢、下发延迟。

 

架构3.0平台化、精准化

2015年中开始,架构师李帅启动3.0架构升级,其理念是解耦、简化。架构越简单越好,没接触过的人新人很快可以上手;架构也必须松耦合的,写、下发、读都可以各自做升级,相互不影响,逐步提升整体性能。

 

用Jingobus基于从库日志识别商品信息变动,并发送通知、刷新redis集群。异步引擎消息可配置化,商品属性的组合对应消息队列。例如:搜索关注skuSKU状态变化,那么只有skuSKU的上下柜状态变化时,才会发送消息,消息体中只包含skuSKU编号及状态。可配置化的任务引擎,新需求响应快、开发接近零成本;实现了按需发送,给消费方减压(例如:给wms的消息量降低80%+);并且写系统解耦,整体稳定性增强。在推广过程中,还进行跨部门技术协作,共同升级技术架构。例如网站单品页数据异构升级项目,降低50%+接口交互,节约上百台Docker。

 

商品服务作为超0级系统 ,必须具有高可用性。任何影响到订单的系统故障都必须在三分钟内解决,有了统一切换平台,执行预案是可以很快的。因此发现问题并警报至关重要。在研发负责人赵湘建的引领下,商品组启动秒级监控平台的研发。内存级监控信息收集、合并、延迟秒级。并且实现了秒级监控的平台化,可将监控能力输出到其他系统。

 

期间商品读服务也在持续进行着升级。因为skuSKU数量大(数十亿)且持续增长(周增长率约105%),Redis存储集群规模也大。读服务为其他众多系统提供商品数据的查询服务,访问量很大,特别是在618,双11期间,所以需要多组Redis集群分担流量。NIO的Redis客户端,降低了连接数量;后续为解决多组Redis集群流量均衡问题,对NIO版本的客户端做了扩展,实现了多分片连接统一管理,使其负载均衡,并能当某一分片宕机的情况下,自动从集群中剔除,恢复后自动加入集群中,达到故障自动转移与恢复的目的。不仅提高了集群整体的吞吐量,而且提升了可靠性。

    

同时因为商品数量增长很快,Redis集群的规模也成倍增加,为减少资源的利用,设计三级缓存功能,将最热数据放应用内存中,缓存时间较短;热数据放在规模较小的Redis集群中,全量数据放到规模较大的集群中,这样全量数据的Redis集群OPS较少,可以减少部署组数,从而减少资源利用。

 

凯叔解密京东千亿商品系统核心架构
            
    
    博客分类: 架构

图1-3 商品架构V3.0

 

京东商品系统在业务创新、数据智能化、性能及稳定性提升方面,将持续努力提升,努力实践让技术改变生活的愿景。

 

=============面试宝典==============

凯叔解密京东千亿商品系统核心架构
            
    
    博客分类: 架构