前言 ~
我们知道现在的京东、淘宝、以及类似购物的一些项目,他们都会定期或者不定期的举行秒杀活动,以次来提高消费者的购买力,但是我们知道秒杀这个功能怎么实现的嘛?实现过程会遇到什么难题嘛?现在跟随小编的脚步,让我们一起迈进秒杀系统的实现分析。
一、秒杀系统业务流程
这一流程虽然看似简单,但是里面还是存在着问题的,因为我们知道秒杀活动不是只有一个人在对该商品进行操作,而是上万、上十万以上的消费者在对一类商品进行操作,这样就会产生高并发的问题,并且假如有10万个消费者在对一类商品进行秒杀购买,那么请求接口的次数就不止是10万那么少了,可能是50万,也可能更高,因为所有人在参与点击秒杀时候,都会尝试多次点击,期待增加成功的机会。
解决这一问题,我们可以在前端进行按钮频繁点击操作的限制,防止重复提交,减少90%的重复请求。就是让用户点击一次后,就不让他点击了。如图类似:
就算对前端页面按钮操作进行了控制,那么也会有很大的接口请求量涌入,此时如果如此巨大的接口请求量必定会对服务器产生巨大的损害。
解决这一问题,就要考虑到负载均衡了,负载均衡简单来说就是将多个请求平均分发给多台服务器,由这些服务器共同处理用户请求,到达减缓服务器负载的效果。负载均衡有硬件和软件的解决方案,硬件可以使用lvs、F5、Radware等,软件可以使用nginx,可以实现多个tomcat的负载均衡。除了此方式,还可以使用限制流量、分散流量等操作。
修改库表,主要是修改该商品作为秒杀商品提供总的商品数量,但是毕竟是秒杀活动,所以该商品的数量是固定的,而如此大用户量的秒杀,可能会造成商品数据呈现负数的情况。
解决这一问题,可以使用分布式锁,分布式锁是一种悲观锁的形式,有些情况下也可以使用乐观锁。可以给sql一个条件,当商品数量减一的结果大于或者等于0的时候,才给予修改商品数量,如果小于0,则不给予修改。
例如该SQL:update tb_miaosha set goods_num=goods_num-1 where goods_code='' and goods_num>=0.
将用户信息和商品信息添加到秒杀表,这里又会出现一个问题,可能会产生,同一类商品,均由同一个用户购买,那么一起来参加秒杀的小伙伴们可能不乐意啦,一起来秒杀商品的,凭什么都由你一个人购买了。
解决这一问题,而前台我们可以使用nginx进行ip限制,后台代码就要使用到redis-------key-value型的非关系型数据库了,对用户进行限制,比如限制该用户20秒之内,只能秒杀一次,从而解决这一问题,如果redis中没有这个key,那么就设置,并且设置过期时间,如果redis中存在这个key,那么就不进行设置。组合命令 set key valye EX time NX
EX:设置过期时间
time:过期时间
NX:判断redis数据库中是否有这个key
后台代码:jedis.set("要设置的key","该key的值","NX","EX",10);
如果使用了redis进行用户的限制,但还是会出现数据库还承受不了过滤之后的请求量,这时候,应该怎么办勒?这时候肯定会有小伙伴提出弄个数据库集群呀,这种方法是好,但是有没有不用花钱买服务器弄数据库集群就可以实现的呢?办法还是有的。
解决方法,可以使用令牌机制, 我们知道商品数量是有限的,能秒杀成功的请求较少,我们可以预先(异步)初始化一个和商品数量相同的令牌池放入到内存中,当用户发来请求,就去令牌池中取令牌,令牌数量有限,先到先得,拿到令牌的可以请求操作数据库,从而减缓数据库的压力。
当用户登陆的时候,让客户端携带token,发送请求到服务器端,验证成功后让用户登录成功,当用户进入到秒杀页面,用户点击秒杀按钮的时候,让客户端也携带token,并且在服务器端设置一个令牌池,令牌池数量为秒杀商品数量,当用户每点击秒杀按钮,就去令牌池中去令牌,先到先得,直到令牌池数量为空。
非常感谢腾讯课堂的Tony老师视频教材!!!!