• 限流算法

    • 令牌桶算法
    • 漏桶算法
  • 应用级限流
    • 限制总并发数/连接/请求数
    • 限制接口的总并发/请求数
    • 限流接口每秒的请求数
    • 平滑限流接口的请求数
      • 平滑突发限流(SmoothBursty)
      • 平滑预热限流(SmoothWarmingUp)

在开发高并发的系统时,有很多手段来保护系统,如缓存、降级和限流等。缓存可以提升系统的访问速度,降级可以暂时屏蔽掉非核心业务,使得核心业务不受影响。限流的目的通过对并发访问进行限速,一旦达到一定的速率就可以拒绝服务(定向到错误页或告知资源没有了)、排队等待(如秒杀、评论、下单等)、降级(直接返回兜底数据、如商品库存默认有货)。

常见的限流方式有:限制总并发数(数据库连接池、线程池)、限制瞬时并发数(如Nginx的limit_conn模块)、限制时间窗口的平均速率(如Guava的RateLimiter、Nginx的limit_req模块)、限制远程接口的调用速率限制MQ的消费速率等。从应用的层面上来讲,又可以分为:接入层限流应用层限流分布式限流等。

限流算法

令牌桶算法

令牌桶算法是一个存放固定容量令牌的容器,按照固定速率添加令牌,算法描述如下:

  1. 假设限制2r/s,则按照500ms的固定速率添加令牌。
  2. 桶的总容量为N,当达到总容量时,新添加的令牌则被丢弃或拒绝。
  3. 当一个n个字节大小的数据包到达,则从桶中删除n个令牌,然后处理数据包。
  4. 如果桶中的令牌不足n个,则不会删除令牌,但是数据包将会被限流。

漏桶算法

漏桶可以用于流量整型和流量控制,算法描述如下:

  1. 一个固定容量的漏桶,会按照固定的速率流出水滴。
  2. 如果桶中无水,则不需要流出水滴。
  3. 可以以任意速率流入水滴。
  4. 如果流入的水滴超出了桶容量,则新添加的则会被丢弃。

综上可以看出,令牌桶允许一定程度的突发请求(有令牌就可以处理),漏桶的主要目的是来平滑流入的速率。

应用级限流

限制总并发数/连接/请求数

对于一个应用来说,总会有一个TPS/QPS的阀值,如果超过了阀值,则系统就会变得非常慢跟甚至无法响应。因此需要对系统进行过载保护,避免大量请求击垮系统。

如Tomcat的Connector中的以下几个参数:

  • acceptCount:如果Tomcat的线程都忙于响应,新来的连接将会进入队列,如果超出队列大小,则会拒绝连接。
  • maxConnections:瞬时最大连接数,超出的会排队等待。
  • maxThreads:Tomcat能启动用来处理请求的最大线程数,如果请求处理量一直远远大于线程数,则会引起响应变慢甚至会僵死。

类似于Tomcat配置最大连接数等参数,Redis和MySQL也有相关的配置。

限制接口的总并发/请求数

在Java中可以用线程安全的AtomicLong或者Semaphore进行处理,如下使用了AtomicLong进行简单的统计:

