流程
登录/注册——>列表——>详情页——>秒杀
优化
html等静态资源不需要重新到服务器获取,cdn会缓存。在做倒计时时,超过时间禁用按钮,或者已经点击过按钮禁用按钮,按钮绑定一次点击事件,保证只发送一次请求
只需要获取服务器时间保证时间一致,服务器时间接口不需要优化,获取时间接口简单并发量很高效率足够
获取秒杀地址接口:可以用redis,redis官方并发可以到10万,集群化后可以高达百万
在获取地址时,先到redis查看,如果没有再到mysql获取并保存到redis,下次访问就能直接在redis访问,当mysql更新时可以主动更新redis
秒杀接口:不可用缓存,涉及库存增减会导致数据不一致.使用mysql的事务保证数据一致
其他方案
通过redis/nosql实现一个原子计数器,计算库存,保证数据的原子性,同时产生的行为信息通过分布式MQ发布记录。后端通过取出MQ里的消息消费,落地到mysql
缺点:需要大量的运维成本去维护分布式的NOSQL和MQ组件的稳定性
开发成本:保持nosql中数据一致,当减库存失败时数据回滚等等
很难解决重复秒杀,需要记录消息再次发送消息去确认。不适合新手
为什么mysql低效
单执行update语句,一秒可以达到4w并发
在我们开发中需要使用事务去保证数据一致,一个用户秒杀的流程是:减库存——>新增秒杀记录,因为使用的是事务,一个事务开始会锁住当前要修改的行记录,直到事务完成或者回滚,在一个用户的事务还未完成时其他用户只能等待,导致mysql效率降低。
update,insert,commit过程中存在网络延迟,java客户端中需要GC,导致mysql性能下降。
总结
方法一:
1.前端控制,按钮控制防止重复,暴露接口
2.动静态数据分离:CDN缓存后端缓存
3.事务竞争:减少锁时间
行级锁在事务commit或者rollback之后释放,优化可以往如何减少行级锁持有时间方向,
3.1.修改mysql源码,当update条数是一条时自动commit。
3.2.存储过程,mysql完成整个事务,减少GC干扰和网络延迟
方法二:
1.使用缓存存储当前商品秒杀状态
2.select当前用户状态和订单状态防止重复秒杀
3.使用mq消息队列延迟消费信息