from 《亿级流量网站架构核心技术 – 跟开涛学搭建高可用高并发系统》
在压测时我们可以找出每个系统的处理峰值,然后通过设定峰值阈值,来防止当系统过载时,通过拒绝处理过载的请求来保障系统可用。
限流需要评估好,不然会导致正常的流量出现异常,被用户投诉。
限流算法
常见的限流算法有:令牌桶。漏桶。计数器也可以用来进行简单粗暴限流实现。
令牌桶算法
存放固定容量令牌的桶,按照固定的速率往桶里添加令牌。 1、按照一定速率往桶里添加令牌。 2、桶里最多放m个令牌。 3、当一个n个字节大小的数据包到达,将从桶中删除n个令牌,接着数据包被发送到网络上。 4、如果桶中的令牌不足n个,则不会删除令牌,该数据包要么丢弃,要么在缓冲区等待。
漏桶算法
1、一个固定容量的漏桶,按照常量速率流出水滴。 2、如果桶是空的,则不需流出水滴。 3、可以以任意速率流入水滴到漏桶。 4、如果流入的水滴超出了桶的容量,则流入的水滴溢出(被丢弃),而漏桶容量不变。
应用级限流
1、限制 总并发/连接/请求数 对于一个应用系统来说,一定会有极限并发/请求数。如果超了阈值,则系统就会不响应用户请求或响应的非常慢,因此我们最好进行过载保护,以防止大量请求涌入击垮系统。
2、限流总资源数
3、限流某个接口的总并发/请求数
4、限流某个接口的时间窗请求数
5、平滑限流某个接口的请求数(令牌桶和漏桶)
分布式限流
redis lua
代码语言:javascript复制local key = KEY[1] --限流 KEY
local limit = tonumber(ARGV[1]) --限流大小
local current = tonumber(redis.call('get',key) or "0") --请求数加1
if current 1 > limit then --超出限流大小
return 0
else then --请求数 1,并设置2秒过期
redis,call("INCRBY",key,"1")
redis.call("expire",key,"2")
return 1
end
Java中判断是否需要限流的代码:
代码语言:javascript复制public static boolean acquire() throws Exception{
string luaScript = Files.toString(new File("limit.lua"),Charset,defaultCharset());
Jedis jedis = new Jedis("127.0.0.1",6379);
String key = "ip:" System.currentTimeMillis()/1000;
String limit = "3";
return (long)jedis.eval(luaScript,Lists.newArrayList(key),Lists.newArrayList(limit))
}
nginx lua 实现
代码语言:javascript复制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())
使用时需要定义两个共享字典:
代码语言:javascript复制http{
···
lua_shared_dict locks 10m;
lua_shared_dict limit_counter 10m;
}
接入层限流
接入层通常指流量的入口,该层的主要目的有:负载均衡、非法请求过滤、请求聚合、缓存、降级、限流、A/B测试、服务质量监控等。
这个在我的毕设后面的版本需要系统学习nginx的时候会补充。目前强行看用处没那么大。