在高并发系统中,需要使用多种方式来保护系统,例如:
所以,限流是保证系统高可用的重要手段。
在单机系统中,限流逻辑直接放在服务接口中即可,Guava RateLimiter 可以方便的实现。
但在分布式系统中,一个服务可能启动多个实例,需要对服务整体进行限流,就不能放在每个实例中进行限流判断了,需要统一管理,例如放到API网关中:
分布式限流最关键的是要将限流服务做成原子化,常见的方案是 Redis+Lua 和 Nginx+Lua。
Lua 代码:
-- 获取调用脚本时传入的第一个key值(用作限流的 key)
local key = KEYS[1]
-- 获取调用脚本时传入的第一个参数值(限流大小)
local limit = tonumber(ARGV[1])
-- 获取当前流量大小
local curentLimit = tonumber(redis.call('get', key) or "0")
-- 是否超出限流
if curentLimit + 1 > limit then
-- 返回(拒绝)
return 0
else
-- 没有超出 value + 1
redis.call("INCRBY", key, 1)
-- 设置过期时间
redis.call("EXPIRE", key, 2)
-- 返回(放行)
return 1
end
Redis 是单线程,如上的限流逻辑是在 Lua 脚本中,是线程安全的。
Java 调用示例代码:
public boolean limit() throws Exception {
String luaScript = Files.toString(
new File("limit.lua")
, Charset.defaultCharset());
Jedis jedis = new Jedis(ip, port);
String key = "ip:"
+ System.currentTimeMillis()/1000;
String limit = "3";
ArrayList<String> scriptKeys =
Lists.newArrayList(key);
ArrayList<String> scriptArgs =
Lists.newArrayList(limit);
return (Long)jedis.eval(
luaScript,
scriptKeys,
scriptArgs) == 1;
}
点击?阅读原文,查看文章列表