redis限流案例

1.简单限流

1.实现原理:通过zset实现!
2.pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>distribute-lock</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!--json依赖-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.3</version>
        </dependency>
        <!--jedis依赖-->
        <dependency>
               <groupId>redis.clients</groupId>
               <artifactId>jedis</artifactId>
               <version>3.2.0</version>
               <type>jar</type>
               <scope>compile</scope>
        </dependency>
        <!--bloom依赖-->
        <dependency>
               <groupId>com.redislabs</groupId>
               <artifactId>jrebloom</artifactId>
               <version>1.2.0</version>
        </dependency>
    </dependencies>

</project>

3.JedisUtils

package com.yl;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

public class JedisUtils {
    private static JedisPool jedisPool = null;

    public static Jedis getJedisObject() {
        if (jedisPool == null) {
            GenericObjectPoolConfig config = new GenericObjectPoolConfig();
            //最大空闲数
            config.setMaxIdle(400);
            //最大连接数
            config.setMaxTotal(2000);
            //连接最大等待时间,-1代表没有限制
            config.setMaxWaitMillis(300000);
            /**
             * 配置连接池的地址,端口号,超时时间,密码
             */
            jedisPool = new JedisPool(config,"192.168.244.129",6379,30000,"root123");
        }
        try {
            //通过连接池获取jedis对象
            Jedis jedis = jedisPool.getResource();
            jedis.auth("root123");
            return jedis;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

4.实现限流

package com.yl;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;

/**
 * 限流
 */
public class CurrentLimiting {
    private Jedis jedis;

    public CurrentLimiting(Jedis jedis) {
        this.jedis = jedis;
    }

    /**
     *
     * @param user 限流对象
     * @param action 具体操作
     * @param period 周期
     * @param maxCount 限流次数
     * @return 返回true代表可以操作,还没限流,返回false代表限流,不可以操作
     */
    public boolean isPermit(String user,String action,int period,int maxCount) {
        //用zset来实现
        //生成一个key
        String key = user + "->" + action;
        long timeMillis = System.currentTimeMillis();
        //建立管道
        Pipeline pipeline = jedis.pipelined();
        pipeline.multi();
        //将当前操作保存下来
        pipeline.zadd(key,timeMillis,String.valueOf(timeMillis));
        //移除时间窗之外的数据
        pipeline.zremrangeByScore(key,0,timeMillis - period * 1000);
        //统计剩下的key
        Response<Long> zcard = pipeline.zcard(key);
        //给key设置过期时间
        pipeline.expire(key,period + 1);

        //关闭管道
        pipeline.exec();
        pipeline.close();
        return zcard.get() <= maxCount;
    }
}

5.测试

package com.yl;

import redis.clients.jedis.Jedis;

public class LimitTest {
    public static void main(String[] args) {
        Jedis jedis = JedisUtils.getJedisObject();
        CurrentLimiting limiting = new CurrentLimiting(jedis);
        for (int i = 0; i < 20; i++) {
            System.out.println(limiting.isPermit("yl", "editUser", 5, 3));
        }

    }
}

2.通过Redis-Cell实现限流

  1. Redis-Cell模块也可以解决限流问题,其内部用到的算法为漏斗算法,请求从漏斗的大口进,从小口出,再进入到系统!

  2. 下载并且安装Redis-Cell模块

mkdir redis-cell
cd redis-cell/
wget https://github.com/brandur/redis-cell/releases/download/v0.2.5/redis-cell-v0.2.5-x86_64-unknown-linux-gnu.tar.gz
tar zxvf redis-cell-v0.2.5-x86_64-unknown-linux-gnu.tar.gz

  1. 在redis.conf中加载Redis-Cell模块

在这里插入图片描述

4.重启redis后,如果发现连接不上redis
在这里插入图片描述

可参考这篇文章解决:链接: https://blog.csdn.net/hxxx1314/article/details/115109098.

  1. 重启redis,连接到redis,发现CL.THROTTLE命令可用就代表redis-cell安装且配置成功!
    在这里插入图片描述

5.CL.THROTTLE命令参数介绍
第一个是key
第二个是漏斗的容量
第三个是时间窗内可以操作的次数
第四个是时间窗
第五个是每次漏出数量

命令执行成功也返回五个值
第一个,返回0代表允许,返回1代表拒绝
第二个,漏斗的容量(返回的值-1才是容量值)
第三个,漏斗的剩余空间
第四个,如果拒绝了,多长时间后可以再试
第五个,多行时间后,漏斗会完全空出来

3.lettuce自定义命令实现限流

1.pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>lettuce</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <dependency>
               <groupId>io.lettuce</groupId>
               <artifactId>lettuce-core</artifactId>
               <version>5.2.2.RELEASE</version>
        </dependency>
    </dependencies>

</project>
  1. 自定义接口
package com.yl.config;

import io.lettuce.core.dynamic.Commands;
import io.lettuce.core.dynamic.annotation.Command;

import java.util.List;

public interface RedisCommandInterface extends Commands {

    /**
     *
     * @param key key
     * @param init 漏斗容量大小
     * @param count 时间窗内可以操作的次数
     * @param period 时间窗
     * @param quota 每次漏出数量
     * @return
     */
    @Command("CL.THROTTLE ?0 ?1 ?2 ?3 ?4")
    List<Object> throttle(String key, Long init, Long count, Long period, Long quota);
}
  1. 测试
package com.yl.config;

import io.lettuce.core.RedisClient;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.dynamic.RedisCommandFactory;

import java.util.List;

public class ThrottleTest {
    public static void main(String[] args) {
        //创建client对象
        RedisClient redisClient = RedisClient.create("redis://root123@192.168.244.129");
        //获取连接对象
        StatefulRedisConnection<String, String> connect = redisClient.connect();
        RedisCommandFactory redisCommandFactory = new RedisCommandFactory(connect);
        RedisCommandInterface commands = redisCommandFactory.getCommands(RedisCommandInterface.class);
        List<Object> list = commands.throttle("yl-update", 10L, 10L, 60L, 1L);
        System.out.println(list);
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值