Redis+Lua+Java

Java+Redis+Lua

Redis在2.6推出了脚本功能,允许开发者使用Lua语言编写脚本传到Redis中执行。使用脚本的好处如下:

1.减少网络开销:本来5次网络请求的操作,可以用一个请求完成,原先5次请求的逻辑放在redis服务器上完成。使用脚本,减少了网络往返时延。
2.原子操作:Redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。
3.复用:客户端发送的脚本会永久存储在Redis中,意味着其他客户端可以复用这一脚本而不需要使用代码完成同样的逻辑。


高并发 原子 交互
1 redis执行可以保证lua脚本的执行的原子性
2 减少网络延迟


/**
 * [times description]
 * @type {[type]}
   下标从1开始
 */
local times = redis.call('incr',KEYS[1])

if times == 1 then
    redis.call('expire',KEYS[1], ARGV[1])
end

if times > tonumber(ARGV[2]) then
    return 0
end
return 1

redis-cli --eval ratelimiting.lua rate.limitingl:127.0.0.1 , 10 3
                                        KEYS                 ARGV

--eval参数是告诉redis-cli读取并运行后面的Lua脚本,ratelimiting.lua是脚本的位置,
后面跟着是传给Lua脚本的参数。其中","前的rate.limiting:127.0.0.1是要操作的键,可以再脚本中用KEYS[1]获取,
","后面的10和3是参数,在脚本中能够使用ARGV[1]和ARGV[2]获得。注:","两边的空格不能省略,否则会出错。
 

 

*********************************分布式限流器*******************************************************

local tokens_key = KEYS[1]
local timestamp_key = KEYS[2]
local rate = tonumber(ARGV[1])
local capacity = tonumber(ARGV[2])
local now = tonumber(ARGV[3])
local requested = tonumber(ARGV[4])
local fill_time = capacity/rate
local ttl = math.floor(fill_time*2)
local last_tokens = tonumber(redis.call("get", tokens_key))
if last_tokens == nil then
  last_tokens = capacity
end
local last_refreshed = tonumber(redis.call("get", timestamp_key))
if last_refreshed == nil then
  last_refreshed = 0
end
local delta = math.max(0, now-last_refreshed)
local filled_tokens = math.min(capacity, last_tokens+(delta*rate))
local allowed = filled_tokens >= requested
local new_tokens = filled_tokens
local allowed_num = 0
if allowed then
  new_tokens = filled_tokens - requested
  allowed_num = 1
end
redis.call("setex", tokens_key, ttl, new_tokens)
redis.call("setex", timestamp_key, ttl, now)
return { allowed_num, new_tokens }


String prefix = "rate_limiter.{" + key;
String tokenKey = prefix + "}.tokens";
String timestampKey = prefix + "}.timestamp";
return Arrays.asList(tokenKey, timestampKey);

int burstCapacity = replenishRate;
List<String> keys = getKeys(key);
List<String> scriptArgs = Arrays.asList(String.valueOf(replenishRate), String.valueOf(burstCapacity),
        String.valueOf(System.currentTimeMillis() / 1000L), "1");
Object reply = jedisCluster.eval(rateLimiterScript, keys, scriptArgs);
if (LOGGER.isDebugEnabled()) {
    LOGGER.debug("Redis Response=" + reply);
}
if (reply != null && List.class.isAssignableFrom(reply.getClass())) {
    List list = List.class.cast(reply);
    if (CollectionUtils.isNotEmpty(list)) {
        Object item;
        return NumberUtils.toInt((item = list.get(0)) != null ? item.toString() : null, -1) > 0;
    }
}

***********************************************************************************************************************************************

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值