parent
f6bdc25ea2
commit
de50c4dd5a
@ -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 |
Loading…
Reference in new issue