首页  

分布式限流方案     所属分类 architecture 浏览量 302
高并发系统保护  缓存 降级 限流

限制总并发数(比如数据库连接池、线程池)
限制瞬时并发数(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读操作为什么不需要加锁