转促销系统与交易系统的重构实践

如今大规模促销已经成为大大小小的电商平台及入驻商家运营的常态。随着业务的复杂化、运营的精细化,以及品类、平台、渠道的不断丰富,各种新的促销形式也层出不穷,贯穿从商品展示、搜索、购买、支付等整个流程,电商对于精细化、精准化促销运营的需求也越来越强烈。

一次促销活动几十万商品,一天之内几十个、上百个促销活动已是家常便饭,至于入驻商家的常态促销更是不胜枚举。双十一期间,电商平台和商家更是会使出浑身解数,火力全开,无品不促销。

促销规则支持分时段设置,多个活动能够叠加,促销系统中的数据量甚至会超过商品信息系统,而且促销内容会根据执行效果快速调整,这些都对促销系统提出了更高的要求,促销系统越强大,促销活动才能玩得越疯狂。

我们在重构前面临的状况,是促销模型比较陈旧、扩展性差,促销系统成熟度低、与其他系统耦合严重,新增一个促销类型可能牵动从单品展示、搜索、推荐、购物车、交易、订单、退换货、库存、价格、促销自身等一系列产品线的变更。因此,促销系统的重构势在必行,数据模型与运营的贴合度决定的扩展性、灵活性,系统解耦和更强大的数据处理能力,是核心改进点。

最基本的促销模型很简单,如下图:

在当当,有一些“类促销”业务,从广义上可以归入促销范畴,但业务与数据均不属于促销系统,在设计中,我们考虑将这类业务逐渐回收;另外,促销系统能不能承担一些营销的功能?带着这两点考虑,在促销基础上进一步抽象出活动模型。

什么是活动?我们认为任何一个有时间范围的事件/动作均可称为活动,活动则抽象为三要素组成:基础信息、维度(条件)、工具(动作)

例如,在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%。

交易系统业务主流程图如下:

交易系统重构引入了许多业界成熟的技术实现方案,主要有以下几点:

1. 集中化配置

集中化配置方式,一点配置,所有实例可见,更易于管理,而且配置修改后,通过热加载方式,立刻生效,快速便捷。而原有交易系统修改配置后,必须重启系统才能生效。

2. 页面缓存技术

用户请求一次交易结算页面,会调用各种后端服务,而由于逻辑的复杂性,每次服务调用都会调用订单计算大流程,导致页面刷新缓慢。新交易系统将大流程计算结果进行缓存,在一次页面请求范围内,后续调用直接用缓存结果,极大提高了页面的刷新速度。

3. 小版本合并

由于历史原因,交易系统存在很多版本的结算逻辑。最常用的是统一结算,还有一些特殊类型的结算,如秒杀、一键下单、补发货等等,逻辑与统一结算稍有不同,统称为小版本结算。因小版本结算与统一结算大部分逻辑相同,因此新交易系统将二者合到了一起,共享基础逻辑,而不同的逻辑则单独处理,极大提高了可维护性。

4. 灰度发布、无缝切换

借助了Nginx在运行状态下可以reload配置,而基本不影响对外提供服务的能力。每个Nginx负载两台应用服务器,灰度发布时,将Nginx配置更改为只负载一台应用服务器,即可对另一台进行部署。用户请求不会导向正在部署中的服务器,从而不影响用户下单。

(点击放大图像)

5. 并行比对

交易系统重构后,尽管进行了大量的测试,仍不能放心部署上线。因为交易系统的计算都和金钱有关,必须慎之又慎,我们提出了线上并行比对方案,根据老交易系统比对新交易,保证其逻辑正确。原理如下:

1) 用户请求到达老交易系统

2) 根据条件将部分请求数据复制,发送至调用mock服务的新交易系统

3) 新老交易同时计算,结果存入各自的数据库,但只有老交易结果对用户公开

4) 对新老计算结果进行比对

这样,既实现了比对目的,又不会影响线上环境。

6. 分流

比对之后,新交易系统也不能立即全面上线,那样可能有巨大风险。我们开发了分流功能,按照用户id来分流,正式分流前,先使用测试白名单中的用户进行预验证。预验证通过后,再按比例由低至高逐步切换。

7. Web服务器按需伸缩

基于前面所讲的灰度发布技术,新交易系统很容易做到按需伸缩。正常情况下,每个Nginx负载两台应用服务器。双十一需要扩容时,将待扩服务器ip地址加入Nginx配置,重新reload,该Nginx就可负载更多台应用服务器了。

交易系统上线后为备战双十一,确保万无一失,利用老交易系统还未下线的条件进行了线上压测。为达到最准确的测试效果,且不影响正常系统运行,进行了以下的准备:

1. 测试环境、数据与生产环境一致

在准备测试环境方面,为了保证测试结果更接近真实结果,本次测试使用线上环境,通过大量测试账号对线上的真实促销商品进行测试,这样也对新交易系统所依赖的各系统服务做了检验。

2. 线上业务运行保障

测试阶段线上的请求切到老交易系统,压测请求发送到新交易系统,使测试和生产业务进行分离,保证了各自服务器资源的独立性。在应用服务器层面使测试过程不会影响到线上正常交易。

3. 拦截订单回收库存

由于使用线上环境测试,需要对测试订单进行拦截,避免进入生产流程,并回收占用的库存,使商品不会耗尽库存,采用的方法是在自动审单系统中将测试账户加入黑名单,测试订单提交后会被拦截,然后取消订单释放库存。为防止测试过程占用了商品的全部库存而影响线上销售,测试商品池基数很大,并且过滤掉了库存数量较少的商品,在执行测试过程中控制每个商品的使用次数,保证可销售库存占用在安全范围内。

