本文共 4170 字,大约阅读时间需要 13 分钟。
漏桶算法
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 JedisGetRateLimiter { private static final String IP = "192.168.0.163"; private String luaScript; private String key; public JedisGetRateLimiter(String scriptFile, String key) { super(); this.key = key; try { luaScript = Files.asCharSource(new ClassPathResource(scriptFile).getFile(), Charset.defaultCharset()) .read(); } catch (IOException e) { e.printStackTrace(); } } public boolean acquire() { try (Jedis jedis = new Jedis(IP, 6379)) { return (Long) jedis.eval(luaScript, 1, key) == 1L; } }}import java.io.IOException;import java.nio.charset.Charset;import java.util.Timer;import java.util.TimerTask;import java.util.concurrent.TimeUnit;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 JedisInitRateLimiter implements AutoCloseable { private static final String IP = "192.168.0.163"; private String luaScript; private Timer timer; private final Jedis jedis = new Jedis(IP, 6379); public JedisInitRateLimiter(String scriptFile, String key, String limit) { super(); try { luaScript = Files.asCharSource(new ClassPathResource(scriptFile).getFile(), Charset.defaultCharset()) .read(); } catch (IOException e) { e.printStackTrace(); } timer = new Timer(); // 放入令牌的时间间隔 long period = 1000L / Long.valueOf(limit); // 通过定时器,定时放入令牌 timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { System.out.println( System.currentTimeMillis() + " 放入令牌:" + ((Long) jedis.eval(luaScript, 1, key, limit) == 1L)); } }, period, period); } @Override public void close() throws Exception { this.jedis.close(); this.timer.cancel(); } public static void main(String[] args) throws Exception { JedisInitRateLimiter jrls = new JedisInitRateLimiter("initRateLimit.lua", "test1", "5"); TimeUnit.SECONDS.sleep(10L); jrls.close(); }}
Lua脚本
--令牌桶初始化操作 initRateLimit.lualocal key = KEYS[1] --限流KEYlocal limit = tonumber(ARGV[1]) --容量-- 获取当前令牌数local current = tonumber(redis.call('get', key) or "0")if current + 1 > limit then --如果超出容量 return 0else redis.call("INCRBY", key, "1") --令牌数+1endreturn 1 --返回1代表不限流--取令牌 getRateLimit.lualocal key = KEYS[1] --限流KEY-- 获取当前可用令牌数local current = tonumber(redis.call('get', key) or "0")if current <= 0 then --没有令牌了 return 0else redis.call("DECRBY", key, "1") --令牌数-1endreturn 1 --返回1代表不限流
测试类
//Controller层测试类 //初始化给入的容器数量 JedisInitRateLimiter initRateLimiter = new JedisInitRateLimiter("initRateLimit.lua","test","5"); JedisGetRateLimiter jtwl = new JedisGetRateLimiter("getRateLimit.lua","test"); public String doQuery2(String name) throws Exception { // 从redis 上获得 自增后的值 if (!jtwl.acquire()) { return System.currentTimeMillis() / 1000 + "秒杀结束,谢谢参与!"; } return System.currentTimeMillis() / 1000 + "恭喜,秒杀成功!"; }//漏桶算法 @Test public void smoothRequestTest() 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.doQuery2("test")); } 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.doQuery2("Mike")); }
测试结果:
转载地址:http://iujdi.baihongyu.com/