资讯 小学 初中 高中 语言 会计职称 学历提升 法考 计算机考试 医护考试 建工考试 教育百科
栏目分类:
子分类:
返回
空麓网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
空麓网 > 计算机考试 > 软件开发 > 后端开发 > Java

服务限流方案总结

Java 更新时间: 发布时间: 计算机考试归档 最新发布

服务限流方案总结

流控作用

一般的做后台服务的,都会接触到流控,一般的场景就是在流量异常,比如遭受攻击的时候,保障服务不过载,在可支持的范围内提供稳定的服务。比如我们的服务支持100QPS,当一下子来了1000个请求的时候,我们在可服务的范围内,每秒处理100个请求,这样在牺牲一些响应时效性的时候,可以保证服务不会crash。

单机限流(guava的RateLimiter)

示例

Guava给我们提供了好用的流控工具,简单使用场景如下

    private static RateLimiter rateLimiter = RateLimiter.create(5);    public static void main(String[] args) throws InterruptedException {        while (true) {            get(1);        }    }    private static void get(int permits) {        rateLimiter.acquire(permits);        System.out.println(System.currentTimeMillis());    }

运行这个简单的代码片段,从打印的时间戳可以看出来,每200ms打印一次,即正好控制QPS为5,同时保证稳定的速率。简单来说,就是当有大量请求进来的时候,限制请求的频率,维持其在一个稳定的区间。而其具体的方法,简单来说就是,根据上次处理的时间戳和允许的每秒允许的请求,来决定下次可以执行的时间。

原理

RateLimiter主要是利用了一个令牌桶的算法,系统以恒定的速率产生令牌(permit),当来一个请求的时候,会请求一个或者多个令牌,当且仅当系统有这么多个令牌的时候,请求才被允许执行,否则就一直等待令牌的生成。也就是以固定的频率向桶中放入令牌,例如一秒钟10枚令牌,实际业务在每次响应请求之前都从桶中获取令牌,只有取到令牌的请求才会被成功响应,获取的方式有两种:阻塞等待令牌或者取不到立即返回失败。

令牌同简单示意图

核心方法

方法说明

public static RateLimiter create(double permitsPerSecond)

该方法会创建一个RateLimiter实例,其每秒产生permitsPerSecond个令牌

public double acquire(int permits)

该方法是用于获取N个令牌的方法,如果系统内令牌不够,则一直等待直到有足够令牌可用

public boolean tryAcquire(int permits, Duration timeout)

该方法用户获取另外,如果在timeout时间内可以获取到足够的令牌,则等待,否则直接返回false

方法原理

  • 保持分发的速率,以一定速率分发令牌,比如我们设置permitsPerSecond为500的话,则每2毫秒产生一个令牌
  • 令牌会存储,若一定时间没有请求,可用令牌会存储下来,当然会有一个上限值,当下次来请求的时候,优先使用现有的存储的令牌
  • 会有一个nextFreeTicketMicros来记录下次有可用令牌的时间戳,在这个时间之前,所有的请求均不能通过

guava依赖:

      com.google.guava      guava      18.0    

集群限流

下面介绍几种服务集群的限流方案:

Nginx 限流

Nginx 官方提供的限速模块使用的是 漏桶算法,保证请求的实时处理速度不会超过预设的阈值,主要有两个设置:

  • limit_req_zone: 限制 IP 在单位时间内的请求数
  • limit_req_conn: 限制同一时间链接数

Redis 限流

分布式服务接口限流,通常会结合Redis来做,根据 Redis 提供的 incr 命令,在规定的时间窗口,容许经过的最大请求数。例如如果要设置每1s只能通过的请求数,通常会使用redis incr再设置过期时间,例如使用的键值对业务标识:秒级时间戳,并使用incr命令,每来一次请求,就增加1,然后与规则进行对比,并为键设置过期时间,例如1分钟。

Incr 命令介绍:

Redis Incr 命令将 key 中储存的数字值增一。如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。且将key的有效时间设置为长期有效 。如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误。本操作的值限制在 64 位(bit)有符号数字表示之内。因为Redis没有专用的整数类型,所以在内存中是以字符串的形式存储的。

限流:利用redis的incr命令可以实现一般的限流操作。如限制某接口每秒请求次数上限1000次

        public Boolean limiter(String key, Long expireMillis) {        Long count = redisTemplate.opsForValue().increment(key, INCREMENT_STEP);        if (1 == count) {            redisTemplate.expire(key, expireMillis, TimeUnit.SECONDS);        }        if (count > 1000) {            return Boolean.TRUE;        }        return Boolean.FALSE;    }

increment函数解释:在key下的value整型数基础上加delta值。

		@Nullable	Long increment(K key, long delta);

 

分布式滑动窗口限流

Kong 官方提供了一种分布式滑动窗口算法的设计, 目前支持在 Kong 上作集群限流配置。它经过集中存储每一个滑动窗口和 consumer 的计数,从而支持集群场景。这里推荐一个 Go 版本的实现: slidingwindow

其余

另外业界在分布式场景下,也有 经过 Nginx+Lua 和 Redis+Lua 等方式来实现限流

总结

        本文主要在学习和调研高并发场景下的限流方案的总结。目前业界流行的限流算法包括计数器、漏桶、令牌桶和滑动窗口, 每种算法都有本身的优点,实际应用中能够根据本身业务场景作选择,而分布式场景下的限流方案,也基本经过以上限流算法来实现。在高并发下流量控制的一个原则是:先让请求先到队列,并作流量控制,不让流量直接打到系统上。

转载请注明:文章转载自 http://www.konglu.com/
本文地址:http://www.konglu.com/it/1094782.html
免责声明:

我们致力于保护作者版权,注重分享,被刊用文章【服务限流方案总结】因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理,本文部分文字与图片资源来自于网络,转载此文是出于传递更多信息之目的,若有来源标注错误或侵犯了您的合法权益,请立即通知我们,情况属实,我们会第一时间予以删除,并同时向您表示歉意,谢谢!

我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2023 成都空麓科技有限公司

ICP备案号:蜀ICP备2023000828号-2