try {if (atomic.incrementAndSet() > 阀值) {// 拒绝请求}// 处理请求
} finally {atomic.decrementAndGet();
}

这种方式实现起来比较简单暴力,没有平滑处理,这需要根据实际情况选择使用。

限流接口每秒的请求数

限制每秒的请求数,可以使用Guava的Cache来存储计数器,设置过期时间为2S(保证能记录1S内的计数)。下面代码使用当前时间戳的秒数作为key进行统计,这种限流的方式也比较简单。

LoadingCache<Long, AtomicLong> counter =CacheBuilder.newBuilder().expireAfterWrite(2, TimeUnit.SECONDS).build(new CacheLoader<Long, AtomicLong>() {@Overridepublic AtomicLong load(Long seconds) throws Exception {return new AtomicLong(0);}});
long limit = 1000;
while (true) {//得到当前秒long currentSeconds = System.currentTimeMillis() / 1000;if (counter.get(currentSeconds).incrementAndGet() > limit) {System.out.println("限流了:" + currentSeconds);continue;}//业务处理
}

上面介绍的2中限流方案都是对于单机接口的限流,当系统进行多机部署时,就无法实现整体对外功能的限流了。当然这也看具体的应用场景,如果平行的应用服务器需要共享限流阀值指标,可以使用Redis作为共享的计数器。

平滑限流接口的请求数

Guava的RateLimiter提供的令牌桶算法可以用于平滑突发限流(SmoothBursty)和平滑预热限流(SmoothWarmingUp)实现。

平滑突发限流(SmoothBursty)

平滑突发限流顾名思义,就是允许突发的流量进入,后面再慢慢的平稳限流。下面给出几个Demo

# 创建了容量为5的桶,并且每秒新增5个令牌,即每200ms新增一个令牌
RateLimiter limiter = RateLimiter.create(5);
while (true) {// 获取令牌(可以指定一次获取的个数),获取后可以执行后续的业务逻辑System.out.println(limiter.acquire());
}

上面代码执行结果如下所示:

0.0
0.188216
0.191938
0.199089
0.19724
0.19997

上面while循环中执行的limiter.acquire(),当没有令牌时,此方法会阻塞。实际应用当中应当使用tryAcquire()方法,如果获取不到就直接执行拒绝服务。

下面在介绍一下中途休眠的场景:

RateLimiter limiter = RateLimiter.create(2);
System.out.println(limiter.acquire());
Thread.sleep(1500L);
while (true) {System.out.println(limiter.acquire());
}

上面代码执行结果如下:

0.0
0.0
0.0
0.0
0.499794
0.492334

从上面结果可以看出,当线程休眠时,会囤积令牌,以给后续的acquire()使用。但是上面的代码只能囤积1S的令牌(也就是2个),当睡眠时间超过1.5S时,执行结果还是相同的。

平滑预热限流(SmoothWarmingUp)

平滑突发限流有可能瞬间带来了很大的流量,如果系统扛不住的话,很容易造成系统挂掉。这时候,平滑预热限流便可以解决这个问题。创建方式:

// permitsPerSecond表示每秒钟新增的令牌数,warmupPeriod表示从冷启动速率过渡到平均速率所需要的时间间隔
RateLimiter.create(double permitsPerSecond, long warmupPeriod, TimeUnit unit)
RateLimiter limiter = RateLimiter.create(5, 1000, TimeUnit.MILLISECONDS);
for (int i = 1; i < 5; i++) {System.out.println(limiter.acquire());
}
Thread.sleep(1000L);
for (int i = 1; i < 50; i++) {System.out.println(limiter.acquire());
}

执行结果如下:

0.0
0.513566
0.353789
0.215167
0.0
0.519854
0.359071
0.219118
0.197874
0.197322
0.197083
0.196838

上面结果可以看出来,平滑预热限流的耗时是慢慢趋近平均值的。


参考:《亿级流量网站架构核心技术》
链接:http://moguhu.com/article/detail?articleId=73

分布式系统限流策略(一)相关推荐

  1. 分布式系统限流策略/秒杀系统限流设计

    目录 概述 限流算法 令牌桶算法 漏桶算法 应用级限流 限制总并发数/连接/请求数 限制接口的总并发/请求数 限流接口每秒的请求数 平滑限流接口的请求数 平滑突发限流(SmoothBursty) 平滑 ...

  2. 如何设计秒杀服务器的限流策略

    如果平时系统的访问量只有一万,而最大承受限制为五万,在秒杀时刻的瞬间,访问量突然增加到100W,此事系统一定会因访问量过大而宕机,此时就应该设计一个限流策略,使服务器能接收和处理的请求减少. 秒杀限流 ...

  3. Java限流策略与算法

    概要 在大数据量高并发访问时,经常会出现服务或接口面对暴涨的请求而不可用的情况,甚至引发连锁反映导致整个系统崩溃.此时你需要使用的技术手段之一就是限流,当请求达到一定的并发数或速率,就进行等待.排队. ...

  4. 探索常见的几种限流策略和实现

    高并发访问时,缓存.限流.降级往往是系统的利剑,在互联网蓬勃发展的时期,经常会面临因用户暴涨导致的请求不可用的情况,甚至引发连锁反映导致整个系统崩溃.这个时候常见的解决方案之一就是限流了,当请求达到一 ...

  5. 秒杀限制人群,如何设计秒杀服务的限流策略?

    对于秒杀业务,大家应该比较熟悉了.比如,"某商品原价 1299 元, 双十一整点秒杀价仅 500 元,限量 100 件,先到先得" 等等.通过这段文案我们能够发现,参与秒杀活动商品 ...

  6. 设计一个基于用户的API限流策略 Rate Limit

    设计一个基于用户的API限流策略 Rate Limit 应用场景 API接口的流量控制策略:缓存.降级.限流.限流可以认为服务降级的一种,限流就是限制系统的输入和输出流量已达到保护系统的目的.限流策略 ...

  7. 基于用户的API限流策略

    应用场景 API接口的流量控制策略:缓存.降级.限流.限流可以认为服务降级的一种,限流就是限制系统的输入和输出流量已达到保护系统的目的.限流策略虽然降低了服务接口的访问频率和并发量,却换取服务接口和业 ...

  8. Kubernetes APIServer 限流策略

    之前说过了,认证,鉴权,准入,这三个重要的环节.到此为止k8s apiserver就已经将请求继续往后传递了,作为rest服务器,它一定要有自我保护机制,这个自我保护的机制最核心的就是限流. 作为we ...

  9. 高可用系统设计 | 分布式限流策略:计数器算法、漏桶算法、令牌桶算法

    文章目录 限流 什么是限流? 分布式限流 限流算法 计数器算法 固定窗口计数器 滑动窗口计数器 漏桶算法 令牌桶算法 限流 什么是限流? 限流可以认为服务降级的一种,限流就是限制系统的输入和输出流量已 ...

最新文章

  1. 让FX1.1的NotifyIcon支持BalloonTip(1)
  2. Notes客户端重新配置批处理
  3. 如何迭代pandas dataframe的行
  4. Packet for query is too large (1166 1024). You can change this value
  5. 处理SAP Netweaver gateway service使用过程中遇到的404 error
  6. 工业交换机故障分析的原则
  7. Material Theme
  8. 【每日算法Day 84】面试必考题:Trie(字典树/前缀树)的实现
  9. Java如何使用IP代理
  10. 国际知名制作公司名录及网址大全,制作人员必备
  11. centos gcc卸载_CentOS gcc多版本的卸载与修复
  12. 如何使用逆分布函数模拟MEDIAN()聚合函数
  13. 跳转QQ群android代码,android 怎么跳转直接到qq群
  14. GOM引擎登陆器自动更新教程(不会的新手看)
  15. kali初使用之zsh
  16. Nacos Go微服务生态系列(一) | Dubbo-go 云原生核心引擎探索
  17. ICG setup timing violation介绍?
  18. AAC帧格式及编码介绍
  19. 去中心化的前端构建工具 — Vite
  20. 塞班经典游戏超级矿工(super miners)类似游戏”滚石传说“发布

热门文章

  1. 国外问卷调查做题工具
  2. 2022年危险化学品经营单位主要负责人特种作业证考试题库及答案
  3. 使用基与maven的构建插件在构建阶段压缩css,js并为压缩后的文件追加版本号
  4. win11重启键在哪 windows11关机重启的设置方法
  5. ionic如何使用第三方iconfont,以及图标微调 (转载)
  6. 爱普生(EPSON) ME300 问题解决
  7. 【算法设计与分析】HDU-1108 C++诡异的楼梯(BFS迷宫最短路径)
  8. 笔记本“电源已接通,未充电”的解决办法 win7
  9. 集丰照明|一帖说清6种防眩射灯应用在家装修上
  10. 阿里云免费的ssl证书到期怎么续费