电商诞生已经有20多个年头了,从早期很多人的质疑、骗子、不接受、甚至肄业排斥、打压,到现在彻底融入我们生活的方方面面,并号称中国的 “新四大发明”,“认知教育”使命已经完成。人们足不出户,网上下个单,就可以在家坐等收包裹,确实是一种享受。
今天就跟大家聊聊电商技术里面最重要的交易部分
购物车
下单
付款
库存
优惠
收获地址
订单管理
退款
成交记录
评价
1、创业早期,人手资源都比较缺乏,讲究灵活策略,为了快速上线,通常会采用集中式系统架构。等后面业务稍微稳定些,再喘口气慢慢做系统架构衍化、升级。
2、电商业务比较特殊,贴近生活,特别是经过十几年的淘宝电商教育,人们对网上购物已经形成习惯,如果你做垂直电商、社区电商、生鲜电商,虽然是切入部分人群,但高频交易依然会产生海量数据,底层存储设计要提前预留扩展。
3、电商营销活动总是特别多,市场同学经常搞个大促、秒杀,要注意高并发流量设计
4、电商的业务玩法总是特别多,要学会抽离共性组件,模块化,采用流程引擎灵活满足不同业务诉求
5、古话说得好,船小好掉头。臃肿庞大的系统、复杂历史包袱,不但协同效率低下,而且稳定性、扩展性也比较差。“拆” 是不可避免的选择,按DDD设计思想,确定好限界上下文,拆分一系列子域,如:会员域、商品域、交易域、库存域、支付域、物流域、营销域等等。
当然,随着业务的日积月累,子域系统逐渐复杂起来,可能还需要进一步拆分子子域。所以说,“复杂的系统架构都是随着业务发展逐渐演化而来的!”
交易流程
1、正向流程

用户添加购物车分为登录态和非登录态,登录态好理解,将商品及购买数量关联到用户id上。对于非登录态,server端会创建用户临时token标识,除了关联商品记录外,还会将标识缓存到客户端。如果处于登录态,会将临时表的数据合并到购物车表。
新创建的订单会放入超时表,由定时任务扫描记录,未付款超时执行订单关闭,释放库存
购物车批量下单,如果涉及多个店铺,会进行拆单
发货环节,如果涉及多个商品,可能会拆包分批发货,关联多个物流单
对于恶意刷单要接入风控处理
2、逆向流程

1、任何事物都有自己的生命周期,透过现象直达本质,可以帮我们以较低成本解决很多难题。交易订单分为在线库(只保留近三个月的订单数据),对于超过三个月且状态结束(交易成功、交易关闭)的订单会移到归档库中,大大提高了查询性能。
2、电商平台一般发展比较迅猛,如果再搞点市场活动,订单数据是比较容易出现因为单个数据库表中的数据量过大而造成性能的瓶颈。如何选择分表键,买家uid、还是订单id、又或者是卖家uid,貌似都无法满足所有的业务场景。
可以参考淘宝的做法,规则最大化适用原则,订单号拆成两部分,前面为全局唯一自增id,后面为买家id的后六位,分表键按照买家uid的后6位来计算,未来最大支持扩展100万张逻辑分表。可以支持按订单id或买家uid来查询,至于卖家部分,采用数据异构方式,将卖家uid及订单id放入另一张数据表中。

3、大多数业务都是读多写少,如果访问性能开始出现瓶颈,可以考虑一主多从、读写分离等优化策略
主从存储间数据同步都是异步操作,如果延迟较大,很容易影响用户体验。对于实时性要求较高的业务,可以依赖主库,或者借助缓存。
4、系统拆分
基础业务逻辑下沉到服务,业务模型需要统一抽象,能支持定制扩展。比如,对不同规格优惠券原子性拆分、动作类型定义,数据重组。非核心数据可以考虑复合字段,数据异构化并考虑引入搜索,满足多维度查询。
Web 产品层专注表示逻辑和编排,可以借助 SPI 业务框架、流程引擎、规则引擎等这些基础业务框架,在业务支撑上做到了灵活可扩展。系统也做了比较合理的分层,每层只需要关心本层所需关注的能力即可。
5、复杂且较多外部RPC依赖,如何保证全局性的事务处理,最直接场景就是交易的下单。

营销优惠券服务、库存服务、下单服务是分开部署。交易创建流程中,订单、券和库存的状态必须要保证一致性
调用券/库存服务超时/失败,异步发消息通知回滚;复杂性可控
MQ 生产端发送失败,可以重试,消息框架要采用幂等性生产者 。消费端通过ACK 机制保证最终一致
消除了二阶段提交等分布式事务框架的侵入性影响
最后一步的数据库订单置为 “可见” 要采用事务性消息,保证一致性。
注意:也可能存在优惠券预冻结后,交易这边的服务器宕机了,废单消息没有发送成功。此时可以参考RocketMQ的回查机制,通过轮询任务,扫描出相关记录,反查订单状态,决定最终提交或回滚。
6、支付环节如何保证多节点间数据一致性。采用消息+异步任务补偿

7、如果业务逻辑复杂,内部涉及大量的接口调用,串行调用等待时间较长,如果各个节点间没有依赖关系,可以考虑并行化处理。

大促活动时,提前对缓存预热,借助缓存的高性能抗住大部分访问压力。
本文作者:TomGE 来源:微观技术
CIO之家 www.ciozj.com 微信公众号:imciow