key-prefix标记方法进行分布式限流控制

97 阅读2分钟

如何使用key-prefix标记方法进行分布式限流控制。

本案例使用Spring Boot框架和 Redis客户端库,可以直接运行并测试接口限流功能。

  1. 创建一个RateLimitInterceptor拦截器类,在该类中实现接口限流逻辑。
import io.lettuce.core.RedisClient;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;

public class RateLimitInterceptor implements HandlerInterceptor {

    private final RedisClient redisClient;
    private final String apiPrefix;
    private final int rateLimit;

    public RateLimitInterceptor(RedisClient redisClient, String apiPrefix, int rateLimit) {
        this.redisClient = redisClient;
        this.apiPrefix = apiPrefix;
        this.rateLimit = rateLimit;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String key = apiPrefix + ":" + request.getRemoteAddr(); // 构造唯一键值
        StatefulRedisConnection<String, String> connection = redisClient.connect(); // 获取Redis连接
        RedisCommands<String, String> syncCommands = connection.sync(); // 获取Redis命令对象
        long count = syncCommands.incr(key); // 计数器加1,并获取当前值
        syncCommands.expire(key, 1, TimeUnit.SECONDS); // 设置计数器过期时间为1秒
        if (count > rateLimit) { // 如果超出限制则返回错误码
            response.setStatus(HttpServletResponse.SC_TOO_MANY_REQUESTS);
            return false;
        }
        return true;
    }

}
  1. 在Spring Boot的配置文件中添加Redis连接配置信息。
spring:
  redis:
    host: localhost
    port: 6379
  1. 在启动类中创建RedisClient对象,并注册RateLimitInterceptor拦截器。
import io.lettuce.core.RedisClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@SpringBootApplication
public class MyApp implements WebMvcConfigurer {

    @Value("${app.api.prefix}")
    private String apiPrefix;

    @Value("${app.rate.limit}")
    private int rateLimit;

    @Bean
    public RedisClient redisClient() {
        return RedisClient.create("redis://localhost:6379");
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new RateLimitInterceptor(redisClient(), apiPrefix, rateLimit));
    }

    public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
    }

}
  1. 在Controller中添加一个测试接口。
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {

    @GetMapping("/api/test")
    public String test() {
        return "Hello, world!";
    }

}
  1. 运行并测试接口限流功能。在浏览器中访问测试接口,如果请求次数超过限制,服务器将返回429错误码。

注意:为了保证测试稳定性,建议将限流阈值设置得较低。真实环境下应根据具体情况进行调整,避免过于严格的限流导致正常请求无法访问。

限流阈值(Rate Limit)是指在一段时间内允许通过的最大请求数量。通常用于控制系统的接口访问流量,防止系统被恶意攻击或过度使用而导致负载过高