秒杀场景下订单中心的架构设计( 二 )

步骤 3:根据订单号查询轮询下单结果说明

  1. order-core(订单核心服务)提供根据订单号查询订单是否已创建接口(/order/is-created)
  2. 该接口返回报文应包括,订单号、订单创建状态(创建中,创建成功,创建失败)、创建失败原因
  3. 前端定时轮询该接口,查询订单是否创建成功,轮询频率可根据实际情况进行调整,比如 20ms 一次
  4. 轮询到订单创建成功,可直接唤起支付,失败则直接提示失败信息
核心表分库1. 以订单主表和订单明细表为例进行分库设计,假如按 32 个库进行分库 。
2. 订单主表和订单明细表通过订单号进行关联 。
3. 分库要求:
  • 某个用户的所有订单在同一个库,避免跨库查询(可根据用户 id——buyerId 定位到分库编号)
  • 某个商家的所有订单在同一个库,避免跨库查询(可根据商家 id——sellerId 定位到分库编号)
  • 可以根据订单号查询(可根据订单号定位到分库编号)
4. 按照以上分库要求,做出以下分库设计
  • 订单主表进行冗余,订单主表分成用户订单主表(buyer_order)和商家订单主表(seller_order)
  • 用户订单主表(buyer_order)按照 buyerId % 32 进行分库
  • 商家订单主表(seller_order)按照 sellerId %32 进行分库
  • 订单号末位带上分库编号,分库编号为 buyerId % 32
  • 订单明细表(order_detail)按照订单号进行分库,确保同一个订单的明细在同一个库
  • 用户订单主表(buyer_order)同步写入,因为订单是由用户发起的,需要保证实时性 。
  • 商家订单主表(seller_order)建议保证最终一致性即可,可根据实际业务选择同步双写或者通过 MQ 异步写入
5. 分库设计图:
秒杀场景下订单中心的架构设计

文章插图
 
库存扣减方案
  1. 采用预占库存方案:创建订单时预占库存
  2. 库存不足,预占失败,下单失败
  3. 库存足够,预占成功,创建订单
  4. 订单创建成功,扣减库存;创建订单失败或者取消订单,释放库存
库存扣减序列图
秒杀场景下订单中心的架构设计

文章插图
 
库存设置到 redis 中,已 skuId 为 key,变化的数量为值,如:
  1. 将 skuId=10086 的库存值初始化为 100,redis.incrby(10086, 100)
  2. 库存初始化后,只能对库存进行加减操作,不允许做覆盖操作
Redis 如何与数据库中的库存保持一致:
  1. Redis 和数据库的库存保持最终一致性
  2. 库存被预占时,生成库存预占流水,关键字段有,订单号、skuId、预占数量、流水状态有(预占中、已扣减、已释放),预占超时时间,同时可以在 Redis 或者数据库中维护一个 skuId 对应的总预占数量字段,总预占数量 + 预占数量
  3. 订单中心发送库存扣减消息,库存中心消费消息时更新库存流水状态为已扣减,总预占数量 - 预占数量
  4. 订单中心发送库存释放消息,库存中心消费消息时更新库存流水状态为已释放,返还库存到 Redis,总预占数量 - 预占数量
/** * 预占库存 伪代码 * @param orderNo 订单号 * @param skuId sku 标识 * @param quantity 预占数量 */boolean preOccupy(String orderNo, String skuId, int quantity) {boolean isPreOccupySuccess = false;int value = https://www.isolves.com/it/cxkf/jiagou/2022-04-20/redis.decrby(skuId, quantity);if (value >= 0) {// 库存充足// 生成库存预占流水记录//(关键字段:orderNo,skuId,quantity,state(0-预占中;1-已扣减;2-已释放),timeout(超时时间)isPreOccupySuccess = true;} else {// 库存不足,返还刚才预占的库存redis.incrby(skuId, qunatity);}return isPreOccupySuccess;}数据库的库存数量禁止覆盖更新!扣减库存伪 SQL:update stock set stock_num = stock_num - 变化的值 where sku_id = 10086关于释放库存
对一些释放异常的情况,可由库存中心调度服务,找出库存预占流水状态为预占中且预占超时的记录,根据订单号向订单中心确认该订单号的库存是已扣减还是已释放,再进行相应业务处理 。
其他除了以上大的方面设计,分布式事务、幂等、补偿、压测……这些点是大家在设计系统时都需要考虑的,不在本文讨论范围 。


推荐阅读