zl程序教程

您现在的位置是:首页 >  其他

当前栏目

读书笔记:限流详解

2023-04-18 14:07:37 时间

from 《亿级流量网站架构核心技术 – 跟开涛学搭建高可用高并发系统》

在压测时我们可以找出每个系统的处理峰值,然后通过设定峰值阈值,来防止当系统过载时,通过拒绝处理过载的请求来保障系统可用。

限流需要评估好,不然会导致正常的流量出现异常,被用户投诉。

限流算法

常见的限流算法有:令牌桶。漏桶。计数器也可以用来进行简单粗暴限流实现。

令牌桶算法

存放固定容量令牌的桶,按照固定的速率往桶里添加令牌。 1、按照一定速率往桶里添加令牌。 2、桶里最多放m个令牌。 3、当一个n个字节大小的数据包到达,将从桶中删除n个令牌,接着数据包被发送到网络上。 4、如果桶中的令牌不足n个,则不会删除令牌,该数据包要么丢弃,要么在缓冲区等待。

漏桶算法

1、一个固定容量的漏桶,按照常量速率流出水滴。 2、如果桶是空的,则不需流出水滴。 3、可以以任意速率流入水滴到漏桶。 4、如果流入的水滴超出了桶的容量,则流入的水滴溢出(被丢弃),而漏桶容量不变。

应用级限流

1、限制 总并发/连接/请求数 对于一个应用系统来说,一定会有极限并发/请求数。如果超了阈值,则系统就会不响应用户请求或响应的非常慢,因此我们最好进行过载保护,以防止大量请求涌入击垮系统。

2、限流总资源数

3、限流某个接口的总并发/请求数

4、限流某个接口的时间窗请求数

5、平滑限流某个接口的请求数(令牌桶和漏桶)

分布式限流

redis + lua

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中判断是否需要限流的代码:

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 实现

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())

使用时需要定义两个共享字典:

http{
	···
	lua_shared_dict locks 10m;
	lua_shared_dict limit_counter 10m;
}

接入层限流

接入层通常指流量的入口,该层的主要目的有:负载均衡、非法请求过滤、请求聚合、缓存、降级、限流、A/B测试、服务质量监控等。

这个在我的毕设后面的版本需要系统学习nginx的时候会补充。目前强行看用处没那么大。