大厂面试问答题汇总分析--- 秒杀 / 限流 / 高并发

本文分析了大厂面试中关于秒杀、限流和高并发的问题,重点讨论了限流算法,如计数、固定窗口、滑动窗口、漏桶和令牌桶算法。此外,还涵盖了秒杀系统的架构设计,前端和后端的解决方案,以及应对技术挑战的策略,包括前端页面静态化、用户限流和后端的网关层、服务层设计等。
摘要由CSDN通过智能技术生成

大厂面试---Redis面试题(含答案,相关知识点,面试考察次数统计)

大厂面试问答题汇总分析---数据库(索引-聚集/非聚集,事务,mySql, 锁)

大厂面试问答题汇总分析---网络安全类问题

大厂面试问答题汇总分析--- 秒杀 / 限流 / 高并发

【锁】的相关概念汇总

大厂面试问答题汇总分析---多线程问题

目录

1、如何进行限流?

1-1、合法性限流

1-2、基于负载限流

1-3、基于服务限流(重点)

算法限流 (重点)

计数限流

固定窗口限流算法

滑动窗口限流

漏桶算法 

令牌桶算法

限流算法相关结论

2、秒杀系统架构设计

3、业务分析

4、秒杀技术挑战

4-1、前端设计方案

4-2、后端设计方案

4-3、相关问题解决方案


1、如何进行限流?

限流的【本质】是为了不断地削减请求的数量

可参考:如何设计秒杀服务的限流策略? - 简书

1-1、合法性限流

区分【正常用户】 与【机器人/刷单用户】,通过验证码的方式(还可以拉长用户的访问时间);通过IP的方式,某个IP下的下单频率在毫秒级别 = 判定为不合法用户,还有一种方法是,隐藏秒杀入口地址。

作弊的手段:进攻与防守

1)同一个账号,一次性发出多个请求,应对方案:一个账号只允许接受1个请求。具体做法:通过Redis内存缓存服务,写入一个标志位(只允许1个请求写成功,结合watch的乐观锁的特性),成功写入的则可以继续参加。

2)多个账号【僵尸粉】,一次性发送多个请求,通过检测指定机器IP请求频率,如果发现某个IP请求频率很高,可以给它弹出一个验证码或者直接禁止它的请求

  • 1-弹出验证码,最核心的追求,就是分辨出真实用户
  • 2-直接禁止IP,实际上是有些粗暴的,因为有些真实用户的网络场景恰好是同一出口IP的,可能会有“误伤“

3)多个账号,不同IP发送不同请求

  • 跟真实用户区别不大,容易【误伤】
  • 通过设置业务门槛高来限制这种请求了
  • 通过账号行为的”数据挖掘“来提前清理掉它们
  • 【僵尸账户】账号很可能属于同一个号码段甚至是连号的,活跃度不高等级低,资料不全等

1-2、基于负载限流

  

软负载限流:

集群:  工具,Nginx(第七层-应用层) 和 LVS(第四层-传输层)

[Nginx  是一个高性能的HTTP反向代理web服务器 ] 

级联负载:  级联的做法也会同时增加请求的路径

在第 2 层的数据链路层,也可以通过 MAC 地址进行负载。比如我们可以生成一个虚拟 MAC ,然后将这个 MAC 地址映射到其他三个真实的服务器上。同样的,也可以在网络第 3 层通过 IP 进行负载,在第 4 层通过端口号进行负载

硬负载限流:

常见的应用负载工具有 F5 或 Array 等

1-3、基于服务限流(重点)

算法限流 (重点)

限流算法-常见的4种限流算法_billgates_wanbin的博客-CSDN博客_常见限流算法

计数限流

最简单的限流算法就是计数限流了,例如系统能同时处理100个请求,保存一个计数器,处理了一个请求,计数器加一,一个请求处理完毕之后计数器减一。

优点就是:简单粗暴,单机在 Java 中可用 Atomic 等原子类、分布式就 Redis incr。

缺点就是:假设我们允许的阈值是1万,此时计数器的值为0, 当1万个请求在前1秒内一股脑儿的都涌进来,这突发的流量可是顶不住的。缓缓的增加处理和一下子涌入对于程序来说是不一样的。

固定窗口限流算法

