对订单系统的一些思考

订单是什么

  • 订单是交易的快照信息,用于记录交易发生时的相关信息

订单一般包含哪些信息

  • 用户:商品或服务的消费者
  • 商家:商品或服务的提供者
  • 物品:交易涉及的商品或服务的名称、属性及描述信息
  • 价格:物品的价格,根据需要可以分为原始价格、单位价格、最终价格等
  • 优惠:商家提供给用户的用于减免价格的行为描述,一般包含折扣、代金券、抵扣券等各种类型
  • 时间:一般包含交易发生与结束时间、支付发生与结束时间、物品发货与完成时间等
  • 支付流水号:凡是涉及支付行为的订单,一般都需要与支付流水号相关联,支付流水号一般由其他系统维护,记录支付渠道、账户变更等信息

订单的常见状态与主要流程

订单状态迁移

  • 创建:用户通过前台售卖页面或API发起下单请求,订单系统根据请求内容创建新的订单,此时订单的状态为“初始化”
  • 支付:若订单最终需要支付的金额不为0,则一般由用户通过前台售卖页面或API发起支付请求,订单系统调用外部支付系统发起支付,若支付请求是同步的,则可根据支付成功与失败决定订单新的状态,若支付请求是异步的,一般需要先将订单状态切换为“支付中”,后续通过订单系统轮询或支付系统回调的方式获取支付结果
  • 发货:已支付的订单或者不需要支付的订单,系统可直接进行发货,发货结果一般由订单系统轮询或外部系统回调进行更新
  • 退款:用户通过前台管理页面或API发起退款请求,一般仅当订单处于“发货完成”或“发货失败”时才可进行退款
  • 查询:用户通过前台售卖页面或API,查询符合条件的单个或多个订单
  • 取消:处于“初始化”状态的订单,一般可由用户主动取消,若订单超过一定时间未支付,系统也可自动取消
  • 删除:对于“已取消”或“已退款”状态的订单,用户可通过前台管理页面或API进行删除,后续查询请求无法获取“已删除”状态的订单

订单系统的安全问题

  • 权限校验:用户任何操作都需要先鉴权,用户仅能操作自己的订单
  • 操作频率限制:系统针对用户特定操作必须有频率限制,若发现异常请求需要能主动拒绝
  • 通用参数校验:对每一个订单相关的通用参数都需要做类型与取值范围的基础校验,同时需要考虑参数与业务逻辑的相关校验
  • 业务参数校验:通常用户购买的商品都会有特定的属性,这些属性必须是合法且有效的,不能信任前台带过来的任何参数
  • 操作日志:用户在何时进行了何种操作,系统都需要记录下来
  • 数据备份:订单数据库需要避免单点问题

订单系统的性能问题

订单号的生成

  • 订单server通常需要分布式部署,但订单号必须是全局唯一的,这就要求有特定的算法用于处理订单号的生成规则,一般可以考虑时间戳、随机数、机器ID等因素的组合

读写分离

  • 普通的订单系统一般是读多写少,对于常见的数据库一主多备部署方式,写请求由主库处理,读请求则分散到各个从库处理

缓存

  • 为减轻数据库的压力,可考虑引入缓存,但缓存会增加系统复杂度,重点需要考虑缓存的更新问题

数据大结点

  • 对于to B的订单server,可能10%的用户覆盖了90%的订单,这种情况下订单表分布是极不均匀的,即使命中索引,数据库处理速度仍然不满足要求,这种情况下需要根据使用场景,引入缓存或特殊逻辑处理这些大结点

分布式事务

  • 订单server与数据库一般是独立部署的,不同server之间通过网络调用进行通信,必然会出现各类异常情况,此时可引入分布式事务,解决各个server之间状态不一致的问题,但分布式事务会增加系统复杂度,同时可能导致性能问题,需要根据实际场景做好评估

其他需要考虑的点

  • 接口可重入:订单server对外提供的接口必须是可重入的,网络超时重试是必然会出现的