redis的搭建及应用(七)-redis的限流插件redis-cell

2024-01-03 01:56:00

Redis限流插件-redis-cell

redis-cell 是一个用rust语言编写的基于令牌桶算法的的限流模块,提供原子性的限流功能,并允许突发流量,可以很方便的应用于分布式环境中。

image-20231126175846605

下载redis-cell插件

访问Releases · brandur/redis-cell (github.com)

image-20231126171102106

上传redis-cell插件到linux服务器

image-20231126171232661

解压插件

[root@localhost plugin]# tar -zxvf redis-cell-v0.3.1-x86_64-unknown-linux-gnu.tar.gz 
libredis_cell.d
libredis_cell.so

拷贝libredis_cell.so到redis容器中

docker cp libredis_cell.so redis_6390:/usr/local/etc/redis

修改后redis.conf文件

在redis.conf配置文件中引用插件

38 ################################## MODULES #####################################
39 
40 # Load modules at startup. If the server is not able to load modules
41 # it will abort. It is possible to use multiple loadmodule directives.
42 #
43 # loadmodule /path/to/my_module.so
44 loadmodule /usr/local/etc/redis/libredis_cell.so
image-20231126171836524

插件使用

查询插件是否已启用

输入命令: module list

127.0.0.1:6379> module list
1) 1) "name"
   2) "redis-cell"
   3) "ver"
   4) (integer) 1
image-20231126173521851
语法
image-20231126173228028
127.0.0.1:6379> cl.throttle mytest 99 5 100 2
1) (integer) 0                        #0 表示成功, 1表示失败
2) (integer) 100                      # 令牌桶的容量
3) (integer) 98                       # 当前令牌桶的令牌数
4) (integer) -1                       # 成功时该值为-1,失败时表还需要等待多少秒可以有足够的令牌
5) (integer) 41                       # 预计多少秒后令牌桶会满
测试

多次从令牌桶取出数据

127.0.0.1:6379> cl.throttle mytest 99 5 100 40
1) (integer) 0
2) (integer) 100
3) (integer) 54
4) (integer) -1
5) (integer) 911
127.0.0.1:6379> cl.throttle mytest 99 5 100 40
1) (integer) 0
2) (integer) 100
3) (integer) 14
4) (integer) -1
5) (integer) 1708
127.0.0.1:6379> cl.throttle mytest 99 5 100 40
1) (integer) 1                      #失败,拒绝取出
2) (integer) 100
3) (integer) 14
4) (integer) 505                  # 取出失败,令牌桶还有14个令牌,还需505秒才能够取出
5) (integer) 1705

springboot使用令牌

引入redis
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
yml配置
server:
  port: 10022
spring:
  redis:
    host: 192.168.198.128
    port: 6390
redis配置
package com.wnhz.redis.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());

        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());

        return redisTemplate;
    }
}
测试
    @PostMapping("/redisCell")
    public String redisCell() {
        String script = "return redis.call('cl.throttle',KEYS[1],ARGV[1],ARGV[2],ARGV[3],ARGV[4])";
        DefaultRedisScript<List<Long>> defaultRedisScript = new DefaultRedisScript<>();
        int maxBurst = 99;
        int countPerPeriod = 10;
        int period = 100;
        int quantity = 10;

        List<Long> retVal = redisTemplate
                .execute(
                        new DefaultRedisScript<>(script, List.class),
                        new ArrayList<String>() {{
                            add("cell_key");
                        }},
                        maxBurst,
                        countPerPeriod,
                        period,
                        quantity);

        System.out.println(retVal);


        if (1 == retVal.get(0)) {  //第一个返回为1,表示拒绝
            return "频繁访问服务器过载,请过一会再来";
        }

        return "SUCCESS";
    }

image-20231126182938870

运行结果 [0, 100, 90, -1, 101]

redis-cell封装

/**
 * @param key            redis key
 * @param maxBurst       令牌桶最大容量
 * @param countPerPeriod 通过的令牌桶数(countPerPeriod/period 速率)
 * @param period         时间
 * @param quantity       取出数量
 * @return List  返回集合中5个Long值
 *  第0个位置:  0 表示成功, 1表示失败
 *  第1个位置:  令牌桶的容量
 *  第2个位置:  当前令牌桶的令牌数
 *  第3个位置:  成功时该值为-1,失败时表还需要等待多少秒可以有足够的令牌
 *  第4个位置:  预计多少秒后令牌桶会满
 */
public List<Long> redisCell(String key,
                            String maxBurst,
                            String countPerPeriod,
                            String period,
                            String quantity) {
    final String script = "return redis.call('cl.throttle',KEYS[1],ARGV[1],ARGV[2],ARGV[3],ARGV[4])";
    connect();
    List<Long> eval = this.connection.sync()
            .eval(script, ScriptOutputType.MULTI,
                    new String[]{key},
                    maxBurst,
                    countPerPeriod,
                    period,
                    quantity);
    returnPool();
    return eval;
}

文章来源:https://blog.csdn.net/qq_36115196/article/details/135343453
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。