分布式限流方案
所属分类 architecture
浏览量 2536
高并发系统保护 缓存 降级 限流
限制总并发数(比如数据库连接池、线程池)
限制瞬时并发数(nginx的limit_conn模块,用来限制瞬时并发连接数)
限制时间窗口内的平均速率(如Guava的RateLimiter、nginx的limit_req模块)
限制远程接口调用频率、限制MQ的消费速率。
还可以根据网络连接数、网络流量、CPU或内存负载等来限流。
流量入口限流在接入层完成,接入层一般使用Nginx
业务限流
常见的限流算法
令牌桶 Token Bucket
漏桶 Leaky Bucket
简单的计数器限流
漏桶(Leaky Bucket)算法 ,水(请求)先进入到漏桶里,漏桶以一定的速度出水(接口有响应速率),
当水流入速度过大会直接溢出(访问频率超过接口响应速率),然后就拒绝请求
有两个变量,一个是桶的大小,支持流量突发增多时可以存多少的水(burst),另一个是水桶漏洞的大小(rate)。
令牌桶算法(Token Bucket),按恒定1/QPS时间间隔(如果QPS=100,则间隔是10ms)往桶里加入Token ,如果桶已经满了就不再加了.
请求到来时,会去拿一个Token,如果没有Token了就阻塞或者拒绝服务
令牌桶和漏桶对比
令牌桶是按照固定速率往桶中添加令牌,请求是否被处理需要看桶中令牌是否足够,当令牌数减为零时则拒绝新的请求;
漏桶则是按照常量固定速率流出请求,流入请求速率任意,当流入的请求数累积到漏桶容量时,则新流入的请求被拒绝;
令牌桶限制的是平均流入速率(允许突发请求,只要有令牌就可以处理,支持一次拿3个令牌,4个令牌),并允许一定程度突发流量;
漏桶限制的是常量流出速率(即流出速率是一个固定常量值,比如都是1的速率流出,而不能一次是1,下次又是2),从而平滑突发流入速率;
令牌桶允许一定程度的突发,而漏桶主要目的是平滑流入速率;
两个算法实现可以一样,但是方向是相反的,对于相同的参数得到的限流效果是一样的。
Guava RateLimiter 提供令牌桶算法实现 平滑突发限流(SmoothBursty)和平滑预热限流(SmoothWarmingUp)
RateLimiter.create(5)
桶容量为5且每秒新增5个令牌,即每隔200毫秒新增一个令牌
单节点,可使用 Guava RateLimiter
集群qps/集群节点数
分布式系统中 , 统一管理 , 可在 网关限流
限流服务化
Redis+Lua 和 Nginx+Lua
或者直接 封装 Guava RateLimiter 提供限流服务
redis+lua lua脚本
local key = KEYS[1]
--限流大小
local limit = tonumber(ARGV[1])
local current = tonumber(redis.call("INCRBY", key, "1"))
if current > limit then
return 0
elseif current == 1 then
redis.call("expire", key,"1")
end
return 1
Nginx+Lua Lua脚本
local locks = require "resty.lock"
local function acquire()
local lock =locks:new("locks")
local elapsed, err =lock:lock("limit_key") --互斥锁
local limit_counter =ngx.shared.limit_counter --计数器
local key = "ip:" ..os.time()
local limit = 5 --限流大小
local current =limit_counter:get(key)
if current ~= nil and current + 1> limit then --如果超出限流大小
lock:unlock()
return 0
end
if current == nil then
limit_counter:set(key, 1, 1) --第一次需要设置过期时间,设置key的值为1,过期时间为1秒
else
limit_counter:incr(key, 1) --第二次开始加1即可
end
lock:unlock()
return 1
end
ngx.print(acquire())
上一篇
下一篇
集群session处理
分布式数据库主键生成方案
properties与yml配置文件比较
lua函数使用说明
jvm相关知识点
ConcurrentHashMap读操作为什么不需要加锁