首先维护一个计数器,将单位时间段当做一个窗口,计数器记录这个窗口接收请求的次数。

  • 当次数少于限流阀值,就允许访问,并且计数器+1
  • 当次数大于限流阀值,就拒绝访问。
  • 当前的时间窗口过去之后,计数器清零。

假设单位时间是1秒,限流阀值为3。在单位时间1秒内,每来一个请求,计数器就加1,如果计数器累加的次数超过限流阀值3,后续的请求全部拒绝。等到1s结束后,计数器清0,重新开始计数。

  1. 一段时间内(不超过时间窗口)系统服务不可用。比如窗口大小为1s,限流大小为100,然后恰好在某个窗口的第1ms来了100个请求,然后第2ms-999ms的请求就都会被拒绝,这段时间用户会感觉系统服务不可用。
  2. 窗口切换时可能会产生两倍于阈值流量的请求。假设限流阀值为5个请求,单位时间窗口是1s,如果我们在单位时间内的前0.8-1s和1-1.2s,分别并发5个请求。虽然都没有超过阀值,但是如果算0.8-1.2s,则并发数高达10,已经超过单位时间1s不超过5阀值的定义啦,通过的请求达到了阈值的两倍。

滑动窗口限流

滑动窗口限流解决固定窗口临界值的问题,可以保证在任意时间窗口内都不会超过阈值。

相对于固定窗口,滑动窗口除了需要引入计数器之外还需要记录时间窗口内每个请求到达的时间点,因此对内存的占用会比较多。

规则如下,假设时间窗口为 1 秒:

  • 记录每次请求的时间
  • 统计每次请求的时间 至 往前推1秒这个时间窗口内请求数,并且 1 秒前的数据可以删除。
  • 统计的请求数小于阈值就记录这个请求的时间,并允许通过,反之拒绝。

从图中不难看出,滑动窗口算法就是固定窗口的升级版。将计时窗口划分成一个小窗口,滑动窗口算法就退化成了固定窗口算法。而滑动窗口算法其实就是对请求数进行了更细粒度的限流,窗口划分的越多,则限流越精准。

但是滑动窗口和固定窗口都无法解决短时间之内集中流量的突击

我们所想的限流场景,例如每秒限制 100 个请求。希望请求每 10ms 来一个,这样我们的流量处理就很平滑,但是真实场景很难控制请求的频率。因此可能存在 5ms 内就打满了阈值的情况。

当然对于这种情况还是有变型处理的,例如设置多条限流规则。不仅限制每秒 100 个请求,再设置每 10ms 不超过 2 个。

接下来再说说漏桶,它可以解决时间窗口类的痛点,使得流量更加的平滑。
 

漏桶算法 

漏桶算法面对限流,就更加的柔性,不存在直接的粗暴拒绝。

它的原理很简单,可以认为就是注水漏水的过程。往漏桶中以任意速率流入水,以固定的速率流出水。当水超过桶的容量时,会被溢出,也就是被丢弃。因为桶容量是不变的,保证了整体的速率。

  • 流入的水滴,可以看作是访问系统的请求,这个流入速率是不确定的。
  • 桶的容量一般表示系统所能处理的请求数。
  • 如果桶的容量满了,就达到限流的阀值,就会丢弃水滴(拒绝请求)
  • 流出的水滴,是恒定过滤的,对应服务按照固定的速率处理请求。

看到这想到啥,是不是和消息队列思想有点像,削峰填谷。经过漏洞这么一过滤,请求就能平滑的流出,看起来很像很挺完美的?实际上它的优点也即缺点。

面对突发请求,服务的处理速度和平时是一样的,这其实不是我们想要的,在面对突发流量我们希望在系统平稳的同时,提升用户体验即能更快的处理请求,而不是和正常流量一样,循规蹈矩的处理(看看,之前滑动窗口说流量不够平滑,现在太平滑了又不行,难搞啊)。

而接下来我们要谈的令牌桶算法能够在一定程度上解决流量突发的问题。
 

令牌桶算法

令牌桶算法是对漏斗算法的一种改进,除了能够起到限流的作用外,还允许一定程度的流量突发。

令牌桶算法原理:

  • 有一个令牌管理员,根据限流大小,定速往令牌桶里放令牌。
  • 如果令牌数量满了,超过令牌桶容量的限制,那就丢弃。
  • 系统在接受到一个用户请求时,都会先去令牌桶要一个令牌。如果拿到令牌,那么就处理这个请求的业务逻辑;
  • 如果拿不到令牌,就直接拒绝这个请求。

