秒杀系统设计(JAVA)

高并发
一、前端
1.静态化页面,将页面缓存在用户的浏览器和CDN上
2.提交后按钮disabled,禁止用户重复提交

二、服务器集群
1.通过nginx分发请求,提前预判会产生的PV数,部署合适数量的服务器集群,防止其中一台Web机器挂了,导致流量分散到其他正常工作的机器上,再导致正常的机器也挂,将整个Web系统拖垮
2.优化服务器中间件如tomcat jvm优化(虚拟机初始化时的最小内存,可用最大内存,GC模式等),并发连接优化(初始化 socket线程数,最大socket线程数等)

三、服务端层
1.秒杀业务是一个读多写少的场景,大部分请求是查询请求,多使用缓存对应读的请求,增加服务端响应速度,减少CPU处理多个连接数的压力 导致整体响应速度变慢,以及web服务器链接数被占满

减库存实现逻辑
2-1.将商品的开始时间放置在redis缓存中,判断是否到了秒杀开始时间
2-2.请求间隔是否符合正常时间(如将用户上一次的请求时间记录下来计算时间差)
2-3.将商品库存剩余数量放置到redis缓存中,判断库存数量是否还有剩余
2-4.有剩余的话,获取一个redis分布式锁
利用redis的.setnx命令,先判断是否存在再赋值
因为redis都是串行操作的,不存在并发问题
拿到锁:
2-5.处理业务逻辑,如将数据放置在一个mq中,然后通过incr、incrby、decr、decrby原子操作命令控制库存数,减少数据库IO的开销
  • incr递增1并返回递增后的结果;
  • incrby根据指定值做递增或递减操作并返回递增或递减后的结果(incrby递增或递减取决于传入值的正负);
  • decr递减1并返回递减后的结果;
  • decrby根据指定值做递增或递减操作并返回递增或递减后的结果(decrby递增或递减取决于传入值的正负);
2-6.释放锁,返回应答
未拿到锁:
2-7.线程sleep再次尝试拿锁 ,多次未拿到锁则返回用户活动太火爆

3.数据库层操作sql语句加上乐观锁做一个保护


四、防作弊
1.同一个账号,一次性发出多个请求
部分用户通过浏览器的插件或者其他工具,在秒杀开始的时间里,以自己的账号,一次发送上百甚至更多的请求。实际上,这样的用户破坏了秒杀和抢购的公平性。
应对方案:
1.同一账号请求记录时间戳标记位。(可以在redis里根据用户ID 记录一条数据,比如1秒后失效)
2.再次请求的时候判断标记位是否存在,如果存在就立即打回请求。

2.多个账号,一次性发送多个请求
例如微博中有转发抽奖的活动,如果我们使用几万个“僵尸号”去混进去转发,这样就可以大大提升我们中奖的概率。
如果发现某个IP请求频率很高
应对方案:
1.返回验证码,区分真实用户

3. 多个账号,不同IP发送不同请求
黑客操作多个肉鸡
应对方案:
1.活动开始前通过一些数据挖掘筛选过滤僵尸号,僵尸账号也还是有一些共同特征的,例如账号很可能属于同一个号码段甚至是连号的,活跃度不高,等级低,资料不全等等。根据这些特点,适当设置参与门槛,例如限制参与秒杀的账号等级。

4. 火车票的抢购
高级的黄牛刷票时,在识别验证码的时候使用真实的人,中间搭建一个展示验证码图片的中转软件服务,真人浏览图片并填写下真实验证码,返回给中转软件。对于这种方式,验证码的保护限制作用被废除了,目前也没有很好的解决方案。
应对方案:
1.账号数据进行“数据挖掘”,这些黄牛账号也是有一些共同特征的,例如经常抢票和退票,节假日异常活跃等等。将它们分析出来,再做进一步处理和甄别。

没有更多推荐了,返回首页