zoukankan      html  css  js  c++  java
  • 面试相关-怎么实现限流功能

    背景:在和一个同事聊天中,说到面试可能会问到怎么实现流量控制。一时没有头绪,网上查资料记录下来。

    图解+代码|常见限流算法以及限流在单机分布式场景下的思考

    ps:看这篇博客就够了

    什么是限流?
    限流指代的是 限制到达系统的并发请求数,使得系统能够正常的处理 部分 用户的请求,来保证系统的稳定性。
    为什么限流?
    限流的本质是因为后端处理能力有限,需要截掉超过处理能力之外的请求,亦或是为了均衡客户端对服务端资源的公平调用,防止一些客户端饿死。
    常见限流算法
    计数限流
    最简单的限流算法就是计数限流了,例如系统能同时处理100个请求,保存一个计数器,处理了一个请求,计数器加一,一个请求处理完毕之后计数器减一。
    优点就是:简单粗暴,单机在 Java 中可用 Atomic 等原子类、分布式就 Redis incr。

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


    固定窗口限流
    它相比于计数限流主要是多了个时间窗口的概念。计数器每过一个时间窗口就重置。
    规则如下:

    请求次数小于阈值,允许访问并且计数器 +1;
    请求次数大于阈值,拒绝访问;
    这个时间窗口过了之后,计数器清零;

    缺陷:固定窗口临界问题(可以看图) 滑动窗口解决


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

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

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

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

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

    漏桶算法
    如下图所示,水滴持续滴入漏桶中,底部定速流出。如果水滴滴入的速率大于流出的速率,当存水超过桶的大小的时候就会溢出。

    规则如下:

    请求来了放入桶中
    桶内请求量满了拒绝请求
    服务定速从桶内拿请求处理
    它的特点就是宽进严出,无论请求多少,请求的速率有多大,都按照固定的速率流出,对应的就是服务按照固定的速率处理请求。


    令牌桶算法
    令牌桶其实和漏桶的原理类似,只不过漏桶是定速地流出,而令牌桶是定速地往桶里塞入令牌,然后请求只有拿到了令牌才能通过,之后再被服务器处理。

    当然令牌桶的大小也是有限制的,假设桶里的令牌满了之后,定速生成的令牌会丢弃。

    规则:
    定速的往桶内放入令牌
    令牌数量超过桶的限制,丢弃
    请求来了先向桶内索要令牌,索要成功则通过被处理,反之拒绝

    可以解决 面对突发流量我们希望在系统平稳的同时,提升用户体验即能更快的处理请求,而不是和正常流量一样,循规蹈矩的处理
    Semaphore 信号量 可以处理

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

    分布式限流:
    像令牌桶也可以将令牌数量放到 Redis 中。

    不过这样的方式等于每一个请求我们都需要去Redis判断一下能不能通过,在性能上有一定的损耗,所以有个优化点就是 「批量」。例如每次取令牌不是一个一取,而是取一批,不够了再去取一批。这样可以减少对 Redis 的请求。

    不过要注意一点,批量获取会导致一定范围内的限流误差。比如你取了 10 个此时不用,等下一秒再用,那同一时刻集群机器总处理量可能会超过阈值。
    其实「批量」这个优化点太常见了,不论是 MySQL 的批量刷盘,还是 Kafka 消息的批量发送还是分布式 ID 的高性能发号,都包含了「批量」的思想。

    常见限流组件:
    一般而言我们不需要自己实现限流算法来达到限流的目的,不管是接入层限流还是细粒度的接口限流其实都有现成的轮子使用,其实现也是用了上述我们所说的限流算法。

    比如Google Guava 提供的限流工具类 RateLimiter,是基于令牌桶实现的,并且扩展了算法,支持预热功能。

    阿里开源的限流框架 Sentinel 中的匀速排队限流策略,就采用了漏桶算法。

    Nginx 中的限流模块 limit_req_zone,采用了漏桶算法,还有 OpenResty 中的 resty.limit.req库等等。

    利用限流工具类RateLimiter实现限流的功能

    ps:实际使用

  • 相关阅读:
    虚基类练习 动物1
    UVa 10820
    hdu1027 Ignatius and the Princess II (全排列 & STL中的神器)
    在windows下安装redmine及相关问题
    批量导出表数据到CSV文件
    轻松学习Ionic (二) 为Android项目集成Crosswalk(更新官方命令行工具)
    swift第一章
    socket编程演示样例(多线程)
    谋哥:玩App怎么赚钱(三)
    Oracle database wrc运行报错ORA-15557
  • 原文地址:https://www.cnblogs.com/lixuwu/p/14664794.html
Copyright © 2011-2022 走看看