Java 中的调用逻辑:
- --lua 下标从 1 开始
- -- 限流 key
- local key = KEYS[1]
- -- 限流大小
- local limit = tonumber(ARGV[1])
- -- 获取当前流量大小
- local curentLimit = tonumber(redis.call('get', key) or "0")
- if curentLimit + 1 > limit then
- -- 达到限流大小 返回
- return 0;
- else
- -- 没有达到阈值 value + 1
- redis.call("INCRBY", key, 1)
- redis.call("EXPIRE", key, 2)
- return curentLimit + 1
- end
所以只需要在需要限流的地方调用该方法对返回值进行判断即可达到限流的目的。
当然这只是利用 Redis 做了一个粗暴的计数器,如果想实现类似于上文中的令牌桶算法可以基于 Lua 自行实现。
Builder 构建器
在设计这个组件时想尽量的提供给使用者清晰、可读性、不易出错的 API。
比如第一步,如何构建一个限流对象。
最常用的方式自然就是构造函数,如果有多个域则可以采用重叠构造器的方式:
- public A(){}
- public A(int a){}
- public A(int a,int b){}
缺点也是显而易见的:如果参数过多会导致难以阅读,甚至如果参数类型一致的情况下客户端颠倒了顺序,但不会引起警告从而出现难以预测的结果。
第二种方案可以采用 JavaBean 模式,利用 setter 方法进行构建:
- A a = new A();
- a.setA(a);
- a.setB(b);
这种方式清晰易读,但却容易让对象处于不一致的状态,使对象处于线程不安全的状态。
所以这里采用了第三种创建对象的方式,构建器:
- public class RedisLimit {
- private JedisCommands jedis;
- private int limit = 200;
- private static final int FAIL_CODE = 0;
- /**
- * lua script
- */
- private String script;
- private RedisLimit(Builder builder) {
- this.limit = builder.limit ;
- this.jedis = builder.jedis ;
- buildScript();
- }
- /**
- * limit traffic
- * @return if true
- */
- public boolean limit() {
- String key = String.valueOf(System.currentTimeMillis() / 1000);
- Object result = null;
- if (jedis instanceof Jedis) {
- result = ((Jedis) this.jedis).eval(script, Collections.singletonList(key), Collections.singletonList(String.valueOf(limit)));
- } else if (jedis instanceof JedisCluster) {
- result = ((JedisCluster) this.jedis).eval(script, Collections.singletonList(key), Collections.singletonList(String.valueOf(limit)));
- } else {
- //throw new RuntimeException("instance is error") ;
- return false;
- }
- if (FAIL_CODE != (Long) result) {
- return true;
- } else {
- return false;
- }
- }
- /**
- * read lua script
- */
- private void buildScript() {
- script = ScriptUtil.getScript("limit.lua");
- }
- /**
- * the builder
- * @param <T>
- */
- public static class Builder<T extends JedisCommands>{
- private T jedis = null ;
- private int limit = 200;
- public Builder(T jedis){
- this.jedis = jedis ;
- }
- public Builder limit(int limit){
- this.limit = limit ;
- return this;
- }
- public RedisLimit build(){
- return new RedisLimit(this) ;
- }
- }
- }
(编辑:晋中站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|