秒杀核心时序图
2022-01-27 10:24:49 2 举报
秒杀核心时序图
作者其他创作
大纲/内容
1、同一IP/用户频率限制(比如5S)防止多次点击,或程序脚本暴力请求2、黑名单识别下单不支付用户3、限流过载保护
4、订单状态查询短轮询
查询
Gateway
返回订单号
关键信息:场次、商品ID、数量、UID、单据号(多条同个单据号,下单不支付回滚用)
传递抢购参数
交易中心
有效性判断条件限制重计算验证
处理下单
1、商品是否存在2、多次参与判断3、有效期判断4、条件限制轻计算判断5、库存判断超过库存容量,提示已售罄,提前挡流6、写入MQ队列7、redis打标识(排队中),KEY: ${UID}+${场次ID}
查询缓存,获取资格标志(排队中,抢购成功,抢购失败)KEY: ${UID}+${场次ID}
生成抢购记录下单时购买资格验证
返回接受成功与否,告知客户端发起轮询下单状态
传递单据号及其他下单参数
1、发起秒杀获取资格
1、直接更新数据库,利用行X锁示例SQL:update x set stock=stock-{counts} where itemid=${itemid} and stock >= ${counts}2、发送库存变更消息(便于集群实例更新本地全局库存)3、更新全局库存缓存,减少数据库读写压力(更新前判断,减少数据库没必要开销)4、条件限制等判断无效时、扣库存失败(SQL更新条数为0),redis打标识,记为抢购失败(便于轮询快速获取资格)5、MySql记录抢购记录6、若负载过高,可拆离MQ消费者独立部署运行7、死锁对于一次请求同时多个秒杀商品的情况,可能出现死锁,更新库存作为独立事务,分多次更新。由此产生的问题,既其中一个更新失败,前头已经更新的需要手动回滚8、关闭MySQL死锁检测虽然关闭死锁检测,在多数场景对业务是有损伤的,但秒杀场景下,数据读写比较单一,业务比较集中,可以使用独立的数据库,关闭死锁检测,利用锁等待超时及业务代码规避死锁,对秒杀集中写单一数据,是比较好的选择9、锁冲突异常重新消费,利用rocketmq重试及业务限制次数10、拆多份库存(暂不实现,编码要求高,编码不严谨容易导致库存混乱)如,100库存,每人限制2,按2的倍数,每份分20库存,插入10条记录。更新上能分散锁竞争,及利用分库提升效率,但更新时需按规则(如哈希取模)选取其中一条进行更新,若该条已扣减完,需另选其它行进行更新,悲观的情况下会挨个试一遍,从一定程度延长排队时间。另若抢购限制数量不是为1的,一次扣库存可能涉及需要操作多条记录,综合实现难度极高。
下单成功时,发起支付及后续流程
查询缓存,订单状态查询(下单中,下单完成,下单失败)KEY: ${UID}+${场次ID}
应用层(前端)
返回状态或订单号
下单队列消费者
1、判断库存(redis)2、扣减库存(mysql)3、扣减失败时,redis打标识(抢购失败)
所需数据特性离散化,使用统一缓存注意IP“误伤”,如公司网络,或小区集中网络出口
1、商品是否存在、有效期判断,读取本地缓存;多次参与判断,读统一缓存2、库存判断秒杀库存:既活动库存局部库存:将秒杀库存均匀拆分为多份(本地缓存,为尽量防止少卖,局部库存乘以扩大系数,如1.5)全局库存:秒杀库存余量(本地缓存,监听库存变更事件,动态扣减)判断规则:若局部库存不足,则快速返回(售罄),若局部库存足够,则判断全局库存是否足够,不足则快速返回(售罄)。本地全局库存是在异步执行数据库扣除后,异步同步更新的,对流量瞬间集中且库存量大的情况,是没有实际挡流的作用,但处理原则是能挡尽量挡,如访问不是很集中,库存量少且扩大系数大的情况涉及问题1、导致少卖的情况条件限制重计算在异步消费时计算,可能会有部分不符合;机器意外宕机;购买数量不均,本地库存不足但有小余量2、拆分库存计算时需要获取机器数量,可在代码埋个点,实例启动时计入Redis,实例关闭时Redis减少计数。但当机器意外宕机,Redis计数不变,这将导致少卖(包含已开始及未开始秒杀),此问题除了放大局部库存,没有其它好的办法,虽然可以通过运维监控触发修改,或者运维告警人工修改,但实现较为麻烦
2、资格查询短轮询
3、下单
秒杀系统
促销中心
返回单据号
MQ消费者
验证抢购资格,下单接口调用
1、发送下单MQ消息2、redis打标识(下单处理中)
0 条评论
下一页