基于Redis的全局限流方案示例

530 阅读1分钟

首先,在使用Redis进行全局限流前,需要安装并启动Redis服务,并在Spring Boot项目中引入Redis依赖:

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

**

然后,我们在项目中添加一个工具类RedisRateLimiter,用来实现基于Redis的全局限流:

import org.springframework.data.redis.core.RedisTemplate;
import java.util.concurrent.TimeUnit;

public class RedisRateLimiter {

    private RedisTemplate<String, String> redisTemplate;

    public RedisRateLimiter(RedisTemplate<String, String> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 检查是否超出限制
     * @param key 限流的key
     * @param maxCount 限制次数
     * @param expireSeconds 时间段
     * @return 是否超限
     */
    public boolean checkRate(String key, int maxCount, int expireSeconds) {
        String redisKey = key + System.currentTimeMillis() / (expireSeconds * 1000);
        Long count = redisTemplate.opsForValue().increment(redisKey, 1);
        if (count == 1) {
            redisTemplate.expire(redisKey, expireSeconds, TimeUnit.SECONDS);
        }
        return count > maxCount;
    }
}

**

这个类中,我们通过Redis的Increment方法实现接口的调用计数,每次使用一个特定的key,来判断当前时间段内是否超出限制。如果累计调用次数超过了限制,就返回 true,否则返回 false。

下面是一个基于RedisRateLimiter的Controller示例代码:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;

@RestController
public class DemoController {
    
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @GetMapping("/demo")
    public String demo() {
        RedisRateLimiter rateLimiter = new RedisRateLimiter(redisTemplate);
        if (rateLimiter.checkRate("my_key", 100, 60)) {
            return "请求太过频繁,请稍后再试!";
        } else {
            //业务逻辑代码
            return "请求正常!";
        }
    }
}

**

在Controller中,我们通过RedisRateLimiter判断每个请求是否超出限制,如果超出,就返回错误提示;如果没有超出,就执行正常的业务逻辑代码。

需要注意的是,RedisRateLimiter适用于单个应用程序进程的全局限流,如果要进行分布式限流,可以使用key-prefix标记方法调用请求,并将限流的数据放入Redis Cluster或者Redis Sentinel集群中。当然,具体实现方式需要根据实际情况进行调整。