JAVA 秒杀系统总结

文章目录

    • 参考博客
    • 测试工具
    • 项目要点
      • 1、库存扣除
      • 2、接口验证
      • 3、接口限流
      • 4、缓存一致性
      • 5、消息队列处理下单

参考博客

秒杀系统[从零开始的秒杀系统设计]

测试工具

JMeter:用于多线程测试接口。

项目要点

另一种角度分析:

  • 高性能:静态资源,CDN
  • 一致性:分布式锁,减库存的几种方式
  • 高可用:集群,哨兵,流量控制,消息队列

1、库存扣除

未加任务处理的下单请求,极有可能在高并发环境下造成超卖。

即库存减少了100个,订单生成了1000个。

解决方案

使用分布式锁对库存进行处理。

  • 1、分布式锁 数据库锁
    • 1.1、乐观锁;使用version字段,每次update时判断version是否一致(每个update会持有这个记录的排他锁)
    • 1.2、悲观锁;使用FOR UPDATE关键词,每次请求使用@Transactional事务,FOR UPDATE加行锁
  • 2、分布式锁 redis锁
    • set key value NX PX expire
  • 3、Zookeeper

2、接口验证

防止一些人使用脚本对接口进行大量发送。

当秒杀时间到达后才能访问,生成一个hash值,秒杀请求需要带该hash值才有效,否则直接拒绝。

3、接口限流

对秒杀接口进行限流,对用户限流,对接口限流。

计数法:对某一时间接口访问的次数进行统计,然后过一段时间后清空,再次统计。

令牌桶法:桶中存放一定的令牌数量,同时每个时间段生成一批令牌。每个请求消耗一个令牌,当令牌桶为空时拒绝请求。

桶漏法:将请求都放进一个桶中,然后按照指定速率放行。

4、缓存一致性

redis中的缓存和数据库中的数据需要保持一致性。

两种方案:

更新缓存:1000个请求就要更新1000次缓存,效率太低

删除缓存:每次更新库中数据后,删除缓存。先删除缓存,后更新数据库;还是先更新数据库,后删除缓存。

  • 先删除缓存:A请求删除缓存,然后准备更新数据库时;B请求获取缓存失效,查询数据库得到旧数据,然后A请求更新数据库;此时缓存为脏数据。
  • 先更新数据库:缓存刚好失效,A请求数据,还未写入缓存时;B请求更新数据库,删除缓存;然后A将请求的数据写入缓存;此时缓存为脏数据。
  • 延时双删策略:综上可知,无论是先删还是后删,总会有问题,所以这个时候边有了第三种方式。先删除一次缓存,然后执行数据库更新操作,最后一定时间后再删除缓存(将中途可能的脏数据清除)。

5、消息队列处理下单

请求成功之后并不对库存进行处理。而是发送消息到消息队列,订单服务从中获取消息进行下单处理

你可能感兴趣的:(Java,分布式,java,缓存)