经典面试题——让你设计一个限流的系统怎么做?

Posted Javaesandyou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了经典面试题——让你设计一个限流的系统怎么做?相关的知识,希望对你有一定的参考价值。

保障服务稳定的三大利器:熔断降级、服务限流和故障模拟。限流系统是当前很多系统都需要考虑的场景。首先在nginx层面是可以做限流的,除此之外,在微服务层面还是有很多空间可以施展的。

限流的话,主要思路分为请求数量限制消费能力限制两类。前者主要是限制一段时间内的总并发数、后者主要是限制消费者的消费能力。

限流算法

限流算法来说,主要包含令牌桶算法、漏桶算法和计数器等。对于简单的计数器算法,通过AtomicLong#incrementAndGet()来进行粗暴的控制,因为容易导致“突刺现象”(比如单位时间1s内的前10ms,已经通过了100个请求,那后面的990ms,只能拒绝),所以这里不做推荐

令牌桶算法

令牌工厂:匀速生成令牌

令牌桶:拥有固定的令牌数

应用者:一次可以申请N个令牌,没有令牌不能进行后续处理。

如果使用Redis来实现的话会比较简单,大概思路如下:

1/ 获取令牌:依靠List的leftPop来获取令牌

Object result = redisTemplate.opsForList().leftPop("limit_list");

2/ 向令牌桶添加令牌

redisTemplate.opsForList().rightPush("limit_list",UUID.randomUUID().toString());

漏桶算法

漏桶:容量固定

流速:任意

流出水滴:固定速率

滑动窗口

用Redis的list数据结构可以轻而易举的实现该功能:保证每N秒内至多M个请求,缺点就是zset的数据结构会越来越大。实现方式相对也是比较简单的。

1/ 请求进来:UUID生成唯一的value;score用当前的时间戳

redisTemplate.opsForZSet().add("limit",UUID.randomUUID().toString(),currentTime);

2/ 限流:zset的range方法可以统计两个时间戳内的请求,达到限流效果

Integer count = redisTemplate.opsForZSet().rangeByScore("limit", currentTime -

面试题:如何设计一个高并发的系统?

技术图片

这道面试题涉及的知识点比较多,主要考察的是面试者的综合技术能力。高并发系统的设计手段有很多,主要体现在以下五个方面。

1、前端层优化
① 静态资源缓存:将活动页面上的所有可以静态的元素全部静态化,尽量减少动态元素;通过 CDN、浏览器缓存,来减少客户端向服务器端的数据请求。

② 禁止重复提交:用户提交之后按钮置灰,禁止重复提交。

③ 用户限流:在某一时间段内只允许用户提交一次请求,比如,采取 IP 限流。

2、中间层负载分发
可利用负载均衡,比如 nginx 等工具,可以将并发请求分配到不同的服务器,从而提高了系统处理并发的能力。

nginx 负载分发的五种方式:

① 轮询(默认)每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器不能正常响应,nginx 能自动剔除故障服务器。

② 按权重(weight)使用 weight 参数,指定轮询几率,weight 和访问比率成正比,用于后端服务器性能不均的情况,配置如下:

upstream backend {
server 192.168.0.14 weight=10;
server 192.168.0.15 weight=10;
}
③ IP 哈希值(ip_hash)每个请求按访问 IP 的哈希值分配,这样每个访客固定访问一个后端服务器,可以解决 session 共享的问题,配置如下:

upstream backend {
ip_hash;
server 192.168.0.14:88;
server 192.168.0.15:80;
}
④ 响应时间(fair)按后端服务器的响应时间来分配请求,响应时间短的优先分配,配置如下:

upstream backend {
    fair;
    server server1.com;
    server server2.com;
}

⑤ URL 哈希值(url_hash)按访问 url 的 hash 结果来分配请求,和 IP 哈希值类似。

upstream backend {
    hash $request_uri;
    server server1.com;
    server server2.com;
}

3、控制层(网关层)优化
限制同一个用户的访问频率,限制访问次数,防止多次恶意请求。

4、服务层优化
① 业务服务器分离:比如,将秒杀业务系统和其他业务分离,单独放在高配服务器上,可以集中资源对访问请求抗压。

② 采用 MQ(消息队列)缓存请求:MQ 具有削峰填谷的作用,可以把客户端的请求先导流到 MQ,程序在从 MQ 中进行消费(执行请求),这样可以避免短时间内大量请求,导致服务器程序无法响应的问题。

③ 利用缓存应对读请求,比如,使用 Redis 等缓存,利用 Redis 可以分担数据库很大一部分压力。

5、数据库层优化
① 合理使用数据库引擎 ② 合理设置事务隔离级别,合理使用事务 ③ 正确使用数据库索引

  • 尽量使用主键查询,而非其他索引,因为主键查询不会触发回表查询。
  • 不做列运算,把计算都放入各个业务系统实现
  • 查询语句尽可能简单,大语句拆小语句,减少锁时间
  • 不使用 select * 查询
  • or 查询改写成 in 查询
  • 不用函数和触发器
  • 避免 %xx 查询
  • 少用 join 查询
  • 使用同类型比较,比如 ‘123‘ 和 ‘123‘、123 和 123
  • 尽量避免在 where 子句中使用 != 或者 <> 操作符,查询引用会放弃索引而进行全表扫描
  • 列表数据使用分页查询,每页数据量不要太大
  • 用 exists 替代 in 查询
  • 避免在索引列上使用 is null 和 is not null
  • 尽量使用主键查询
  • 避免在 where 子句中对字段进行表达式操作
  • 尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型
    ④ 合理分库分表 ⑤ 使用数据库中间件实现数据库读写分离 ⑥ 设置数据库主从读写分离

【END】
热文推荐:史上最全面试题详解

关注下方二维码,订阅更多精彩内容
技术图片

老王著
转发更佳
喜欢作者

以上是关于经典面试题——让你设计一个限流的系统怎么做?的主要内容,如果未能解决你的问题,请参考以下文章

Java高频面试题:四种经典限流算法,有哪四种?

Java高频面试题:四种经典限流算法,有哪四种?

面试题:如何设计一个高并发的系统?

经典面试题,如何设计一个秒杀系统

秒杀系统个人总结

面试官:连漏桶算法和令牌桶算法都不知道吗?回去多看看书吧