赞
踩
在开发高并发系统时,有很多手段来保护系统,如缓存,降级和限流,限流的目的是通过对并发访问/请求进行限速或者一个时间窗口内的请求进行限速来保护系统。一旦达到限速之后可以通过拒绝服务(定向页面跳转)或者排队等待的方式,以保证系统的高可用,防止瞬时的大并发访问冲垮系统
一般开发高并发系统常见的限流有:
限制总并发数(比如数据库连接池,线程池),限制瞬时并发数,限制时间窗口内的平局时速(可以通过guava中的RateLimiter实现)
计数器算法是限流算法中最简单的,它是针对于固定时间范围内,对于访问总数的一个限流,假如系统要求在一分钟内访问不超过100次,大致的设计原理如下:
主要的设计逻辑是,首先定义一个计数器regCount,每当系统访问就加一,如果当前访问时间间隔处于指定时间间隔内之后,并且当前的regCount小于访问阈值,即可以访问,如果当前访问时间超过当前指定时间间隔(系统重新计算),直接设置当前记时时间未当前访问时间,并且regCount设置1
这个算法虽然简单,但是有一个十分致命的问题,那就是临界问题,我们看下图:
从上图中我们可以看到,假设有一个恶意用户,他在0:59时,瞬间发送了100个请求,并且1:00又瞬间发送了100个请求,那么其实这个用户在 1秒里面,瞬间发送了200个请求。我们刚才规定的是1分钟最多100个请求,也就是每秒钟最多1.7个请求,用户通过在时间窗口的重置节点处突发请求, 可以瞬间超过我们的速率限制。用户有可能通过算法的这个漏洞,瞬间压垮我们的应用。
聪明的朋友可能已经看出来了,刚才的问题其实是因为我们统计的精度太低。那么如何很好地处理这个问题呢?或者说,如何将临界问题的影响降低呢?我们可以看下面的滑动窗口算法。
滑动窗口
在上图中,整个红色的矩形框表示一个时间窗口,在我们的例子中,一个时间窗口就是一分钟。然后我们将时间窗口进行划分,比如图中,我们就将滑动窗口 划成了6格,所以每格代表的是10秒钟。每过10秒钟,我们的时间窗口就会往右滑动一格。每一个格子都有自己独立的计数器counter,比如当一个请求 在0:35秒的时候到达,那么0:30~0:39对应的counter就会加1。
那么滑动窗口怎么解决刚才的临界问题的呢?我们可以看上图,0:59到达的100个请求会落在灰色的格子中,而1:00到达的请求会落在橘黄色的格 子中。当时间到达1:00时,我们的窗口会往右移动一格,那么此时时间窗口内的总请求数量一共是200个,超过了限定的100个,所以此时能够检测出来触 发了限流。
我再来回顾一下刚才的计数器算法,我们可以发现,计数器算法其实就是滑动窗口算法。只是它没有对时间窗口做进一步地划分,所以只有1格。
由此可见,当滑动窗口的格子划分的越多,那么滑动窗口的滚动就越平滑,限流的统计就会越精确。
令牌桶算法,是一个存放固定容量令牌的桶,按照固定速率网桶里面添加令牌,大致的逻辑如下:
漏桶作为计量工具时,可以用于流量整形和流量控制,漏桶算法的描述如下:
Tomcat中和一些基本的容器配置参数
限制总资源数
限制某个接口的总并发/请求 数
限制某个接口的时间窗请求数
平滑限制某个接口的请求数(gavva RateLimiter)
分布式限流最关键的是要将限流服务做成原子化,Redis+Lua 或者是Nginx+Lua
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。