可以看出令牌桶在应对突发流量的时候,桶内假如有 100 个令牌,那么这 100 个令牌可以马上被取走,而不像漏桶那样匀速的消费。所以在应对突发流量的时候令牌桶表现的更佳

限流算法相关结论


固定窗口算法实现简单,性能高,但是会有临界突发流量问题,瞬时流量最大可以达到阈值的2倍。

为了解决临界突发流量,可以将窗口划分为多个更细粒度的单元,每次窗口向右移动一个单元,于是便有了滑动窗口算法。

滑动窗口当流量到达阈值时会瞬间掐断流量,所以导致流量不够平滑

想要达到限流的目的,又不会掐断流量,使得流量更加平滑?可以考虑漏桶算法!需要注意的是,漏桶算法通常配置一个FIFO的队列使用以达到允许限流的作用。

由于速率固定,即使在某个时刻下游处理能力过剩,也不能得到很好的利用,这是漏桶算法的一个短板。

限流和瞬时流量其实并不矛盾,在大多数场景中,短时间突发流量系统是完全可以接受的。令牌桶算法就是不二之选了,令牌桶以固定的速率v产生令牌放入一个固定容量为n的桶中,当请求到达时尝试从桶中获取令牌。

当桶满时,允许最大瞬时流量为n;当桶中没有剩余流量时则限流速率最低,为令牌生成的速率v。

如何实现更加灵活的多级限流呢?滑动日志限流算法了解一下!这里的日志则是请求的时间戳,通过计算制定时间段内请求总数来实现灵活的限流。

当然,由于需要存储时间戳信息,其占用的存储空间要比其他限流算法要大得多。

2、秒杀系统架构设计

架构设计
1)将请求拦截在 系统上游,降低下游压力:秒杀系统特点是并发量极大,但实际秒杀成功的请求数量却很少,所以如果不在前端拦截很可能造成数据库读写锁冲突,甚至导致死锁,最终请求超时。
2)充分利用缓存(redis):利用缓存可极大提高系统读写速度。
3)消息中间件(ActiveMQ、Kafka等):消息队列可以削峰,将拦截大量并发请求,这也是一个异步处理过程(消息队列作用:解耦 削峰 异步操作)

3、业务分析

  1. 正常电子商务流程(1)查询商品;(2)创建订单;(3)扣减库存;(4)更新订单;(5)付款;(6)卖家发货

  2. 秒杀业务的特性(1)低廉价格;(2)大幅推广;(3)瞬时售空;(4)一般是定时上架;(5)时间短、瞬时并发量高;

4、秒杀技术挑战

4-1、前端设计方案

前端设计方案
页面静态化:将活动页面上的所有可以静态的元素全部静态化(通过CDN的部署)
禁止重复提交:用户提交之后按钮置灰,禁止重复提交
用户限流:在某一时间段内只允许用户提交一次请求,比如可以采取IP限流

4-2、后端设计方案

网关层: 限制uid(UserID)访问频率, 针对某些恶意攻击或其它插件,在服务端控制层需要针对同一个访问uid,限制访问频率。
服务层:
采用消息队列缓存请求:先把这些请求都写到消息队列缓存一下
利用缓存应对读请求:对典型的读多写少业务,大部分请求是查询请求。 利用缓存分担数据库压力。

4-3、相关问题解决方案

1-对现有网站业务造成冲击 ,解决方案:将秒杀系统独立部署,甚至使用独立域名,使其与网站完全隔离。

2-高并发下的应用、数据库负载, 解决方案:重新设计秒杀商品页面,不使用网站原来的商品详细页面,页面内容静态化,【用户请求不需要经过应用服务】。

3-突然增加的网络及服务器带宽,解决方案:因为秒杀新增的网络带宽,必须和运营商重新购买或者租借。为了减轻网站服务器的压力,需要将秒杀商品页面缓存在CDN,同样需要和CDN服务商临时租借新增的出口带宽。

4-直接下单, 解决方案:下单页面URL加入由服务器端生成的随机数作为参数,在秒杀开始的时候才能得到

5-如何控制秒杀商品页面购买按钮的点亮(前端js控制)

6-秒杀一般是定时上架,减库存的操作,库存会带来“超卖”的问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值