秒杀系统, 小库存场景,瞬间抢购完成的case,譬如iphone 11 上亿人抢一个,可通过使用事务 的悲观锁的实现(为了降低并发冲突,可对于事务内要读取且后续要基于此做更新的select语句 + for update来实现降低并发冲突,即加共享读锁),事务执行操作的结果,都需要通过判断affectedRow是否返回0,返回0则通过rollback transaction执行回滚。 也可以不用事务,通过应用层面写sql来实现乐观锁 ,譬如减库存
select itemVersion from itemTable where itemid=id;
update itemTable set itemNum=itemNum-1 where itemVersion=oldVersion and itemid=id;
若库存量很大,并发量也大,则并发冲突概率就大,失败重试就多,系统做很多无用功,性能低。
此时加缓存,只能降低读的压力,写冲突仍旧长时间存在。
所以针对大库存,采用消息中间件,将下单和减库存解耦,下单还是通过创建订单,持久化至数据库,同时写入消息中间件一条某商品待减库存的消息(包含order id, user id),减库存通过缓存的DECRBY操作,完成后回写此订单id的状态,完全异步化来做。
对于秒杀,给用户延迟几秒,前端做好提示即可。同时,若商品种类及商品数量很多,还存在热点商品,针对海量用户并发抢购,通过user id对订单db分库分表,先均摊用户压力;通过item id切片来写入消息中间件topic对应hasing取模后的partition。然后闪购后台作业通过配置的模数N 来启动N个实例,通过配置指定partition执行消费,通过user id及order id来查询及更新订单状态。
补充:对于订单系统,由于基于user id分库分表,order id为主键,如何分布式的生成,保障全局单调或趋势递增, 可基于snowflake或segment方案