使用redis-cell模块实现令牌桶限流

110 篇文章 2 订阅
26 篇文章 1 订阅

先安装redis,可以参考我另一篇博文
https://blog.csdn.net/weixin_43944305/article/details/120661885

安装redis-cell

https://github.com/brandur/redis-cell/releases/

我用的ubuntu系统
在这里插入图片描述

下载后解压,然后将libredis_cell.so文件的路径配置到redis的配置文件redis.conf中,然后启动并登陆redis,用MODULE LIST命令查看module是否加载成功

loadmodule /home/ubuntu/download/redisCell/libredis_cell.so

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

命令行测试令牌桶功能

cl.throttle liziba 10 5 60 1
CL.THROTTLE liziba  10  5 60 1
               ▲     ▲  ▲  ▲ ▲
               |     |  |  | └───── apply 1 token (default if omitted) (本次申请一个token)
               |     |  └──┴─────── 5 tokens / 60 seconds  (60秒添加5个token到令牌桶中)
               |     └───────────── 10 max_burst    (最大的突发请求,不是令牌桶的最大容量)
               └─────────────────── key "liziba" (限流key)

命令的响应结果

127.0.0.1:6379> cl.throttle liziba 10 5 60 1
1) (integer) 0       # 当前请求是否被允许,0表示允许,1表示不允许
2) (integer) 11      # 令牌桶的最大容量,令牌桶中令牌数的最大值
3) (integer) 10      # 令牌桶中当前的令牌数
4) (integer) -1      # 如果被拒绝,需要多长时间后在重试,如果当前被允许则为-1
5) (integer) 12      # 多长时间后令牌桶中的令牌会满

java使用RedisTemplate测试令牌桶

引入连接redis依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

这里要注意如果使用自带的RedisTemplate的话执行脚本后redis服务端会莫名挂掉,这是因为自带的RedisTemplate使用了JDK的序列化策略,导致redis服务端收不到命令,所以要修改并使用string序列化策略

@Bean
public RedisTemplate<String,Object> myRedisTemplate(RedisConnectionFactory connectionFactory){

    RedisTemplate<String, Object> template = new RedisTemplate<>();
    template.setConnectionFactory(connectionFactory);

    ObjectMapper objectMapper = new ObjectMapper();
    // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
    objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
    objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
    //兼容java8的时间api
    objectMapper.registerModule(new JavaTimeModule());
    objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    GenericJackson2JsonRedisSerializer jacksonSerializer = new GenericJackson2JsonRedisSerializer(objectMapper);

    // 值采用json序列化
    template.setValueSerializer(jacksonSerializer);
    //使用StringRedisSerializer来序列化和反序列化redis的key值
    template.setKeySerializer(new StringRedisSerializer());

    // 设置hash key 和value序列化模式
    template.setHashKeySerializer(new StringRedisSerializer());
    template.setHashValueSerializer(jacksonSerializer);
    template.afterPropertiesSet();
    return template;
}




 /**
   * 请求是否被允许
   * @param key       限流的key
   * @param maxBurst  最大请求
   * @param tokens    令牌数量   每过seconds时间就往桶里放入tokens的令牌数量
   * @param seconds   时间      每过seconds时间就往桶里放入tokens的令牌数量
   * @param apply     本次获取几个令牌
   * @return
   */
  public boolean isActionAllowed(String key, int maxBurst, int tokens, int seconds, int apply){

      DefaultRedisScript<List> script = new DefaultRedisScript<>("return redis.call('cl.throttle',KEYS[1],ARGV[1],ARGV[2],ARGV[3],ARGV[4])", List.class);

      List<Long> rst = myRedisTemplate.execute(script, Arrays.asList(key), maxBurst, tokens, seconds, apply);
      //响应结果
      /**
       * 1) (integer) 0       # 当前请求是否被允许,0表示允许,1表示不允许
       * 2) (integer) 11      # 令牌桶的最大容量,令牌桶中令牌数的最大值
       * 3) (integer) 10      # 令牌桶中当前的令牌数
       * 4) (integer) -1      # 如果被拒绝,需要多长时间后在重试,如果当前被允许则为-1
       * 5) (integer) 12      # 多长时间后令牌桶中的令牌会满
       */
      return rst.get(0) == 0;
  }
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值