爱美眉网站源码,西安到北京,wordpress响应式后台,上海工商信息查询网限流定义及目的
当系统流量达到系统或下游承受能力的阈值时对系统进行限流控制以防止系统或下游挂掉#xff0c;减少影响面。
限流组成#xff1a;阈值及限流策略。阈值是指系统单位时间接收到的请求qps总数#xff1b;限流策略是指限流行业触发后对应的系统行为#xff…限流定义及目的
当系统流量达到系统或下游承受能力的阈值时对系统进行限流控制以防止系统或下游挂掉减少影响面。
限流组成阈值及限流策略。阈值是指系统单位时间接收到的请求qps总数限流策略是指限流行业触发后对应的系统行为如失败拒绝还是放入等待队列。
应用场景
如秒杀业务商品变更消息等场景。
秒杀业务通常来说是保护全链路系统不挂特性是瞬时流量大超过阈值时拒绝策略通常是返回失败。
商品变更消息业务场景是需要将商品变更消息推送给下游商家下游商家系统能力有限因此需要做限制这个场景更多是保护下游系统不挂整条系统链路上最小短板。
分类
4大类计数滑动窗口漏桶令牌。
计数(固定时间窗口)
单位时间窗口内进行计数超过阈值则进行限流。
算法限制只能限制一整秒流量。若出现第1秒中后500ms和第2秒中前500ms超过阈值则此时不生效。
实现代码
import exception.BlockException;
import java.util.concurrent.atomic.AtomicInteger;
public class CalNumProcessor {//限流窗口大小private static int WINDOW_TIME_MILL 1000;//阈值private static final int LIMIT_NUMS 10;//计数器private AtomicInteger count new AtomicInteger(0);//开始时间private Long startTime;public static void main(String[] args) throws InterruptedException {CalNumProcessor calNumProcessornew CalNumProcessor();for(int i0;i1000;i){System.out.println(i);calNumProcessor.tryIncAndLimit();Thread.sleep(200);}}/*** 进行限流计数超过限流阈值时会抛BlockException*/public void tryIncAndLimit() {//当前时间long curMill System.currentTimeMillis();//开始时间初始化if (startTime null) {startTime curMill;}if ((curMill - startTime) WINDOW_TIME_MILL) {//若时间计数超过一秒则重置计数为0并重新设置计数开始时间count.set(0);startTime curMill;}int after count.incrementAndGet();if (after LIMIT_NUMS) {//超过阈值throw new BlockException();}}
}
滑动窗口
计数有个问题在于流量放大无法限流。如1秒为计数窗口。则第一秒后半秒和第二秒前半秒累计可能超过qps限制但由于不是一个时间窗口此时反而不能限制住。
解决思路每次请求计数每过一个时间窗口单位进行滑动计数。
整体算法思路详细
1.构建n个时间窗口单位每个窗口单位有对应qps变量及窗口开始时间初始化时间窗口单位的qps为0及开始时间为当前时间
2.每次获取qps时计算当前时间应该在哪个时间窗口单位
3.循环处理时间窗口如果发现当前时间与时间窗口单位超过1秒时间窗口单位最大时间则重置窗口开始时间及qps为0。
4.将当前时间对应时间窗口qps加1
5.返回所有时间窗口单位qps累计值 代码实现
import java.time.LocalTime;
import java.util.concurrent.atomic.AtomicInteger;public class TimeWindow {/*** 时间窗口大小如1秒*/private int windowTimeSize;/*** 窗口数*/private int windowNum;private Window[] windows;private int maxQps;public TimeWindow(int maxQps, int windowTimeSize, int windowNum) {this.maxQps maxQps;this.windowTimeSize windowTimeSize;this.windowNum windowNum;windows new Window[windowNum];for (int i 0; i windowNum; i) {windows[i] new Window();windows[i].setQps(new AtomicInteger(0));windows[i].setStartTime(System.currentTimeMillis());}}public static void main(String[] args) throws InterruptedException {int qps 2;int count 20;int sleep 300;int success 0;TimeWindow timeWindow new TimeWindow(qps, 1000, 10);for (int i 0; i count; i) {Thread.sleep(sleep);if (timeWindow.tryAcquire()) {success;if (success % qps 0) {System.out.println(LocalTime.now() : success, );} else {System.out.print(LocalTime.now() : success, );}} else {System.out.println(LocalTime.now() : fail);}}System.out.println();System.out.println(实际测试成功次数: success);}public boolean tryAcquire() {//计算当前时间落到哪个窗口位置int index (int) (System.currentTimeMillis() % windowTimeSize) / (windowTimeSize / windowNum);//当前时间若超过时间累计窗口则重置窗口参数int r 0;for (int i 0; i windowNum; i) {Window curWindow windows[i];if ((System.currentTimeMillis() - curWindow.getStartTime()) windowTimeSize) {//当前时间减去时间窗口大于最大累计时间窗口大小则重置变量curWindow.setQps(new AtomicInteger(0));curWindow.setStartTime(System.currentTimeMillis());}//当前时间对应窗口累计qpsif (index i) {curWindow.getQps().incrementAndGet();}r curWindow.getQps().get();}return r maxQps;}class Window {/*** qps*/private AtomicInteger qps;/*** 开始时间*/private long startTime;public AtomicInteger getQps() {return qps;}public void setQps(AtomicInteger qps) {this.qps qps;}public long getStartTime() {return startTime;}public void setStartTime(long startTime) {this.startTime startTime;}}
} 漏桶算法
流出衡定不能应对突发流量能较好保护下游。 令牌算法
优能处理突出流量流入相对衡定流出允许有波动。秒杀场景适用。
这里核心概念令牌桶有令牌数及桶上限2个参数令牌获取令牌存放令牌
存放令牌策略有1、有单独线路每秒加入n个令牌(相当于qps为n)2、懒计算当获取令牌请求到来时进行计算计算思路Math.min(当前时间距离上次已存放令牌时间间隔秒数*令牌qps,令牌数上限)。 代码 RateLimiter rateLimiter RateLimiter.create(2);for (int i 0; i 10; i) {String time LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_TIME);System.out.println(time : rateLimiter.tryAcquire());Thread.sleep(250);}
实现产品
guava阿里的sentinal。TODO。