微服务中常用的限流算法(一)
一个业务系统在指定配置的服务器上,可以承载的容量是一定的,当请求流量超过系统的容量后,系统就会变得不稳定,可用性下降,为了保证系统的可用性,需要将系统能够承载容量之外的流量进行丢弃,这样虽然会导致部分用户请求失败,但是整个系统依然是可用的,依然能对外提供服务,而不是因为负载压力太大导致整个系统崩溃,使所有用户都不能访问,这就是保证系统高可用的限流方案。
目前业内实现限流的算法有四种,分别是固定窗口算法,滑动窗口算法,漏桶算法和令牌桶算法。
为方面下文代码实现,我们定义了接口和对应的抽闲类:
1.接口定义:
public interface LimitAlgo {// 获取限流资源boolean tryAcquire();
}
2.抽象类定义
public abstract class AbstractLimitAlgo implements LimitAlgo{// 资源限制protected int limit;// 最近获取限流资源时间戳protected long lastTimeStamp;public AbstractLimitAlgo(int limit){this.limit = limit;this.lastTimeStamp = System.currentTimeMillis();}protected long getElapseTimeFromLast() {return System.currentTimeMillis() - lastTimeStamp;}
}
固定窗口算法
固定窗口算法是一个相对比较简单的限流算法,该算法是将一个固定的时间单元当做一个时间窗口,每个窗口仅允许限制的流量内的请求通过,具体如下图:
我们将是事件线切分成一个一个的限流窗口,每个限流窗口有一个窗口的开始和结束时间,窗口开始时,计数器清零,在这个窗口的时间范围内,每进来一个请求,计数器+1,如果计数器记录值超过限流阈值,就拒绝服务,直接给客户端响应503。当限流窗口结束后,进入下一个限流窗口,计数器再次清零,重新开始计数。
固定窗口的限流算法的核心代码实现如下:
public class FixedWindow extends AbstractLimitAlgo {private long windowLength;private AtomicInteger counter = new AtomicInteger(0);private Lock lock = new ReentrantLock();public FixedWindow(int limit,long windowLength) {super(limit);this.windowLength = windowLength;}@Overridepublic boolean tryAcquire() {long elapsedTimeStamp = getElapseTimeFromLast();if(elapsedTimeStamp >= windowLength) {lock.lock();try{if(getElapseTimeFromLast() >= windowLength) {lastTimeStamp = System.currentTimeMillis();counter.getAndSet(0);}}catch (Exception e) {e.printStackTrace();}finally {lock.unlock();}}return counter.incrementAndGet() <= limit;}
}
滑动窗口算法实思想比较简单,但是限流效果比较差,会出现 2倍配置速率问题,导致无法达到限流的目的。简单来说,当限流算法进入一个新的窗口后,计数器会重新计数,我们假设每个窗口限流100个请求,在第一个限流窗口快要结束时,突然进入进入100个请求,因为这个请求量在限流范围内,所以没有触发限流,请求全部通过,然后进入第二个限流窗口,计数器重新计数,这时又忽然进来100个请求,因为此时在第二个限流窗口,所以也没有触发限流,这就导致在短时间内进入了200个请求,这样会给系统造成巨大的负载压力。具体示意图如下:
滑动窗口
为了解决固定窗口2倍速率配置的问题,我们可以采用滑动窗口限流。滑动窗口之所以可以解决固定窗口2倍速率配置的问题,是因为滑动窗口将限流窗口划分成多个更细粒度的分片单元,滑动窗口每次只滑动一个分片单元,短时间出现的请求仍然在一个滑动窗口内,仍然可以被滑动窗口限流,也就是说,前一个滑动窗口的请求数量可以对下一个滑动窗口产生影响。而固定窗口的两个窗口之间完全没有任何关系,这也是固定窗口产生2倍速率配置问题的根本原因。滑动窗口示意图如下:
滑动窗口的实现方式和固定窗口基本是一致的,只不过要改动重置“窗口计数器”和“当前窗口结束时间”的逻辑就可以了,在重置窗口结束时间方面:固定窗口算法将窗口结束时间置为+1 窗口长度,而滑动窗口算法将窗口结束时间为+1时间片长度。在重置计数器方面:固定窗口算法直接将计数器置为0,而滑动窗口则是将计数器置为窗口包含时间片中所有请求之和。
滑动窗口实现代码如下:
public class SlideWindow extends AbstractLimitAlgo {private long windowLength;private AtomicInteger[] windowPlice;private AtomicInteger counter = new AtomicInteger(0);private Lock lock = new ReentrantLock();private volatile int index;private int newCounter;public SlideWindow(int limit, long windowLength, int unitCnt) {super(limit);this.windowLength = windowLength;this.lastTimeStamp = System.currentTimeMillis();this.windowPlice = new AtomicInteger[unitCnt];for(int i=0;i<unitCnt;i++) {windowPlice[i] = new AtomicInteger(0);}}@Overridepublic boolean tryAcquire() {long unitLength = windowLength / windowPlice.length;long elapseTimeStamp = getElapseTimeFromLast();if(elapseTimeStamp >= unitLength) {lock.lock();try{if(getElapseTimeFromLast() >= unitLength){newCounter += windowPlice[index].intValue();index = ++ index % windowPlice.length;newCounter -= windowPlice[index].intValue();windowPlice[index].getAndSet(0);counter.getAndSet(newCounter);lastTimeStamp = System.currentTimeMillis();}}catch (Exception e) {e.printStackTrace();}finally {lock.unlock();}}boolean result = counter.incrementAndGet() <= limit;if(result) {windowPlice[index].incrementAndGet();}return result;}
}
总结
本文介绍了限流算法中的固定窗口算法和滑动窗口算法,固定窗口算法实现简单,但是会出现2倍配置速率问题,滑动窗口通过将窗口划分成多个细粒度的时间分片,每次移动一个小的时间分片,来解决固定窗口的中的限流失效的问题。对于漏桶算法和令牌桶 算法,放在下一篇文章中讨论。
微服务中常用的限流算法(一)相关推荐
- Java中常用的限流算法
在Java的系统中,在一些活动日或者是被黑客攻击,导致访问量突然暴增,系统承受不了巨大的流量冲击而崩溃.为了保护我们的系统,在实际开发中有四种常见的限流算法来保证系统的安全性. 1 固定窗口算法 固定 ...
- golang bufio.newscanner如何超时跳出_Golang微服务的熔断与限流
(给Go开发大全加星标) 来源:Che Dan https://medium.com/@dche423/micro-in-action-7-cn-ce75d5847ef4 [导读]熔断和限流机制对于大 ...
- 亿级流量治理系列:常用的限流算法有哪些?
前言 上篇文章<为什么大公司都要做流量治理?>跟大家聊了下做流量治理的真正目的是什么.如果你要开发一个流量治理的平台或者一个限流的框架,那么必不可少的就是要选择一种合适的限流算法.本篇文章 ...
- 服务高可用利器——限流算法介绍与示例
文章目录 0.前言 1.计数器 1.1 简介 1.2 示例 2.滑动窗口 2.1 简介 2.2 示例 3.漏桶 3.1 简介 3.2 示例 4.令牌桶 4.1 简介 4.2 示例 5.小结 参考文献 ...
- 微服务之熔断、限流、降级 三板斧
系列服务器开发 文章目录 系列服务器开发 前言 一.背景 二.熔断 三. 限流 四. 降级 五.三种措施的差异 总结 前言 Spring Cloud全家桶是提供的一整套微服务开源解决方案,包括服务注册 ...
- 微服务架构 - Gateway网关限流
作者:pu20065226 cnblogs.com/pu20065226/p/11426279.html 1.算法 在高并发的应用中,限流是一个绕不开的话题.限流可以保障我们的 API 服务对所有用户 ...
- java中常见的限流算法详细解析
目录 前言 1. 验证限流以及容器限流 2. 服务端限流 2.1 固定时间窗口 2.2 滑动时间窗口 2.3 漏桶算法 2.4 令牌桶算法 前言 以下的文章参考了一些具体的资料加深了解 B站:Java ...
- 深度好文 — 微服务和API网关限流熔断实现关键逻辑思路
来源:https://www.toutiao.com/i6853970319745483275/?group_id=6853970319745483275 今天准备谈下微服务架构和API网关中的限流熔 ...
- SpringCloud微服务组件:Sentinel限流熔断
点击关注公众号,实用技术文章及时了解 前言 什么是雪崩问题? 微服务之间相互调用,因为调用链中的一个服务故障,引起整个链路都无法访问的情况. 解决雪崩问题的常见方式有四种: 超时处理:设定超时时间,请 ...
最新文章
- NeurIPS 2019最佳论文出炉,今年增设“新方向奖”,微软华人学者获经典论文奖...
- elasticsearch的多索引联合查询以及范围日期查询示例
- conv--向量的卷积和多项式乘法
- 如何挂载阿里云Linux服务器的“数据盘”(新购买)
- (原创)c#学习笔记08--面向对象编程简介02--OOP技术05--运算符重载
- android清理缓存功能吗,Android清理缓存功能实现
- 关于TTThumbsViewController加载更多
- 如何在 Ubuntu 中安装 QGit 客户端
- elasticsearch设置_search的size
- network 网络带宽
- 开运算和闭运算的性质
- 秒杀各大网盘的不限速大文件传输工具
- 表达式类型错误oracle,PL/SQL编译错误 - PLS-00382:表达式类型错误
- JavaWeb调用顺序
- 使用计算机教学的好处,谈计算机在教学中的作用
- 纹理的应用(凹凸贴图与法线贴图,三维噪声和三维纹理)
- 淘宝电商为什么转型社群团购,你知道吗?
- 一个只完成了一部分的小游戏。。。
- duet连win10_在Windows PC上使用Duet Display时连接不上Apple设备的解决方法之一
- java乱码base64_JavaScript BASE64算法实现(完美解决中文乱码)