作者 | 方利
编辑 | 贾亚宁
本文由大厂案例转载自汽车之家主机厂事业部 - 技术部高级研发工程师方利首发于之家技术公众号的文章。
【资料图】
汽车之家电商系统诞生在 2014 年,成长于 2016~2019 年,并经历多年双 11、818 晚会的洪峰考验,沉淀了稳定可靠、性能卓越的在线交易能力。随着业务中台的建设浪潮兴起,2019 年进入中台化建设阶段,输出其在汽车电商领域五年沉淀的能力,助力汽车电商行业发展,加速企业数字化转型!
这个部分主要讲一下汽车之家电商系统的架构发展历程,每个阶段的业务状况、技术挑战和技术体系的应对策略。
互联网大环境在 2011~2013 年经过千团大战、电商大战 [1] 之后,电商业务已经成了互联网流量变现除广告模式外的另外一块战略高地。在 2013 年“双十一”期间,汽车之家推出购车服务,将交易环节作为一个重要发展方向 [2]。
在业务起步阶段对技术的要求就是快速迭代上线,验证产品可行性。在满足业务日常需求的同时,技术架构上的思考也未停止过。考虑到未来电商系统的可扩展性,参考业界阿里巴巴的技术体系,2014 年开始研发技术栈也逐步从 .NET 体系变成 Java 体系,并与 2015 年 5 月 30 日完成所有的应用切换,上线完整的在线网上购车平台车商城。
随着电商业务迅猛发展,技术人员的增加,到 2016 年技术团队已经有了上百人。单体架构之痛迎面扑来,就以一个前台的商城 git 项目而言,就几乎近 30 个 Maven 的子项目,遇上需求并行开发,经常出现代码的合并冲突、需求上线等待、线上慢 SQL 等问题,整个系统的开发效率和系统稳定性都变差了。
这个时候的系统支撑面临巨大的挑战,系统架构必须升级进化。我们开始做分布式战略,把原来的单一系统拆分成多个高内聚,低耦合的中心化系统。也就是现在的用户中心、商品中心、订单中心、促销中心、优惠券中心、商家中心,每个独立的系统可以独立设计、独立接需求、独立发布,整个研发效率和系统稳定性都上了一个台阶。
在这个阶段我们在技术上完成支撑汽车电商百万级商品系统 [3]、订单系统 [4]、优惠券系统 [5] 构建,并完成了应用的全部上云 [6]、自动化测试平台构建 [7]。
同时在业务上探索了自营整车电商模式、开放平台模式、B2B2C 模式、报价单模式、顾问模式、TPCC 模式、平行进口车售卖等各种经营模式。
电商发展的速度实在太快了,到了 2019 年公司内已经有了多种在线交易模式,比如旅游类、车品与后市场服务类、积分兑换类等。公司基于发展战略决定搭建电商中台,一方面为了集中公司优质的产品资源、运营资源,打造具有影响力的垂直类电商交易平台,另一方面也是为了合理管控技术资源,实现电商系统的统一。在此背景之下,我所在的团队承担起了搭建电商中台的任务,由于各个系统间的业务形态、技术架构差异很大,所以我们面临的第一个问题就是用什么方式能够实现交易类系统的整合。
为此我们一方面开始熟悉不同业务场景下的交易系统的现状,另一方面也在技术方案上进行着思考和讨论。最终我们选择了“以数据归一为基础,提供标准化中台服务,从下层向上层逐个系统整合”的方案。
数据是公司的核心资产,任何系统尤其是交易类系统,数据更是重中之重。主数据的建设一方面能够统一数据模型,打破系统壁垒;另一方面也能够通过集中的数据进行经营性数据分析,为业务决策提供依据,因此我们将主数据的建设作为了系统整合的第一步。
在交易流程中,最重要的数据集中在商家、商品、订单、促销活动这四个领域,我们结合公司交易场景的现状,分别对这四个领域的主数据进行抽象,统一建模,尽可能的适配大多数的交易场景。
以下是订单主数据核心数据模型结构的示意图:
完成了统一的数据模型后,下一步就需要将现有的异构型数据导入到主数据库中,我们采用了读取数据库 Binlog(MySQL、SQL Server)进行数据加工的方式完成初期的数据同步导入,这也是对业务侵入最小、最快的实现方案。
完成了主数据建设,下一步我们便开始进行基于主数据的 API 标准化建设,API 可以看做是系统的神经,高质量的 API 可以串联起一个优质的系统,统一了 API 在一定程度上也就实现了系统的收口。
为此,我们遵循单一职责的原则,按照领域进行区分,明确边界,做到所有底层 API 功能原子化,便于上游使用者灵活组装 API 完成业务逻辑,同时统一 API 的参数结构和响应结果的结构,统一错误码,基于 API 网关统一发布、调用,API 的数据统计监控、降级、限流实现统一管控。
有了标准化的 API,自然需要让业务方进行使用才能体现出 API 的价值,为了防止步子迈的太大,我们也是按照业务的重要性以及量级,采用读写分阶段的方案逐个业务进行调用切换,看似很合理的步骤,在实际执行过程中也暴露了很多问题:
在读写强依赖的场景,比如:用户下单完成后马上会跳转到订单详情查看订单,这个时候在未完成写 API 切换的时候,由于数据同步延迟会导致通过读 API 读取数据失败,这时就没有办法按照先读后写分阶段进行切换,最好的办法是读写同时切换。 对于业务切换影响最小的方式,当然是兼容原接口的参数和返回结果,如果我们强加业务方按照我们标准的 API 进行切换,势必给业务方带来切换成本和不必要的负作用。这个时候我们自然要从对方的角度出发做一些取舍。我们采用的方式是在标准 API 之上增加了一层适配层,用于新老协议的转换,让业务方只需要切换域名和请求的 URL 即可,其他逻辑不变,最大限度的做到对业务方友好。
由于我们提供的底层 API 都是原子的,但在实际场景中,尤其是前后端分离的项目,前端是不大愿意为了一个结果多次调用接口获取,面对这种情况,我们也是在后端增加了一层门面层,基于底层原子 API 组合成满足业务场景的 API 对外提供,对于差异化的接口逻辑做适度兼容。 读写切换不可能一蹴而就,在这个过程中势必会存在主数据 API 和原业务 API 并存的场景,鉴于所有 API 的入口都将由我们统一提供,因此我们也是采用了路由的机制,通过路由层的 location 进行区分转发,所有 API 做到对调用方的透明。 在实际 API 切换的过程中,还有一种特殊的场景,因为最终要实现系统的整合,对于那些后续会被整合掉的功能强行做 API 切换其实也是一种资源的浪费,因此我们也是提前做了预判,可以适度地不做切换,等待功能整合后将整体功能进行切换。在完成 API 读写切换之后,基于主数据的功能基本完成了聚合,此时就需要将通用功能进行系统化的统一,比如:统一的商家管理后台、统一的运营后台、统一的 C 端交易体验等,系统层级的统一整合目的是为了给使用者一个统一的操作界面,体现平台的专业性。
在系统整合的过程中,我们采用了“共性沉淀,差异取舍”的原则,对于那些通用的能力,比如:商品发布、订单列表等功能,我们会抽象出通用的能力,提供统一的单元化的操作界面,满足各业务方的使用诉求。
对于业务方特有的功能,我们会建议业务方去实现,而对于那些目前还无法形成通用能力但未来有可能作为通用能力的功能,我们会按照 MVP 原则,用最快的方式实现小版本的上线,随着业务的迭代不断的实现功能沉淀。
在整个系统整合的过程中,必然会出现在整合原有系统功能的同时又有新需求的加入。面对这种场景,我们的采用的方式是新老系统同步开发,看似增加了成本,其实对于新系统的整合是有好处的,一方面能够不影响业务的开展,不会因为技术性的整合对业务造成停滞;另一方面可以通过新老系统的对比,找出新系统可能存在的问题,这也会是验证整合后的新系统功能的最佳途径。
在完成绝大部分的系统整合工作之后,电商核心的交易链路已经可以跑通,并且在线上经历了长时间的验证,从商家入驻、商品发布、商品展示、下单、支付、履约、售后,到最终的结算,期间遇到的问题也在一一化解。在这个阶段我们完成了公司内 3 大交易系统的整合,并进行了电商平台秒杀系统 10 万级 QPS 的架构升级 [8],优惠券系统 10 万级 QPS 的架构升级,支撑了 2020~2021 年的 818 晚会、双 11、双 12 等大型活动的秒杀、发券场景。另外我们也在积极探索领域驱动模型 DDD 的理论与业界实践,并在发票总库系统的重构中进行了落地实践 [9],这也为后续的平台化架构升级提供了技术支撑。
在电商业务中台继续向业务的“逼近”过程中,系统的抽象和建设难度也成指数型增加,出现了一系列新问题:
随着建设中台项目的结束,人员的撤离,电商业务中台在集成这么多业务线的逻辑之后,代码里充斥着大量条件判断,每次需求迭代的开发成本和测试回归成本都很高,如何隔离不同业务之间的逻辑,减少业务之间的耦合度呢? 如何抽象出已接入电商业务中台的多条业务线的共性能力,避免重复建设呢? 当新业务接入电商业务中台,如何基于已有的能力和解决方案快速组装上线,以支撑业务快速迭代创新? 如何能够利用技术手段帮助产品运营日常工作提效呢?综上所述,电商业务中台在建设过程中抽象业务线的共性能力以及共性能力的复用性设计与实现尤其重要,业务中台要做到能力复用和灵活多变才能让中台建设在企业的发展过程中起到降本增效的效果。系统架构必须升级,这就进入了平台化架构阶段。
什么是平台化架构?就是要把基础能力跟每个业务方的特性业务拆分,要把业务和业务之间的逻辑进行隔离。平台化最核心的是业务抽象建模和系统架构的开放性,业务抽象解决共性的 80% 问题,系统架构开放性解决 20% 的个性化问题。
在参考 Thoughtworks 给出的《现代企业架构白皮书》的方案 [10] 以及业界的互联网公司美团 [11]、有赞 [12] 的中台解决方案,我们给出了适合之家电商平台的解决方案:通过领域驱动建模抽象出电商业务中台多业务线的共性能力并预留扩展点,然后利用服务编排对共性能力进行组合。其原理如图所示:
每一个在电商业务中台运行的业务可以理解为:业务身份 + 业务流程 + 规则,业务流程通过流程服务编排来实现,扩展点通过扩展点机制来实现。在整个交易流程中 B 端的商家入驻、商品发布相对通用,不同的业务的主要流程差别体现在订单收单前以及支付后的订单履约,这些流程往往都是需要定制化开发,为此整个解决方案核心在于订单平台化的架构设计。
如图所示,整个订单平台化架构分为四层,从下往上依次是:
基础设施层:提供存储、消息、RPC 等中间件。 基础服务层:按域组织的基础服务、域服务内针对不同业务的差异提供扩展点。 业务能力层:串联不同域服务形成可供外部使用的业务能力,比如下单、支付等。 业务流程层:对业务能力进行编排、形成订单交易流程、完成订单交易过程。 业务层:制定业务身份、扩展点实现以及业务流程配置等,实现不同业务差异。整个订单平台化架构升级实践过程,总结为以下几点:
业务身份的概念最早由阿里巴巴提出,业务平台在对各业务同时提供服务时,需要能区分每一次业务服务请求的业务身份要素,以便提供差异化个性化的服务;因此需要对企业各业务的身份和特征进行建模和区分,其产出即为业务身份。业务身份具有唯一性,业务身份类似于身份证号码一样,需要保证在整个业务中台上必须是唯一的。
有了业务身份业务中台就可以针对抽象这个业务流程和业务规则,并基于业务身份实现服务路由、业务监控。其次业务身份就类似 SaaS 系统中的租户的概念,不同的业务方在中台通过业务身份进行数据权限隔离,这样能保证各业务的运营只能看见自己业务部分的数据。
比如在汽车电商领域,业务身份我们通过人、货、场三个维度进行抽象。人的维度有是否开通会员、是否是认证车主、开通了哪些增值服务等;货的维度有商品类型(整车、实物商品、虚拟商品等),交付方式(核销、兑换、4S 店交付)等;场的维度有线上下单、线下下单、在哪个线上商城下单,在哪个交付店下单、商品投放渠道来源等。根据这些维度确定了唯一的业务身份后,每笔交易的业务流程就确定下来了。
电商业务中台整体采用微服务架构、将整个电商系统拆分为商家中心、用户中心、商品中心、促销中心、交易中心、履约中心、售后中心。每个中心在逻辑上分成了带有业务属性的能力和不带业务属性的基础能力两层。基础能力层关注领域模型的实体属性、行为、事件,不会随着业务的需求调整而发生变化,聚焦于行业共性行为、收敛业务模型,保障基础服务的稳定性。带有业务属性的能力是在基础能力层之上通过服务组合、流程编排之类的技术手段,构成面向业务的解决方案,完成业务共性到个性化的转变。有两种常见的做法如下:
其一是使用硬编码来实现。随着不同业务线的逻辑不断增加,各个业务能力调用的基础能力会变得盘根错节,很难做到可配置、灵活化。当发生需求变更的时候,测试人员很难评估修改的影响范围,回归测试的成本周期长,这样很难真正做到敏捷开发、快速响应业务。
其二是使用服务编排。通过服务编排现有微服务进行服务组合服务,然后一次性的返回前台需要的信息。不同业务线的能力执行不同的流程,通过图形化、XML、JSON 的编排框架,即可以让流程清晰,也可以屏蔽代码细节。
服务拆分的好处无需赘述,但是要实现业务价值,不是看单个服务的能力,而是要协调所有服务保证企业端到端业务流程的成功。业务中台是企业业务的集成平台,集成技术必须松散地耦合组成流程的应用程序和资源,否则流程的逻辑将被硬编码到特定的技术平台中,更改可能代价高昂,从而违背业务流程复用的整个目标。
在服务编排领域,已经有很多工业界解决方案,我们参考了基于 API 网关的服务编排 [13],基于工作流系统的编排框架 Flowable 和 Activiti [14]、基于微服务架构编排框架的 Netflix Conductor [16] 和 Zeebe [17]。通过对技术原理进行分析,发现它们都存在某些程度上的不足,无法应用到电商业务中台的服务编排,最终我们选用 Apache Camel [18] 做为服务编排的底层引擎进行二次封装开发。
Apache Camel 诞生于 2007 年,2009 年前后成为 Apache 顶级项目更名为 Apache Camel,目前最新版本是 3.0。Apache Camel 的优点在于在发布后十多年的时间里,已经拥有三百多种扩展组件;扩展机制也极其方便和灵活;通过开箱即可用的最佳实践来解决应用集成问题;它基于事件驱动的架构,有着良好的性能和吞吐量 [19]。
以下是一个简单的服务流程编排样例:
业务中台使用服务编排技术一方面可以将交易的能力自动识别出来作为组件可视化的呈现,形成能力地图;另一方面,基于这些基础能力实现服务流程的编排,能够通过拖拉拽的方式快速搭建出适合业务的全部或者部分交易流程,类似积木,复用基础组件,灵活搭配,进而实现电商企业级能力的复用,节约开发成本,快速赋能业务的目标。
扩展点的全称是 Service Provider Interface,简称为 SPI。是 Java 提供的一套用来加载和运行第三方扩展的接口实现类的机制,一般用在组件替换和框架扩展的场景。SPI 将服务接口与服务实现分离以达到解耦、提升了应用程序的可扩展性。在程序设计中,模块之间采用面向接口编程而不做具体的实现类引用,通过动态加载实现类达到应用程序的插件化。
COLA 框架是阿里巴巴技术专家提出的一种应用架构的扩展点框架 [20]。COLA 框架的扩展是通过注解的方式来实现的,Extension 扩展注解里面使用用例(useCase)、业务(bizId)、场景(scenario)三个属性用来标识身份。使用 COLA 框架的扩展点可以在代码层面支持不同业务身份的逻辑隔离,因为不同的逻辑分散在不同的实现类里面,符合软件设计的开闭原则。
COLA 框架在应用 Spring 上下文初始化完毕阶段,开始扫描带有 Extension 注解的 bean 进行扩展点注册,以 Map 的结构存储,Key 是 useCase、bizId、scenario 的字符串拼接,value 是该 bean。
在运行时,通过业务身份定位扩展点实现类,然后执行扩展点实现的逻辑。定位扩展点支持三层路由,首先会按照 useCase+bizId+scenario 找扩展点实现,如果没有则按照 useCase+bizId+scenario 默认值查找,如果还未找到则根据 useCase+bizId 默认值 +scenario 默认值查找,具体原理如图所示:
对于简单的业务场景,对应用系统的高扩展性、业务隔离的非功能性要求并不多。但是随着同一应用系统支撑的业务变多、业务场景变复杂,在架构层面需要提供统一的扩展解决方案,将变化的业务规则固化下来,这不仅有助于统一技术规范,还能减少硬编码的 IF-ELSE、策略模式等因开发人员水平不一致带来的理解上复杂度、规范上的一致性。
通过扩展点机制,业务中台就可以从业务身份和框架层面实现对不同的业务的管理,像 SaaS 管理租户一样管理业务,不同业务身份在不同场景下对预定义的扩展点进行扩展。阿里巴巴的业务中台也正是基于扩展点的思想,实现的核心业务逻辑和技术细节的分离和解耦,共享事业部才能对集团内几百条业务线进行支撑的。
在验证功能后对电商交易系统的的场景进行了分类,首先选取用户感知度小、即使出问题也对用户影响最小的节点进行重构试用,如未支付订单超时关闭、用户取消订单。
以用户取消订单场景为例,在修改前各业务的用户取消订单的逻辑为修改订单状态为已取消状态然后执行同一个流程,流程的执行顺序为硬编码,伪代码如图所示:
修改后根据各业务的特性的进行了精细编排,如二手车业务没有使用优惠券的场景,那么就不需要再有这个环节;在积分这个通用能力上,扩展的是万里通积分。伪代码如图所示:
旅行家业务线的的酒店、机票业务无传统的商品库存的概念,那么就不再需要还商品库存的操作,而是抽象一个新的通用能力:取消供应商订单,并预置了取消酒店供应商订单的扩展以及取消机票供应商订单 2 个扩展点。伪代码如图所示:
整个系统的应用效果明显,主要体现在性能提升和人效提升。性能提升主要体现在系统的响应时间变短,在修改后取消订单的接口的生产环境的 TP99 的值提升百分比约为 30%。人效提升方面主要体现在取消订单增加新流程节点的测试所用的时间对比,在修改前,各业务流程之间的代码是耦合的,修改流程增加新节点需要对以前的各业务进行回归测试,修改后不需要进行各业务的回归测试。
在平台化架构实践中我们将那些影响业务流转的核心配置统一提取出来,并按照业务身份进行属性值的配置,确保整个交易流程链路的标准统一,减少对交易核心链路代码的频繁修改,不同业务根据不同的属性值在相同的交易流程中的不同节点进行灵活切换。
比如:商品是否自动推送到资源池、下单是否需要填写身份证、支付成功是否推送线索、超过 N 天未确认收货是否自动确认收货完成等等,所有配置项均通过配置管理后台进行统一维护。此外,对于电商中台中包括业务身份在内的所有元数据,我们也通过配置管理后台进行了统一的管理并提供统一的 API 对外提供查询服务。
从业务和技术的多维度出发,针对日常工作中出现的常见业务问题或者技术问题,研发出各类实用便捷的小工具,实现工作效率的提升、问题的快速定位等效果,比如:消息分发、检索工具;商品优惠价格速算工具;商品展示价格比对监控工具;缓存管理工具;一键降级工具等等。随着大家工具化意识的不断提升,这类小工具不断的出现并汇集在一起,就构成了研发人员必不可少的工具箱。
电商系统的性能指标、资源利用率指标、调用量等系统维度的指标通过公司云平台能够实现统一的监控,对于业务数据同理,我们需要提供统一的业务数据可视化工具,为业务方提供做相关决策的参照依据。
为此,我们采用实时 + 离线的方式开发了订单可视化大屏系统,通过这个系统能够按照业务线、订单状态、区域等多个维度实时监控订单量的变化情况。如果固定时间段内的订单量波动超过了我们事先配置的阈值,还会发送钉钉消息及时通知业务方关注。
此外,对于离线数据,我们也是按照日、周、月等从多个维度进行数据统计分析,最终会以邮件和办公级 App 消息的形式发送给业务方,这些手段的目的都是为了实现电商数据的可视化管理,为业务使用方提供更多便捷的工具对电商业务进行全方位的管控。
我所在的这个团队在公司内部的电商领域是一个专业的团队,多年来积累了很多技术以及产品运营层面的经验。在整个电商中台的建设过程中,我们也是将这些经验以及日常问题的解决办法,作为一种财富不断的沉淀,以往都是采用 wiki 这种文档管理工具进行汇总。
为了能够让这些知识产生价值,我们也开始搭建自己的电商知识库系统,将所有能够作为知识沉淀的内容,按照不同的领域分类录入到知识库系统内,整套知识库对外提供了快速检索和定位的功能,能够服务于技术人员、产品运营人员,进一步培养大家知识积累的意识,提升大家的工作效率。
二十年前,互联网刚开始在中国流行,信息都是通过资讯的方式展示,几乎没有在线交易;十年前,互联网经过快速发展,消费者可以在淘宝、天猫、京东为代表的在线商城上购买自己需要或喜欢的商品进行在线交易;而如今各种电商形态不断涌现,已成百花齐放的趋势,比如内容电商小红书、兴趣电商抖音快手,社交电商微商、拼多多等,会员电商天猫 88vip、京东 plus 等。这些在线交易形态充分证明了电商在互联网领域流量变现的重要一环,已经成为互联网企业基础设施的水电煤。
电商中台的建设不光是一个技术体系的搭建,也是一个组织结构重新塑造的过程。但是随着时间的推移,中台其价值的增长空间会愈发狭窄,这就需要有意识的寻找创新点,突破现有系统的边界,跨界思考,于是我们也开始与前台业务走的更近,积极开展对新业务探索和技术架构升级。
在过往探索汽车电商的业务模式,我们发现核心痛点在无法绕过 4S 店提供服务。近年来特斯拉和国内造车新势力的异军突起,新兴的直销模式一举打破传统车企 4S 经销体系的生态;国内购车群体也日益年轻化让我们看到了线上订车 + 线下交付的新零售模式正在变成可能。
通过升级电商系统的现有能力,商品支持了 SKU 选配,订单支持大小定金组合支付、退款,新增交付系统,为工业协会定制车业务、汽车新零售线下店的业务提供了业务支持。未来还会继续打造业界对齐的新能源选配价格浮动模式以及商品可选配套的服务包模式。
在原有的电商交易下单流程中,设计对外的服务都是颗粒度比较小的原子化服务,这就导致了业务方接入成本比较高,用户体验也不太好。未来我们将会通过增加 BFF 层、精简调用链、电商接入脚手架等技术手段提升业务的产品力以及运营效率。
引用
[1] 盘点:2010-2020 年互联网的十大战役
[2] 汽车之家:从“吸引眼球”向“电商平台”拓展
[3] 之家学宫: 汽车电商商品系统构建实践
[4] 之家学宫: 百万级汽车电商交易系统构建之路
[5] 之家技术: 高可用红包系统构建实战
[6] 之家技术: 电商技术团队云原生实践
[7] 之家技术: 新车电商测试数据自动化实践
[8] 之家技术: 电商秒杀系统的系统架构
[9] 之家技术: 汽车之家发票总库 DDD 实践
[10] ThoughtWorks: 现代企业架构白皮书
[11] 美团: 业务中台之订单平台化建设实践
[12] 有赞: 中台如何助力标准化业务
[13] 吴润. 基于 API 网关的微服务组合策略研究 [J]. 数码世界,2019(03):84-86.
[14] 辛园园, 李俊晖, 李阵. 微服务组合方法研究进展 [J]. 无线通信技术,2018,27(03):42-46.
[15] 杨光.Activiti 工作流框架在 OA 系统中的应用 [J]. 电子设计工程,2021,29(11):65-69.
[16] Conductor 官方网站. Conductor 官方文档 [EB/OL].
[17] Zeebe. Zeebe 源码 [EB/OL].
[18] Apache Camel 官方网站. Apache Camel 官方文档 [EB/OL].
[19] Amaral C J , Bernardes S P , M Conceição, et al. Finding new routes for integrating Multi-Agent Systems using Apache Camel. 2019.
[20] COLA 应用架构的最佳实践
方利 汽车之家高级研发工程师
2016 年加入汽车之家,先后负责过电商 ERP 系统、商家系统、线索系统、订单中心、AIDCC 的研发和架构,现主要负责电商交易系统的整体技术架构升级和业务处理等工作。