技术标签: 架构设计
在开发高并发系统时,有三把利器用来保护系统:缓存、降级和限流。那么何为限流呢?顾名思义,限流就是限制流量,就像你宽带包了1个G的流量,用完了就没了。通过限流,我们可以很好地控制系统的qps,从而达到保护系统的目的。本篇文章将会介绍一下常用的限流算法以及他们各自的特点。
令牌桶算法是比较常见的限流算法之一,大概描述如下:
实现思路:可以准备一个队列,用来保存令牌,另外通过一个线程池定期生成令牌放到队列中,每来一个请求,就从队列中获取一个令牌,并继续执行。
幸运的是,通过Google开源的guava包,我们可以很轻松的创建一个令牌桶算法的限流器。
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
通过RateLimiter类的create方法,创建限流器。
public class RateLimiterMain {
public static void main(String[] args) {
RateLimiter rateLimiter = RateLimiter.create(10);
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
rateLimiter.acquire()
System.out.println("pass");
}
}).start();
}
}
}
其实Guava提供了多种create方法,方便创建适合各种需求的限流器。在上述例子中,创建了一个每秒生成10个令牌的限流器,即100ms生成一个,并最多保存10个令牌,多余的会被丢弃。
rateLimiter提供了acquire()和tryAcquire()接口 :
漏桶算法其实很简单,可以粗略的认为就是注水漏水过程,往桶中以一定速率流出水,以任意速率流入水,当水超过桶流量则丢弃,因为桶容量是不变的,保证了整体的速率。
在算法实现方面,可以准备一个队列,用来保存请求,另外通过一个线程池定期从队列中获取请求并执行,可以一次性获取多个并发执行。
这种算法,在使用过后也存在弊端:无法应对短时间的突发流量。
计数器算法是限流算法里最简单也是最容易实现的一种算法。比如我们规定,对于A接口来说,我们1分钟的访问次数不能超过100个。那么我们可以这么做:在一开 始的时候,我们可以设置一个计数器counter,每当一个请求过来的时候,counter就加1,如果counter的值大于100并且该请求与第一个 请求的间隔时间还在1分钟之内,那么说明请求数过多;如果该请求与第一个请求的间隔时间大于1分钟,且counter的值还在限流范围内,那么就重置 counter,具体算法的示意图如下:
具体的伪代码如下:
public class CounterTest {
public long timeStamp = getNowTime();
public int reqCount = 0;
public final int limit = 100; // 时间窗口内最大请求数
public final long interval = 1000; // 时间窗口ms
public boolean grant() {
long now = getNowTime();
if (now < timeStamp + interval) {
// 在时间窗口内
reqCount++;
// 判断当前时间窗口内是否超过最大请求控制数
return reqCount <= limit;
} else {
timeStamp = now;
// 超时后重置
reqCount = 1;
return true;
}
}
public long getNowTime() {
return System.currentTimeMillis();
}
}
这个算法虽然简单,但是有一个十分致命的问题,那就是临界问题,我们看下图:
从上图中我们可以看到,假设有一个恶意用户,他在0:59时,瞬间发送了100个请求,并且1:00又瞬间发送了100个请求,那么其实这个用户在 1秒里面,瞬间发送了200个请求。我们刚才规定的是1分钟最多100个请求,也就是每秒钟最多1.7个请求,用户通过在时间窗口的重置节点处突发请求, 可以瞬间超过我们的速率限制。用户有可能通过算法的这个漏洞,瞬间压垮我们的应用。
聪明的朋友可能已经看出来了,刚才的问题其实是因为我们统计的精度太低。那么如何很好地处理这个问题呢?或者说,如何将临界问题的影响降低呢?我们可以看下面的滑动窗口算法。
滑动窗口,又称rolling window。为了解决这个问题,我们引入了滑动窗口算法。如果学过TCP网络协议的话,那么一定对滑动窗口这个名词不会陌生。下面这张图,很好地解释了滑动窗口算法:
在上图中,整个红色的矩形框表示一个时间窗口,在我们的例子中,一个时间窗口就是一分钟。然后我们将时间窗口进行划分,比如图中,我们就将滑动窗口 划成了6格,所以每格代表的是10秒钟。每过10秒钟,我们的时间窗口就会往右滑动一格。每一个格子都有自己独立的计数器counter,比如当一个请求 在0:35秒的时候到达,那么0:30~0:39对应的counter就会加1。
那么滑动窗口怎么解决刚才的临界问题的呢?我们可以看上图,0:59到达的100个请求会落在灰色的格子中,而1:00到达的请求会落在橘黄色的格 子中。当时间到达1:00时,我们的窗口会往右移动一格,那么此时时间窗口内的总请求数量一共是200个,超过了限定的100个,所以此时能够检测出来触 发了限流。
我再来回顾一下刚才的计数器算法,我们可以发现,计数器算法其实就是滑动窗口算法。只是它没有对时间窗口做进一步地划分,所以只有1格。
由此可见,当滑动窗口的格子划分的越多,那么滑动窗口的滚动就越平滑,限流的统计就会越精确。
数据表如下:postgresQL无主键数据表地方
记录正则表达式用法。原文地址:http://www.cnblogs.com/deerchao/archive/2006/08/24/zhengzhe30fengzhongjiaocheng.htmldeerchao的blogBe and aware of who you are.正则表达式30分钟入门教程来园子之前写的一篇正则表达式教程,部分翻译自c
2008-09-01我叔叔机器拿回来后,设置了个新的用户,没有设置密码,原来用户有密码的,删除不了,重新开机后,新用户自动出来用密码登陆,我们试过老密码,但是不行,这个账号没有设置密码啊~~~~~~~~~他出来的是更改密码的设置,需要旧密码,和设置新密码,但我们没有旧密码啊,怎么办~~~~~~~~~~~~XP密码忘了,解决方法种种奇招1:大家知道,windows xp的密码存放在系统所在的winn...
背景:作为web前端的程序员都知道,许多需要使用png图片,但是目前仍然占据大部分市场的IE6却有着png图片背景不能透明的bug,下面分析一下:目录:一、可解决的方法1. css滤镜2. 老JavaScript方法3. jQuery实现4. flash实现二、产生的问题1. 响应单击事件2. 图片大小控制3. 背景图片的定位三、相...
当使用多线程访问同一个资源的时候,非常容易出现线程安全的问题(例如,当多个线程同时对一个数据进行修改的时候,会导致某些线程对数据的修改丢失)。因此,需要采用同步机制来解决这种问题。而Java主要提供了三种实现同步机制的方法。今天我们就来认识一下~~一、synchronized关键字在Java语言中,每个对象都有一个对象锁与之相关联,该锁表明对象在任何时候只允许被一个线程锁拥有,当一个线...
在南京第二家公司刚接触到在MFC下读写INI配置文件,下面介绍一下关于如何去读写INI配置文件吧。首先说明一下配置文件的格式:例如:[COUNT]COUNT=6[LONGIN]USER=admin[INFO1]BANK=中国银行ASSIGNPATH=中国银行\{YYYYMMDD}\ACCESSPATH=D:\中国银行\{YYYYMMDD}\
在工作中我们经常会遇到数据类型之间的互转的问题,而通常我们请求一些API借口返回的结果就是字符串,但是格式是Json的,在Python中转为字典是最易处理的,所以这里记录一下在Python下把字符串转为字典的三种方法。方法一: 通过内置函数evalSource Code:#!/usr/bin/env python3#Author: nock.chenstr_info = "{'name...
HTTP在ios中虽然用的多,但对原理理解较少,这篇文章总结的挺好,留着学习。HTTP属于老话题了,在项目中我们经常需要往服务端发POST或者GET请求,但是对于HTTP的了解不应只局限于此。千里之行,始于足下。越想走的远,基本原理就应该了解的透彻全面一些,仅仅停留在使用ASIHttpRequest或者AFNetWorking传个参数发个请求的程度上是不够的。这篇文章就是带你全方面回顾一下HT...
例:这个是根据 列1 == '旧值'这个条件,将列2指定为新的值df.loc[df[(df.列1 == '旧值')].index.tolist(),'列2'] = '新的值'
首先安装这个真的出了好多问题,之前装过一次PIL也失败了,就一直没管,今天刚好找了机会把PIL装好了。如果直接用pip install PIL, 确实可以安装,但是运行代码import ImageFont的时候会报错没有引用C模块什么的。然后就这个找了半天还是不行然后尝试用exe安装。没有一开始就用exe的原因是我电脑读不出来Python2的安装路径,再看能不能手动找路径的时候发现了pcat的解
前一阵子有个网友通过之前写的一篇音频可视化的文章找到我,让我帮忙给他的音乐网站加个播放效果,自己正好没啥事做欣然答应。由于疏于学习,基础掌握的不好,我一直以为音频可视化是通过Web audio API实现的,脑子不会转弯,总觉得只能通过这种方法载入音频: var audio = new Audio("hello.mp4");然后打一套API的组合拳来读取音频数据: AudioContex...
LeetCode第34题:在排序数组中查找元素的第一个和最后一个位置(中等)题目:给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。你的算法时间复杂度必须是 O(log n) 级别。如果数组中不存在目标值,返回 [-1, -1]。解法一:算是一种暴力解法了,没有关注到数组已排序,其实这种做法自己也觉得很无聊。。。。class...