电商行业近年来发展势头迅猛,诸多巨头成功上市,业务模式不断升级,促销手段花样百出。双十一成为各路电商运营能力的年度大考,同时也是对电商技术平台能力的极限测试,每年进行了重大改版升级的系统只有经过双十一的枪林弹雨才能浴火重生。
在当当,2015年的双11,面临考验的是促销系统和交易系统,两者都是电商体系的核心组成部分。此次双11专题,InfoQ特别邀请 EGO会员 、当当架构部总监史海峰先生,为大家讲述当当双11背后的技术故事。
另,ArchSummit全球架构师峰会北京站将于2015年12月18日~19日在北京国际会议中心召开,大会设置了《 揭秘双十一背后的技术较量 》专题来深入解读双十一背后的技术故事,欢迎关注。
如今大规模促销已经成为大大小小的电商平台及入驻商家运营的常态。随着业务的复杂化、运营的精细化,以及品类、平台、渠道的不断丰富,各种新的促销形式也层出不穷,贯穿从商品展示、搜索、购买、支付等整个流程,电商对于精细化、精准化促销运营的需求也越来越强烈。
一次促销活动几十万商品,一天之内几十个、上百个促销活动已是家常便饭,至于入驻商家的常态促销更是不胜枚举。双十一期间,电商平台和商家更是会使出浑身解数,火力全开,无品不促销。
促销规则支持分时段设置,多个活动能够叠加,促销系统中的数据量甚至会超过商品信息系统,而且促销内容会根据执行效果快速调整,这些都对促销系统提出了更高的要求,促销系统越强大,促销活动才能玩得越疯狂。
我们在重构前面临的状况,是促销模型比较陈旧、扩展性差,促销系统成熟度低、与其他系统耦合严重,新增一个促销类型可能牵动从单品展示、搜索、推荐、购物车、交易、订单、退换货、库存、价格、促销自身等一系列产品线的变更。因此,促销系统的重构势在必行,数据模型与运营的贴合度决定的扩展性、灵活性,系统解耦和更强大的数据处理能力,是核心改进点。
最基本的促销模型很简单,如下图:
在当当,有一些“类促销”业务,从广义上可以归入促销范畴,但业务与数据均不属于促销系统,在设计中,我们考虑将这类业务逐渐回收;另外,促销系统能不能承担一些营销的功能?带着这两点考虑,在促销基础上进一步抽象出活动模型。
什么是活动?我们认为任何一个有时间范围的事件/动作均可称为活动,活动则抽象为三要素组成:基础信息、维度(条件)、工具(动作)
例如,在11月1日10:00-12:00在第一会议室开双十一准备会,讨论双十一各系统需要准备的事项,需要各系统负责人参加;那么这个活动的基础信息包括时间(11月1日10:00-12:00)、主题(双十一准备会),维度包括地点(第一会议室)、与会人员(各系统负责人),工具(动作)包括议题以及讨论本身。
那么推而广之,理论上,只要有相应的工具对接,可以用这个极简的活动模型,去管理任何一类活动,这样模型就变为了两层:
实际业务中我们遇到过的一些关于促销计算单元的头疼问题。买了一堆商品,到底哪几个应该作为一组计算条件和优惠,在促销叠加的场景这一点显得更为复杂。所以我们引入作用域来定义这个计算单元的范围。例如常规的限时抢促销,每个SKU有自己的价格,那么SKU就是这个促销的计算单元,也就是促销的作用域;例如第二件5折,可能会按SPU来做,你买一个红的一个蓝的,还是能享受促销,那么SPU成为了这个促销的计算单元;诸如此类,现有及未来可扩展的还有店铺、品类、品牌等等。简言之,这个作用域成为促销计算引擎进行计算单元分组的依据。于是模型又变成了这样:
举个例子,我们要在11月11日11:00-12:00针对IT技术类图书进行满200元减100元促销,购买过此类图书的客户每本书每人限购一册。那么这个活动的基础信息包括时间(11月11日11:00-12:00)、主题(程序猿光棍节福利);维度包括商品品类(IT技术)、用户范围(购买过此类图书的客户);工具是满额减促销、以金额满200元为条件、减100元为优惠,此外还有限购策略为限购1本,作用域为参与活动的所有商品;
可能这里会引发困扰,基础信息的时间为何不能算做时间维度?维度也定义了一些限制条件,那和促销工具模型里的条件有什么区别?时间之所以不归入维度,是基于前面对活动的定义,时间范围是必须的,而维度是可选的;促销模型中的条件只对于促销工具有效和有意义,而维度则有更广泛的普适性,例如平台、渠道、地区、用户、商品等,与工具是什么并无关系。
基础模型定型之后,我们开始着手解耦方面的设计:
首先是系统交互解耦,将直读DB和存储冗余促销数据的系统修改为调用服务及监听MQ;然后是逻辑回收,包括将促销校验与促销计算提取为交易服务,将原先由购物车、交易系统自行处理的促销逻辑回收;从业务上,将促销工具的属性进行提取,诸如类型枚举、促销标签、限购策略、库存策略等,以期外围系统尽量少的关注促销类型,通过促销ID拿到所需信息直接使用;未来则关注于业务层面的梳理与整合,逐步回收适用于活动模型的其他“类促销”业务。
系统解耦后,促销系统需要提供各系统所需要的服务,必须具备更强大的数据处理能力和更好的性能表现。应用架构实现上,从前端页面到后端逻辑,尽量避免有逻辑与促销类型直接绑定,全部以插件化方式与促销模型对接,完全根据促销类型的配置进行组装。针对不同维度、条件、优惠、促销属性,定制页面模板及业务逻辑,使得新增一种促销类型(在已有维度、条件、优惠下)仅需配置即可完成。
促销系统的查询服务需要同时为多个系统提供数据,对TPS要求很高,同时促销的时效性又要求很高的实时性。我们采用的方式是在数据库前加Redis缓存,提高响应速度,同时监听MQ,根据事件清理相应的缓存数据。
这种设计方案也有一些可能的坑,例如Redis缓存虽然减轻了DB压力,但对于计算密集型应用并未减轻应用服务器压力,IO没有节省还增加了序列化的开销;事件驱动清理缓存在读写分离场景下,有可能比主从同步更快,造成缓存数据错误。这也是具体应用中需要注意的地方。
促销系统重构上线后,使多渠道(终端)、多区域化营销成为简单易行的配置操作,显著提高了当当运营能力,当当双十一呈现出更多的想象空间。
交易系统是客户购物流程中最重要的环节,主要任务是完成购物车中商品信息获取、拆单、促销计算、配货计算、运费计算、非现金支付的使用以及生成订单等操作,聚合各方面业务逻辑,计算非常复杂,而且响应速度影响购买转化率,一旦出现故障,直接影响营业收入,可谓电商最为敏感的核心系统,决定对其进行重构需要极大的魄力。
当当原有交易系统采用.NET技术框架,运行多年,很好的支撑了购买流程,但是弊端逐渐显露。首先是技术体系属于微软系,每年要花费大量成本购买服务;其次是随着业务需求的不断叠加,其结构及可维护性逐年下降,尤其是众多小版本结算的存在,使得功能扩展异常艰难。
基于以上因素,交易系统团队在2014年底启动重构项目,2015年10月底新老版本完成切换。此次重构耗费约1500人天,重构代码17万行,全部切换至Java开源技术架构,为公司节约大量成本,并进行了架构优化,整体性能平均提升25%。
交易系统业务主流程图如下:
交易系统重构引入了许多业界成熟的技术实现方案,主要有以下几点:
集中化配置方式,一点配置,所有实例可见,更易于管理,而且配置修改后,通过热加载方式,立刻生效,快速便捷。而原有交易系统修改配置后,必须重启系统才能生效。
用户请求一次交易结算页面,会调用各种后端服务,而由于逻辑的复杂性,每次服务调用都会调用订单计算大流程,导致页面刷新缓慢。新交易系统将大流程计算结果进行缓存,在一次页面请求范围内,后续调用直接用缓存结果,极大提高了页面的刷新速度。
由于历史原因,交易系统存在很多版本的结算逻辑。最常用的是统一结算,还有一些特殊类型的结算,如秒杀、一键下单、补发货等等,逻辑与统一结算稍有不同,统称为小版本结算。因小版本结算与统一结算大部分逻辑相同,因此新交易系统将二者合到了一起,共享基础逻辑,而不同的逻辑则单独处理,极大提高了可维护性。
借助了Nginx在运行状态下可以reload配置,而基本不影响对外提供服务的能力。每个Nginx负载两台应用服务器,灰度发布时,将Nginx配置更改为只负载一台应用服务器,即可对另一台进行部署。用户请求不会导向正在部署中的服务器,从而不影响用户下单。
(点击放大图像)
交易系统重构后,尽管进行了大量的测试,仍不能放心部署上线。因为交易系统的计算都和金钱有关,必须慎之又慎,我们提出了线上并行比对方案,根据老交易系统比对新交易,保证其逻辑正确。原理如下:
1) 用户请求到达老交易系统
2) 根据条件将部分请求数据复制,发送至调用mock服务的新交易系统
3) 新老交易同时计算,结果存入各自的数据库,但只有老交易结果对用户公开
4) 对新老计算结果进行比对
这样,既实现了比对目的,又不会影响线上环境。
比对之后,新交易系统也不能立即全面上线,那样可能有巨大风险。我们开发了分流功能,按照用户id来分流,正式分流前,先使用测试白名单中的用户进行预验证。预验证通过后,再按比例由低至高逐步切换。
基于前面所讲的灰度发布技术,新交易系统很容易做到按需伸缩。正常情况下,每个Nginx负载两台应用服务器。双十一需要扩容时,将待扩服务器ip地址加入Nginx配置,重新reload,该Nginx就可负载更多台应用服务器了。
交易系统上线后为备战双十一,确保万无一失,利用老交易系统还未下线的条件进行了线上压测。为达到最准确的测试效果,且不影响正常系统运行,进行了以下的准备:
1. 测试环境、数据与生产环境一致
在准备测试环境方面,为了保证测试结果更接近真实结果,本次测试使用线上环境,通过大量测试账号对线上的真实促销商品进行测试,这样也对新交易系统所依赖的各系统服务做了检验。
2. 线上业务运行保障
测试阶段线上的请求切到老交易系统,压测请求发送到新交易系统,使测试和生产业务进行分离,保证了各自服务器资源的独立性。在应用服务器层面使测试过程不会影响到线上正常交易。
3. 拦截订单回收库存
由于使用线上环境测试,需要对测试订单进行拦截,避免进入生产流程,并回收占用的库存,使商品不会耗尽库存,采用的方法是在自动审单系统中将测试账户加入黑名单,测试订单提交后会被拦截,然后取消订单释放库存。为防止测试过程占用了商品的全部库存而影响线上销售,测试商品池基数很大,并且过滤掉了库存数量较少的商品,在执行测试过程中控制每个商品的使用次数,保证可销售库存占用在安全范围内。
4. 恶意用户策略控制
因为在交易下单过程中包含恶意用户判定的策略,会对用户进行隔离,禁止连续大量下单,线上压测时根据实际情况短时间内调整了安全级别,保证订单成功率。
经过多轮线上压测,新交易系统的高可用性得到验证,得到了实际性能指标,并根据双十一流量估算进行了扩容部署,将以崭新的面貌为广大客户提供稳定可靠便捷的网购服务。
(感谢周裕杰、王胜军、马铁强对本文内容提供支持)
感谢郭蕾对本文的策划和审校。
给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ,@丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入InfoQ读者交流群 )。