mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 21:57:56 +08:00
支持分布式限流
This commit is contained in:
@@ -37,7 +37,7 @@ public class ConfigLimitDto {
|
|||||||
/** 服务id, 数据库字段:service_id */
|
/** 服务id, 数据库字段:service_id */
|
||||||
private String serviceId;
|
private String serviceId;
|
||||||
|
|
||||||
/** 限流策略,1:漏桶策略,2:令牌桶策略, 数据库字段:limit_type */
|
/** 限流策略,1:窗口策略,2:令牌桶策略, 数据库字段:limit_type */
|
||||||
private Byte limitType;
|
private Byte limitType;
|
||||||
|
|
||||||
/** 每秒可处理请求数, 数据库字段:exec_count_per_second */
|
/** 每秒可处理请求数, 数据库字段:exec_count_per_second */
|
||||||
|
@@ -0,0 +1,79 @@
|
|||||||
|
package com.gitee.sop.gatewaycommon.limit;
|
||||||
|
|
||||||
|
import com.gitee.sop.gatewaycommon.bean.ConfigLimitDto;
|
||||||
|
import com.gitee.sop.gatewaycommon.bean.SopConstants;
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
|
import org.springframework.data.redis.core.script.RedisScript;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基于redis限流管理
|
||||||
|
*
|
||||||
|
* @author tanghc
|
||||||
|
*/
|
||||||
|
public class RedisLimitManager extends DefaultLimitManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 限流脚本
|
||||||
|
*/
|
||||||
|
private static final String DEFAULT_LIMIT_LUA_FILE_PATH = "/sop/limit.lua";
|
||||||
|
|
||||||
|
private static final Long REDIS_SUCCESS = 1L;
|
||||||
|
|
||||||
|
private StringRedisTemplate redisTemplate;
|
||||||
|
private String limitScript;
|
||||||
|
private String limitScriptSha1;
|
||||||
|
|
||||||
|
public RedisLimitManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
|
||||||
|
Assert.notNull(redisTemplate, "redisTemplate不能为null");
|
||||||
|
this.redisTemplate = new StringRedisTemplate(redisTemplate.getConnectionFactory());
|
||||||
|
ClassPathResource limitLua = new ClassPathResource(getLimitLuaFilePath());
|
||||||
|
try {
|
||||||
|
this.limitScript = IOUtils.toString(limitLua.getInputStream(), SopConstants.UTF8);
|
||||||
|
this.limitScriptSha1 = DigestUtils.sha1Hex(this.limitScript);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("读取脚本文件失败,脚本路径:" + getLimitLuaFilePath(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLimitLuaFilePath() {
|
||||||
|
return DEFAULT_LIMIT_LUA_FILE_PATH;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean acquire(ConfigLimitDto routeConfig) {
|
||||||
|
String key = "sop:lmt:" + routeConfig.getRouteId();
|
||||||
|
int limitCount = routeConfig.getExecCountPerSecond();
|
||||||
|
|
||||||
|
Object result = redisTemplate.execute(
|
||||||
|
new RedisScript<Long>() {
|
||||||
|
@Override
|
||||||
|
public String getSha1() {
|
||||||
|
return limitScriptSha1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<Long> getResultType() {
|
||||||
|
return Long.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getScriptAsString() {
|
||||||
|
return limitScript;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// KEYS[1] key
|
||||||
|
Collections.singletonList(key),
|
||||||
|
// ARGV[1] limit
|
||||||
|
String.valueOf(limitCount)
|
||||||
|
);
|
||||||
|
return REDIS_SUCCESS.equals(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,10 @@
|
|||||||
|
local key = KEYS[1] --限流KEY(一秒一个)
|
||||||
|
local limit = tonumber(ARGV[1]) --限流大小
|
||||||
|
local current = tonumber(redis.call("get", key)) or 0
|
||||||
|
if current + 1 > limit then --如果超出限流大小
|
||||||
|
return 0
|
||||||
|
else --请求数+1,并设置2秒过期
|
||||||
|
redis.call("INCRBY", key,"1")
|
||||||
|
redis.call("expire", key,"2")
|
||||||
|
return 1
|
||||||
|
end
|
Reference in New Issue
Block a user