java redis令牌桶_redis 令牌桶算法—Lua-Go语言中文社区

令牌桶算法

8e39f6a5184ff84409bb0f2dace2d33f.png

场景:秒杀(也可以用于平滑限流某个接口请求)

import java.io.IOException;

import java.nio.charset.Charset;

import org.springframework.core.io.ClassPathResource;

import com.google.common.io.Files;

import redis.clients.jedis.Jedis;

/***

*@author dzb

*@date 2019/11/3 22:09

*@Description: 令牌桶

* */

public class JedisLuaTokenTimeLimiter {

/**执行脚本**/

private String luaScript;

/**值**/

private String key;

/**限流次数**/

private String limit;

/**时间**/

private String expire;

public JedisLuaTokenTimeLimiter(String key, String limit, String expire, String scriptFile) {

super();

this.key = key;

this.limit = limit;

this.expire = expire;

try {

luaScript = Files.asCharSource(new ClassPathResource(scriptFile).getFile(), Charset.defaultCharset())

.read();

} catch (IOException e) {

e.printStackTrace();

}

}

/***

* 释放获取

* */

public boolean acquire() {

Jedis jedis = new Jedis("localhost", 6379);

return (Long) jedis.eval(luaScript, 1, key, limit, expire) == 1L;

}

}

--令牌秒杀 Lua脚本 tokenTimeLimiter.lua

local key = KEYS[1] --限流KEY(一秒一个)

local limit = tonumber(ARGV[1]) --限流大小

local exprie = ARGV[2] --过期时间

-- 获取当前计数值

local current = tonumber(redis.call('get', key) or "0")

if current + 1 > limit then --如果超出限流大小

return 0

else

current = tonumber(redis.call("INCRBY", key, "1")) --请求数+1

if current == 1 then --第一次访问需要设置过期时间

redis.call("expire", key,exprie) --设置过期时间

end

end

return 1 --返回1代表不限流

Controller层

//模拟秒杀场景

JedisLuaTokenTimeLimiter jtwlm = new JedisLuaTokenTimeLimiter("商品A", "5", "1", "tokenTimeLimiter.lua");

public String doQuery(String name) throws Exception {

// 从redis 上获得 自增后的值

if (!jtwlm.acquire()) {

return System.currentTimeMillis() / 1000 + "秒杀结束,谢谢参与!";

}

return System.currentTimeMillis() / 1000 + "恭喜,秒杀成功!";

}

测试代码

//模拟场景并发

@Test

public void tokenTimeLimiter() throws Exception {

CountDownLatch cdl = new CountDownLatch(10);

CyclicBarrier cyb = new CyclicBarrier(10);

for (int i = 0; i < 10; i++) {

new Thread(() -> {

try {

cyb.await();

} catch (InterruptedException | BrokenBarrierException e) {

e.printStackTrace();

}

try {

System.out.println(Thread.currentThread().getName() + " " + orderc.doQuery("商品A"));

} catch (Exception e) {

e.printStackTrace();

}

cdl.countDown();

}).start();

}

try {

cdl.await();

} catch (InterruptedException e) {

e.printStackTrace();

}

TimeUnit.SECONDS.sleep(1);

System.out.println(Thread.currentThread().getName() + " " + orderc.doQuery("商品A"));

}

结果:

f8a9f780bca3459904794d47204aa70f.png

注:本人只是简单的模拟了分布式环境并发的场景,其细节还有很多就没有过多给出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值