电商核心订单系统的一些设计思考

7,153 阅读5分钟
黄河远上白云间,一片孤城万仞山。

羌笛何须怨杨柳,春风不度玉门关。

——<<凉州词>> 王之涣

互联网有交易的地方,就有订单。

订单在电商系统中的地位

毋庸置疑,订单系统作为电商的核心,几乎涉及电商的各个系统,地位何其重要。本文将参与订单设计的一些关键技术点进行记录。

订单架构设计

逻辑架构

从用户角度,看订单基本的功能性需求:

数据架构
订单包含的基本信息模块

简化版类图

Payment 支付信息

支付方式、支付号、支付金额、支付状态、支付时间等。

Promotion 优惠信息

优惠方式、优惠金额等。

Delivery 配送信息

收货人、收货地址、收货人电话、快递等。

OrderDetail 订单明细信息

商品、店铺、价格、数量。

Order 订单

用户、下单时间、订单状态等。

AfterSaleOrder 售后订单

部署架构

order-service 订单服务

独立自治,除了MQ服务之外,它不依赖其他服务。订单创建以及状态变化,会通过mq-service发布相应的消息到MQ中,其他需要关注订单的业务订阅MQ即可。

order-gateway 订单网关

对外部服务暴露接口,作为聚合服务,比如搜索订单时,就是通过order-gateway调用搜索服务search-service和order-service,聚合数据后返回给业务方。

开发架构

在这里已order-service为例,列出包结构,供参考

repository 存储包

与底层储存交互,负责数据的增删改查,无业务逻辑

business 业务包

实现业务逻辑处理,无状态,比如,提供订单状态转换的功能

aggregation 聚合包

负责调用business进行业务处理,然后通过repository将业务处理结果保存

controller 控制层

通过调用aggregation完成用户需求

订单状态机

状态机

状态机是对现实世界的抽象,是一个数学模型。有四个要素:

  1. 现态(State): 当前所处的状态
  2. 事件(Event): 触发某个操作的条件
  3. 动作(Action): 条件满足后执行的操作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。
  4. 转换(Transition):就是次态,条件满足后要迁往的新状态。“次态”是相对于“现态”而言的。
订单状态
  1. 订单状态:待付款、待发货、待收货、订单完成、退款中、订单关闭
  2. 订单事件:下单、付款、发货、收货、申请退款、确认退款

状态机:

订单幂等操作

f(f(x)) = f(x) 特点是其任意多次执行所产生的影响均与一次执行的影响相同。

幂等函数,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。

在订单流程中,比如保证下单、支付等状态变化是幂等的。拿下单来说,如果不保证幂等操作,可能因为用户快速提交订单或者网络问题重复请求,会造成有多条订单生成的问题。

保证幂等的手段:

  1. 数据库唯一索引:订单号设置唯一索引
  2. 分布式锁:下单时,已订单号为锁,先去获取分布式锁,拿到锁之后,才能执行下单操作,拿不到锁,直接快速失败响应

订单搜索

订单涉及到买家订单和卖家订单,双方都有查询订单的需求,单库单表还好说,但在单量大了之后,涉及到分库分表,这个时候就不好查询了。

一种解决方案是冗余法,用户下单的时候,基于卖家维度,保存一份订单。

  1. 用户订单表
  • 保存用于列表展示的关键字段,比如:订单状态、下单时间、订单金额、订单数量等,其他明细信息可从订单明细表查询。

  • 以buyer_id(买家标识)为维度进行分库分表

  1. 店铺订单表
  • 保存用于列表展示的关键字段,比如:订单状态、下单时间、订单金额、订单数量等,其他明细信息可从订单明细表查询。
  • 以seller_id(卖家标识)维度进行分库分表
  1. 订单明细表
  • 保存订单明细数据
  • 以order_no(订单号)为维度进行分库分表
  1. 下单同步数据到ES
  • 根据商品标题搜索订单,这个功能是不会直接查询数据库的,一般都是从ES中搜索关键字,返回列表数据。如果看明细,再根据订单号到明细表。
  • 下单的时候,一般会通过MQ将订单数据发到写入搜索引擎

  • 异步写队列,再到ES,会有一定的延迟,产品在设计上要考虑用户体验,一般下单成功会跳到一个成功提示页。

订单与库存

常见有三种减库存方式:

  • 下单减库存
  • 支付成功减库存
  • 预占库存: 下单时预先占着库存,保留一定时间,比如30分钟。订单超时后,库存释放。

这里重点说一下预占库存流程:

  1. 下单时根据订单号预占库存
  2. 支付成功,根据订单号扣减库存
  3. 订单超时,根据订单号释放库存

订单与支付

使用第三方支付的流程

  1. 用户通过微信或支付宝等支付渠道支付成功后,订单的支付状态处于待确认
  2. 通过支付网关异步回调通知更新支付状态
  3. 如果超过一定时间,比如30秒,没有收到支付回调通知,则由订单调度服务主动请求支付网关查询支付结果