zoukankan      html  css  js  c++  java
  • 秒杀设计详细过程:(关于后端我就详细讲解一下)

    秒杀的基本讲解
    秒杀后端的详细简介
    需要了解的问题
    面试时可能会问的问题

    基本讲解
    1、秒杀开始前,秒杀按钮灰掉为“未开始”,不可点击。
    2、URL在活动开始前不可露出或者生效,否则容易被使用工具绕过浏览器提前下单。导致活动还未开始,已经开始下单这个大黑洞。我们的做法是在活动开始前,通过更新JS文件露出下单的URL。
    3、在秒杀进行中,秒杀按钮才可以点击下单。
    4、秒杀产品的介绍,详情,参数等等,全部静态化,将秒杀商品页面缓存在CDN上(资源没那么好其实可以放在Nginx中做动静分离)
    5、用户点击“下单”后,按钮置灰,禁止用户重复提交请求,限制用户在60秒之内只能提交一次请求。(防止DDOS攻击,后面有讲)
    6、然后就发送请求了,请求统一发送到Nginx中,Nginx中限流了,
    7、Nginx限流后把请求分发到tomca的秒杀接口上面去,
    8、然后到了秒杀接口上了,这个秒杀接口的项目在启动运行的时候就把商品id和数量保存到了Redis中,
    9、在做唯一性判断,对uid进行请求计数和去重,发现发送过秒杀请求就结束秒杀
    10、然后请求到达时通过要秒杀的id号到Redis中去查询预减库存,只要商品库存不到0就执 行下一步,(因为Redis的操作是具有原子性所以不会出现超卖的问题),
    11、如果是分布式项目下单的接口在另外的微服务中的话,就把订单消息传MQ,这个MQ实现了流量削峰后在以先进先出的方式进行异步下单(前期都没操作数据库,防止服务器压力太大会死机的,,经过MQ之后才访问数据库)。。。
    11、如果就在此接口下单的话就只需要调用下单接口生成订单就好了,不需要中间插件了。
    12、下单的过程中的SQL语句还使用了乐观锁进行操作的再次控制防止出现超卖现象,
    13、秒杀结束后,秒杀按钮灰掉为“已结束”,不可点击。

    详细讲解
    前端操作
    1、秒杀开始前,秒杀按钮灰掉为“未开始”,不可点击。

    2、URL在活动开始前不可露出或者生效,否则容易被使用工具绕过浏览器提前下单。导致活动还未开始,已经开始下单这个大黑洞。我们的做法是在活动开始前,通过更新JS文件露出下单的URL。

    3、在秒杀进行中,秒杀按钮才可以点击下单。

    4、秒杀产品的介绍,详情,参数等等,全部静态化,将秒杀商品页面缓存在CDN上(资源没那么好其实可以放在Nginx中做动静分离)
    CDN服务器就是内容分发网络,把资源内容放在了全国各地的各服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容。(一般都是到阿里云买CDN服务器)


    5、用户点击“下单”后,按钮置灰,禁止用户重复提交请求,限制用户在60秒之内只能提交一次请求。(防止DDOS攻击,后面有讲)

    6、然后就发送请求了,请求统一发送到Nginx中

    后端操作
    1、Nginx收到前端的请求后,在进行限流操作后才把前端秒杀的请求发送到Tomcat服务器上的秒杀接口上《=======》也就是说:这Nginx转发请求到tomcat的层到途中:Nginx限制用户的重复提交,使用了限流在某一时间段内只允许用户提交一次请求到秒杀接口(重点)
    为什么要Nginx限流:Nginx限流就是限制用户请求速度,防止服务器受不了(防止DDOS攻击,后面有讲)

    Nginx限流有3种
    1、限制访问频率(正常流量)
    2、限制访问频率(突发流量)
    3、限制并发连接数

    我这只写了最平常的一种,限制访问频率(正常流量):限制一个用户发送的请求,我Nginx多久接收一个,(例如:一个用户在一分钟发1000个请求对服务器的压力肯定很大,我如果在Nginx定义了一个人一分钟一个请求的限流的话,我Nginx就是只接收一个,其他的都不要),这也叫做漏桶流:

    图片偷得哈,别在意

    重点:Nginx配置的限流代码:

    2、然后到了秒杀接口上了,这个秒杀接口的项目在启动运行的时候就把商品id和数量保存到了 Redis中,
    秒杀项目启动时的操作,把商品id和数量保存到了 Redis中,(我们考Redis来解压力,防止服务器和数MySql受不了)

    3、项目运行流程先做唯一性判断,对uid进行请求计数和去重,发现以经发送过秒杀请求就结束秒杀。
    万一人家不通过Nginx进来秒杀怎么办,直接访问秒杀接口(所以需要再次判断Uid)
    再次(防止DDOS攻击)


    4、然后请求到达时通过要秒杀的id号到Redis中去查询预减库存,只要商品库存不到0就执 行下一步,(因为Redis的操作是具有原子性所以不会出现超卖的问题),(重点)
    关键的decr方法(redis中的原子递减,根据key减value值)

    decr key
    将指定key的value原子性递减1,就相当于java中的–i。 如果该key不存在,其 初始值为0,在decr之后其值为-1。如果value的值不能转成整型,如helllo,该操作将 执行失败并返回相应的错误信息。


    代码:

    5、然后在把订单消息传入MQ,MQ去通知下单接口生成订单,这个MQ实现了流量削峰后在以先进先出的方式进行异步下 单(前期都没操作数据库,防止服务器压力太大会死机的,,经过MQ之后才访问数据库)。。。注意:(可以不需要此MQ,此MQ只是在分布式项目中需要,就是下单接口在另外的项目就需要,要此MQ还不好,因为中间插件挂了秒杀系统也挂了,其实可以直接调用下单的方法了)


    5、如果就在此接口下单的话就只需要调用下单接口生成订单就好了,不需要中间插件了。

    6、下单的过程中的SQL语句还使用了乐观锁进行操作的再次控制防止出现超卖现象,(其实可以不需要,只是保证以下,其实可以直接生成下单的订单了)
    乐观锁的标记值判断就是把redis中返回预减后的的值去和数据库的库存去判断,达到一个防止超卖的现象


    7、到此秒杀结束后,秒杀按钮灰掉为“已结束”,不可点击。


    需要了解的问题
    1、什么是漏桶流,
    NGINX限流使用漏桶算法(leaky bucket algorithm),该算法广泛应用于通信和基于包交换计算机网络中,用来处理当带宽被限制时的突发情况。和一个从上面进水,从下面漏水的桶的原理很相似;如果进水的速率大于漏水的速率,这个桶就会发生溢出。
    在请求处理过程中,水代表从客户端来的请求,而桶代表了一个队列,请求在该队列中依据先进先出(FIFO)算法等待被处理。漏的水代表请求离开缓冲区并被服务器处理,溢出代表了请求被丢弃并且永不被服务。


    2、什么是MQ的削峰
    MQ的削峰也和漏桶流有点相似道理,只不过他是一个永远不会漏的桶,请求在多没关系,我先接着,我慢慢来,不管你多少请求我都按照我的速度慢慢来,保证消息不丢失。

    3、Tomcat最多支持并发多少用户?
    Tomcat 默认配置的最大请求数是 150,也就是说同时支持 150 个并发,当然了,也可以将其改大。
    当某个应用拥有 250 个以上并发的时候,应考虑应用服务器的集群。
    具体能承载多少并发,需要看硬件的配置,CPU 越多性能越高,分配给 JVM 的内存越多性能也就越高,但也会加重 GC 的负担。
    操作系统对于进程中的线程数有一定的限制:
    Windows 每个进程中的线程数不允许超过 2000
    Linux 每个进程中的线程数不允许超过 1000
    另外,在 Java 中每开启一个线程需要耗用 1MB 的 JVM 内存空间用于作为线程栈之用。
    Tomcat的最大并发数是可以配置的,实际运用中,最大并发数与硬件性能和CPU数量都有很大关系的。更好的硬件,更多的处理器都会使Tomcat支持更多的并发。

    4、Nginx支持多少并发
    单个Nginx并发尽量不要超过2万,如果超过了就要做集群了,虽然官方监测能支持5万并发

    5、MySql最大的并发
    MySql最大的并发量500-1000,好一点的服务可以支持1000-2000,超过了还是要集群


    面试可能会问的问题
    1、库存超卖
    只有10个库存,但是一秒钟有1k个订单,怎么能不超卖呢?
    核心思想就是保证库存递减是原子性操作,10–返回9,9–返回8,8–返回7。
    而不能是读取出来库存10,10-1=9再更新回去。因为这个读取和更新是并发执行的,很可能就会有1k个订单都成功了,而库存实际只有10。
    那么,怎么保证原子性操作呢?

    1 .数据库判断库存不能小于0(我们使用到了,比他吊一点,乐观锁)
    update product set left_num=left_num-1 where left_num>0;

    2.分布式锁(我们没有使用)
    用redis来做一个分布式锁,reids->setnx(‘lock’, 1) 设置一个锁,程序执行完成再del这个锁。
    锁定的过程,不利于并发执行,大家都在等待锁解开,不建议使用。

    3 .消息队列(我们使用了)
    将订单请求全部放入消息队列,然后另外一个后台程序一个个处理队列中的订单请求。
    并发不受影响,但是用户等待的时间较长,进入队列的订单也会很多,体验上并不好,也不建

    4 redis递减(我们使用了,decr方法就是原子性递减)
    通过 redis的:decr(‘key’)方法 以原子性的方式得到递减之后的库存数。
    性能方面很好,同时体验上也很好

    2、集群怎么来规划
    前端服务器不用管,集群的数量不受影响。
    redis的性能可以达到每秒几万次响应,所以一个集群的规模,也就是redis服务可以承载的数量。

    比如:一台前端服务器是1-2k的qps(有库存时),那么10台+1台redis就可以是一个独立的集群,可以支撑1-2w每秒订单量。
    10个上述的集群就可以做到一秒钟处理10w~20w的有效订单。

    如果秒杀活动的库存量在1w以内,预计参与的人数在百万左右,那么有一个集群也就可以搞定。
    如果秒杀参与的人数超过千万,那么就要用到不止一个集群了。

    3、多个集群的数据怎么保持一致性啊
    不要做多集群的数据同步,而是用散列,每个集群的数据是独立存在的。

    假设,有10个商品,每个商品有1w库存,规划用10个集群,那么每个集群有10个商品,每个商品是1k库存。

    每个集群只需要负责把自己的库存卖掉即可,至于说,会不会有用户知道有10个集群,然后每个集群都去抢。

    这种情况就不要用程序来处理了,利用运营规则,活动结束后汇总订单的时候再去处理就好了。

    如果担心散列的不合理,比如:某个集群用户访问量特别少,那么可以引入一个中控服务,来监控各个集群的库存,然后再做平衡。

    4、机器人抢购怎么办
    没什么太好的办法,类似DDOS攻击,只能是让自身更强大才是王道。
    运营策略上,可以严格控制用户注册,必须登录,提交订单的时候引入图像验证码,问答,交互式验证等。

    5.你的秒杀系统可以做到多少并发量。
    前台我没做,
    我就光说后台吧,使用JMeter测试的吧
    首先Nginx
    1000个并发的秒杀,俩台台tomcat,几秒就搞定,具体的我不记得了,Jm测试工具是时间戳显示

    假如做10000并发的秒杀就要很多台服务器
    我就假如做10000并发的秒杀,资源是5台tomcat的话,Nginx就不怕,Nginx2万并发随随便便,超过2万并发最好使用集群
    在Nginx定义限流维度,每秒1000个请求漏下去,漏到Tomcat,大概呢就是十几二十秒秒杀完。

    在说Tomcat,Tomcat可以接受150-250并发之间,超过250并发最好也使用集群

    redis的性能可以达到每秒几万次响应,所以一个集群的规模,也就是redis服务可以承载的数量。
    比如:一台前端服务器是1-2k的qps(有库存时),那么10台+1台redis就可以是一个独立的集群,可以支撑1-2w每秒订单量。

    最后结束!如果需要源码就留言给我吧(o(╥﹏╥)o),都没有人点赞,没有人留言,难受···
    ————————————————
    版权声明:本文为CSDN博主「小杰要吃蛋」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/weixin_43122090/article/details/103652202

  • 相关阅读:
    容器平台选型的十大模式:Docker、DC/OS、K8S 谁与当先?
    Spring Controller里注入Feign的Interface报红提示的问题
    几种常见的日志
    个人博客搭建方案选择
    elasticsearch常用操作命令
    kafka操作命令
    centos7.0安装java环境
    CentOS安装jdk的三种方法
    在OAuth2中 自定义tokenServices来提供个性化服务,每次刷新token并让原token在5分钟内有效
    解决HttpServletRequest的输入流只能读取一次的问题(转)
  • 原文地址:https://www.cnblogs.com/deepalley/p/15433363.html
Copyright © 2011-2022 走看看