4. 恶意用户策略控制

因为在交易下单过程中包含恶意用户判定的策略,会对用户进行隔离,禁止连续大量下单,线上压测时根据实际情况短时间内调整了安全级别,保证订单成功率。

经过多轮线上压测,新交易系统的高可用性得到验证,得到了实际性能指标,并根据双十一流量估算进行了扩容部署,将以崭新的面貌为广大客户提供稳定可靠便捷的网购服务

时间: 2024-10-29 19:05:33

转促销系统与交易系统的重构实践的相关文章

Cobbler无人值守安装系统史上最细实践文档

本文档来自老男孩教育VIP课程 内部学员总结笔记文档笔记内容,和大家分享! 老男孩教育2016年全干货博客,http://blog.oldboyedu.com Cobbler无人值守安装系统史上最细实践文档 http://blog.oldboyedu.com/autoinstall-cobbler/

电子商务-促销系统

促销系统的主要作用:主要提供商品的促销优惠价格,如果该商品没有促销,就提供商品的原价. 促销类型: 直降促销:限时直降,限时限量直降 满额促销:满减,满折 套装促销 (多个商品一起买,N个商品享受优惠 赠品(买N赠N) 秒杀 促销规则: 限制条件: 商品限制:SKU,SPU,品类,品牌,商家 用户限制:pin ip限制 由于促销提供商品的价格,当用户每次浏览商品页面,可能对促销系统的访问多达几十次,所以对促销的高并发要求非常高. 为了及时响应前端的请求,读取数据,计算都应该尽量的快和简单. 由于

Android弹幕实现:基于B站弹幕开源系统(4)-重构

?? Android弹幕实现:基于B站弹幕开源系统(4)-重构 弹幕在视频播放的APP中比较常见,但是逻辑比较复杂,现在在附录1,2,3的基础上,我再次对弹幕进行抽象和重构,把弹幕从底向上抽象成不同的层,便于复用. 第一步,抽象数据层.通常弹幕的来源是来源于后台的数据接口请求,在实时直播时候,是通过网络的轮询机制获取数据,那么,我把这部分代码抽出来设计成一个MGDanmakuHttpController,该类专注于数据的获取与分发: package zhangphil.danmaku; impo

重构实践——为了try-catch大兴排场

可能是我们共同的强迫症,不要说看到,就算想到太多的try-catch也很难接受. 于是,开始了一些尝试,这些尝试都算是思维的锻炼.场面的见识.经验的积累. Version1 —— 原始版本 一开始,在ConcreteService中,拥有了太多的try-catch,而影响码字的兴趣. 代码1 原始代码 /// <summary> /// 契约 /// </summary> public interface IUpdateManyManyThingContract { bool Up

RedHat / Centos &nbsp; Linux 系统运维与管理实践技巧荟萃,持续更新

RedHat / Centos   Linux  系统运维与管理实践技巧荟萃

从零开始--系统深入学习android(实践-让我们开始写代码-Android框架学习-7.通知)

通知 一个通知是一条消息他是显示于你应用程序之外的一个界面中.当你告诉系统要发布一个通知时,它首先作为一个icon出现在通知区域.为了看见通知的细节,用户可以点击通知区域展开一个新的界面.下面让我们来看一下图7-1和图7-2: 图7-1 通知出现在通知区域 图7-2 通知展开后的效果(drawer) 注意:除非特别注明外,本章指的都是NotificationCompat.Builder,它在v4 Support Library中有,正式添加于API Level 15.但有了v4 Support

分布式开放消息系统(RocketMQ)的原理与实践

分布式消息系统作为实现分布式系统可扩展.可伸缩性的关键组件,需要具有高吞吐量.高可用等特点.而谈到消息系统的设计,就回避不了两个问题: 消息的顺序问题 消息的重复问题 RocketMQ作为阿里开源的一款高性能.高吞吐量的消息中间件,它是怎样来解决这两个问题的?RocketMQ 有哪些关键特性?其实现原理是怎样的? 关键特性以及其实现原理 一.顺序消息 消息有序指的是可以按照消息的发送顺序来消费.例如:一笔订单产生了 3 条消息,分别是订单创建.订单付款.订单完成.消费时,要按照顺序依次消费才有意

互联网金融系统技术沙龙:小米风控实践

导读:最近上映的 魔兽世界有一句话"光明源于黑暗,黑暗涌现光明",和互联网金融的安全风控领域非常相似.在 6 月 19 日,微博商业产品部联合小米支付等金融技术团队策划了首届互联网金融系统沙龙,围绕在互联网金融过程中碰到系统安全等问题与业界展开分享及交流.本文是邓文俊在沙龙上的演讲,授权高可用架构首发. 邓文俊,小米高级研发工程师,2013 年加入小米,参与了数据后台,风控系统,支付等系统的研发工作. 我来自小米支付,今天分享的主题是小米风控实践.为什么选风控这个题目?其实在我看来风控

分布式开放消息系统(RocketMQ)的原理与实践(转)

转自:http://www.jianshu.com/p/453c6e7ff81c 分布式消息系统作为实现分布式系统可扩展.可伸缩性的关键组件,需要具有高吞吐量.高可用等特点.而谈到消息系统的设计,就回避不了两个问题: 消息的顺序问题 消息的重复问题 RocketMQ作为阿里开源的一款高性能.高吞吐量的消息中间件,它是怎样来解决这两个问题的?RocketMQ 有哪些关键特性?其实现原理是怎样的? 关键特性以及其实现原理 一.顺序消息 消息有序指的是可以按照消息的发送顺序来消费.例如:一笔订单产生了