好多年没有来写东西了,忙成狗,最近闲暇,有点时间,随手写一下之前的项目中的小点;
一方面是做个总结,一方面打发一下时间
出库
库存扣减时机
- 下单扣减 [生成订单]
- 付款扣减
- 预扣库存(实际使用)
预扣库存
并发量较高,流量不直接打到DB,扣减的是 Redis里面的数据,
- 库存数据加载到Redis (前置操作)
- 用户下单,检查 Redis 里面的库存数量; incryby 下单数量后,结果大于0表示有库存,否则下单失败
- 完成支付,订单信息进入队列 A
- 库存服务,监听 A,执行库存出库【记录订单流水,库存扣减】;
- 库存服务完成出库后,推送出库消息到 队列 B
- 监听队列B,出库失败,需要回滚 Redis 库存; 出库成功,则做相应处理
Redis 里面判断有库存但是实际出库失败的场景:库存系统管理员对实际库存进行了修改,比如锁定为不可卖等
秒杀活动,库存扣减
秒数活动,跟普通的库存扣减基本类似,但是需要做一些优化;
因为秒杀活动的特点是:可卖产品少,产品数量少,成功率极低【比如秒杀10部IPhone,可能有10万人下单】
如果跟普通库存扣减一样的流程,可能导致 Redis负载过高,甚至压垮Redis 导致服务雪崩
优化方案
- 限流,后端判断,当收到指定商品的请求数量达到一定限制后,不再接受请求;比如秒杀产品数量为10,后端可以在收到此产品下单请求数为 10 * K 后,不再接收请求,K 的数值可根据业务需要配置
要超过一定数量的,防止有些场景没有走完全流程(如:人下单后不支付),不要在第一层限流就等于实际库存,都会留一些余地
- 数据&服务隔离,将秒杀的活动数据单独拆开存放;防止秒杀活动影响普通订单
Redis 里面判断有库存但是实际出库失败的场景:库存系统管理员对实际库存进行了修改,比如锁定为不可卖等
服务扩展性
可能瓶颈点
- Redis 预扣库存
- 队列消费速度太慢,导致出单太慢
- 入队列阻塞【订单量需特别大】
处理办法
- Redis 横向扩展: 可以根据商品skuID 将不同商品的数据存放在不同的 Redis集群;在下单的时候,根据skuID 进行分流。可以随着订单量的增加而增加Redis 集群的数量。整体流程不用动
- 订单太多,出库成为瓶颈时:增加消费者里面消费者的数量,可以根据 订单号hash 来分配消费者,防止热商品的数据落到同样节点造成的流量倾斜。
- 入队列太慢的时候,例如 Kafka, 可以增加 partion,消息分散在个 partition, 异步发送,增加推送量
入库
- 库存管理员可以对库存数据进行修改
- DB里的真实库存数据进行加减的时候,会同步修改Redis里面的可卖