其他
高并发系统中的限流应该如何做?
本文来源:
cnblogs.com/haoxinyue/p/6792309.html
缓存
降级
限流
限流的算法
计数器
//服务访问次数,可以放在Redis中,实现分布式系统的访问计数
Long counter = 0L;
//使用LinkedList来记录滑动窗口的10个格子。
LinkedList<Long> ll = new LinkedList<Long>();
public static void main(String[] args)
{
Counter counter = new Counter();
counter.doCheck();
}
private void doCheck()
{
while (true)
{
ll.addLast(counter);
if (ll.size() > 10)
{
ll.removeFirst();
}
//比较最后一个和第一个,两者相差一秒
if ((ll.peekLast() - ll.peekFirst()) > 100)
{
//To limit rate
}
Thread.sleep(100);
}
}
漏桶算法
一个固定容量的漏桶,按照常量固定速率流出水滴; 如果桶是空的,则不需流出水滴; 可以以任意速率流入水滴到漏桶; 如果流入水滴超出了桶的容量,则流入的水滴溢出了(被丢弃),而漏桶容量是不变的。
令牌桶算法
令牌将按照固定的速率被放入令牌桶中。比如每秒放10个。 桶中最多存放b个令牌,当桶满时,新添加的令牌被丢弃或拒绝。 当一个n个字节大小的数据包到达,将从桶中删除n个令牌,接着数据包被发送到网络上。 如果桶中的令牌不足n个,则不会删除令牌,且该数据包将被限流(要么丢弃,要么缓冲区等待)。
漏桶和令牌桶的比较
限流算法实现
Guava
public void test()
{
/**
* 创建一个限流器,设置每秒放置的令牌数:2个。速率是每秒可以2个的消息。
* 返回的RateLimiter对象可以保证1秒内不会给超过2个令牌,并且是固定速率的放置。达到平滑输出的效果
*/
RateLimiter r = RateLimiter.create(2);
while (true)
{
/**
* acquire()获取一个令牌,并且返回这个获取这个令牌所需要的时间。如果桶里没有令牌则等待,直到有令牌。
* acquire(N)可以获取多个令牌。
*/
System.out.println(r.acquire());
}
}
System.out.println(r.acquire(2));
System.out.println(r.acquire(1));
System.out.println(r.acquire(1));
System.out.println(r.acquire(1));
得到如下类似的输出。
System.out.println(r.acquire(1));
Thread.sleep(2000);
System.out.println(r.acquire(1));
System.out.println(r.acquire(1));
System.out.println(r.acquire(1));
/**
* 创建一个限流器,设置每秒放置的令牌数:2个。速率是每秒可以210的消息。
* 返回的RateLimiter对象可以保证1秒内不会给超过2个令牌,并且是固定速率的放置。达到平滑输出的效果
* 设置缓冲时间为3秒
*/
RateLimiter r = RateLimiter.create(2,3,TimeUnit.SECONDS);
while (true) {
/**
* acquire()获取一个令牌,并且返回这个获取这个令牌所需要的时间。如果桶里没有令牌则等待,直到有令牌。
* acquire(N)可以获取多个令牌。
*/
System.out.println(r.acquire(1));
System.out.println(r.acquire(1));
System.out.println(r.acquire(1));
System.out.println(r.acquire(1));
}
Nginx
连接数限流模块ngx_http_limit_conn_module 漏桶算法实现的请求限流模块ngx_http_limit_req_module
#限制每个用户的并发连接数,取名one
limit_conn_zone $binary_remote_addr zone=one:10m;
#配置记录被限流后的日志级别,默认error级别
limit_conn_log_level error;
#配置被限流后返回的状态码,默认返回503
limit_conn_status 503;
然后在server{}里加上如下代码:
#限制用户并发连接数为1
limit_conn one 1;
然后我们是使用ab测试来模拟并发请求:
ab -n 5 -c 5 http://10.23.22.239/index.html
得到下面的结果,很明显并发被限制住了,超过阈值的都显示503:
#http{}段配置
limit_conn_zone $ server_name zone=perserver:10m;
#server{}段配置
limit_conn perserver 1;
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
limit_req zone=one burst=5;
● 如何设计缓存系统:缓存穿透,缓存击穿,缓存雪崩解决方案分析
● Spring Boot实战:逐行释义HelloWorld
● Spring Boot的自动配置、Command-line Runner
● Spring Boot 应用 - 静态视频资源实时播放新姿势