本文目录导读:

我来为您提供一个完整的Spring Cloud Gateway限流案例,涵盖多种限流策略。
项目依赖配置
Maven依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- Redis实现令牌桶限流 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<!-- 限流算法支持 -->
<dependency>
<groupId>com.github.vladimir-bukhtoyarov</groupId>
<artifactId>bucket4j-core</artifactId>
<version>7.6.0</version>
</dependency>
<dependency>
<groupId>com.github.vladimir-bukhtoyarov</groupId>
<artifactId>bucket4j-redis</artifactId>
<version>7.6.0</version>
</dependency>
基础配置文件
application.yml
spring:
application:
name: gateway-service
redis:
host: localhost
port: 6379
database: 0
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/user/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
redis-rate-limiter.requestedTokens: 1
key-resolver: "#{@userKeyResolver}"
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/order/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 5
redis-rate-limiter.burstCapacity: 10
redis-rate-limiter.requestedTokens: 1
key-resolver: "#{@ipKeyResolver}"
限流Key解析器配置
KeyResolver配置类
@Configuration
public class RateLimiterConfig {
/**
* 基于用户ID的限流
*/
@Bean
public KeyResolver userKeyResolver() {
return exchange -> {
// 从需要中获取用户信息
String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");
if (userId == null || userId.isEmpty()) {
// 默认使用IP作为标识
userId = getClientIp(exchange);
}
return Mono.just(userId);
};
}
/**
* 基于IP地址的限流
*/
@Bean
public KeyResolver ipKeyResolver() {
return exchange -> Mono.just(getClientIp(exchange));
}
/**
* 基于API Key的限流
*/
@Bean
public KeyResolver apiKeyResolver() {
return exchange -> {
String apiKey = exchange.getRequest().getHeaders().getFirst("X-API-Key");
if (apiKey == null || apiKey.isEmpty()) {
return Mono.just("unknown_api_key");
}
return Mono.just(apiKey);
};
}
private String getClientIp(ServerWebExchange exchange) {
String ip = exchange.getRequest().getHeaders().getFirst("X-Forwarded-For");
if (ip == null || ip.isEmpty()) {
ip = exchange.getRequest().getRemoteAddress() != null ?
exchange.getRequest().getRemoteAddress().getAddress().getHostAddress() : "unknown";
} else {
ip = ip.split(",")[0].trim();
}
return ip;
}
}
自定义限流过滤器
自定义限流实现
@Component
public class CustomRateLimiterFilter implements GlobalFilter, Ordered {
private final ReactiveStringRedisTemplate redisTemplate;
private final RateLimiterConfig rateLimiterConfig;
@Autowired
public CustomRateLimiterFilter(ReactiveStringRedisTemplate redisTemplate,
RateLimiterConfig rateLimiterConfig) {
this.redisTemplate = redisTemplate;
this.rateLimiterConfig = rateLimiterConfig;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 获取请求路径
String path = exchange.getRequest().getURI().getPath();
// 获取客户端IP
String clientIp = exchange.getRequest().getRemoteAddress() != null ?
exchange.getRequest().getRemoteAddress().getAddress().getHostAddress() : "unknown";
// 构建Redis key
String rateLimitKey = "rate_limit:" + clientIp + ":" + path;
// 实现简单的滑动窗口限流
return isAllowed(rateLimitKey)
.flatMap(allowed -> {
if (allowed) {
return chain.filter(exchange);
} else {
// 返回429状态码
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
return exchange.getResponse().writeWith(
Mono.just(exchange.getResponse().bufferFactory()
.wrap("{\"code\":429,\"message\":\"请求过于频繁\"}".getBytes()))
);
}
});
}
private Mono<Boolean> isAllowed(String key) {
return redisTemplate.opsForValue()
.increment(key)
.flatMap(count -> {
if (count == 1) {
// 设置过期时间,例如1分钟
return redisTemplate.expire(key, Duration.ofMinutes(1))
.map(expired -> true);
}
return Mono.just(count <= 100); // 每分钟最多100次请求
});
}
@Override
public int getOrder() {
return -100; // 高优先级执行
}
}
使用Bucket4j实现更复杂限流
Bucket4j配置类
@Configuration
public class Bucket4jConfig {
private final RedisTemplate<String, Object> redisTemplate;
@Autowired
public Bucket4jConfig(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 创建基于IP的限流桶
*/
@Bean
public Bucket createIpBucket() {
// 创建Bucket4j配置
Bandwidth limit = Bandwidth.classic(10, Refill.greedy(10, Duration.ofMinutes(1)));
// 使用Redis存储桶状态
ProxyManager<String> buckets = Bucket4j.extension(Redis.class)
.proxyManagerForMap(redisTemplate.opsForValue().getOperations().getConnectionFactory());
return Bucket.builder()
.addLimit(limit)
.build();
}
/**
* 获取或创建Bucket
*/
public Bucket getOrCreateBucket(String key) {
ProxyManager<String> buckets = Bucket4j.extension(Redis.class)
.proxyManagerForMap(redisTemplate.opsForValue().getOperations().getConnectionFactory());
Function<String, Bucket> bucketConfiguration = k -> Bucket.builder()
.addLimit(Bandwidth.classic(10, Refill.greedy(10, Duration.ofMinutes(1))))
.build();
return buckets.getProxy(key, bucketConfiguration);
}
}
使用Bucket4j的过滤器
@Component
public class Bucket4jRateLimiterFilter implements GatewayFilter {
private final Bucket4jConfig bucket4jConfig;
@Autowired
public Bucket4jRateLimiterFilter(Bucket4jConfig bucket4jConfig) {
this.bucket4jConfig = bucket4jConfig;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 获取客户端IP作为key
String clientIp = exchange.getRequest().getRemoteAddress() != null ?
exchange.getRequest().getRemoteAddress().getAddress().getHostAddress() : "unknown";
// 获取或创建Bucket
Bucket bucket = bucket4jConfig.getOrCreateBucket(clientIp);
// 尝试获取令牌
ConsumptionProbe probe = bucket.tryConsumeAndReturnRemaining(1);
if (probe.isConsumed()) {
// 添加剩余令牌数到响应头
exchange.getResponse().getHeaders().add("X-Rate-Limit-Remaining",
String.valueOf(probe.getRemainingTokens()));
return chain.filter(exchange);
} else {
// 计算重试时间
long waitForRefill = probe.getNanosToWaitForRefill() / 1_000_000_000;
exchange.getResponse().getHeaders().add("X-Rate-Limit-Retry-After-Seconds",
String.valueOf(waitForRefill));
// 返回429状态码
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return exchange.getResponse().setComplete();
}
}
}
动态限流配置
限流规则管理类
@Service
public class RateLimitRuleService {
private final RedisTemplate<String, Object> redisTemplate;
private final Map<String, RateLimitRule> ruleCache = new ConcurrentHashMap<>();
@Autowired
public RateLimitRuleService(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
loadInitialRules();
}
/**
* 更新限流规则
*/
public void updateRule(String key, RateLimitRule rule) {
redisTemplate.opsForValue().set("rate_rule:" + key, rule);
ruleCache.put(key, rule);
}
/**
* 获取规则
*/
public RateLimitRule getRule(String key) {
// 先从缓存获取
RateLimitRule rule = ruleCache.get(key);
if (rule == null) {
// 从Redis获取
rule = (RateLimitRule) redisTemplate.opsForValue().get("rate_rule:" + key);
if (rule != null) {
ruleCache.put(key, rule);
}
}
return rule;
}
/**
* 动态过滤器
*/
public Mono<Void> applyDynamicRateLimit(ServerWebExchange exchange, GatewayFilterChain chain) {
String clientIp = exchange.getRequest().getRemoteAddress() != null ?
exchange.getRequest().getRemoteAddress().getAddress().getHostAddress() : "unknown";
RateLimitRule rule = getRule(clientIp);
if (rule == null) {
// 使用默认规则
rule = new RateLimitRule(10, 1, 60); // 每秒10个请求,突发1个,窗口1分钟
}
// 应用动态规则
return isAllowedWithRule(clientIp, rule)
.flatMap(allowed -> {
if (allowed) {
return chain.filter(exchange);
} else {
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return exchange.getResponse().setComplete();
}
});
}
private Mono<Boolean> isAllowedWithRule(String key, RateLimitRule rule) {
// 使用Lua脚本实现原子性操作
String script = """
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local current = redis.call('INCR', key)
if current == 1 then
redis.call('EXPIRE', key, window)
end
return current <= limit
""";
return redisTemplate.execute(
new DefaultRedisScript<>(script, Boolean.class),
Arrays.asList("rate:" + key),
String.valueOf(rule.getLimit()),
String.valueOf(rule.getWindowSeconds())
);
}
}
全局限流配置
全局过滤器配置
@Configuration
public class GatewayFilterConfig {
@Bean
public GlobalFilter customGlobalFilter() {
return (exchange, chain) -> {
// 检查是否是API请求
if (exchange.getRequest().getURI().getPath().startsWith("/api/")) {
// 添加自定义头
exchange.getRequest().mutate()
.header("X-Gateway-Request-Time", String.valueOf(System.currentTimeMillis()))
.build();
}
return chain.filter(exchange);
};
}
@Bean
public GlobalFilter rateLimitGlobalFilter(RateLimitRuleService rateLimitRuleService) {
return (exchange, chain) -> rateLimitRuleService
.applyDynamicRateLimit(exchange, chain);
}
}
高级配置示例
多级限流配置
spring:
cloud:
gateway:
routes:
- id: api-routes
uri: lb://api-service
predicates:
- Path=/api/**
filters:
# 第一级:限速
- RequestRateLimiter=5, 10
# 第二级:限流
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 5
redis-rate-limiter.burstCapacity: 10
key-resolver: "#{@userKeyResolver}"
自定义错误处理
@Configuration
public class RateLimitErrorHandler {
@Bean
public ErrorWebExceptionHandler rateLimitExceptionHandler() {
return (exchange, ex) -> {
if (ex instanceof RateLimitExceededException) {
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
String errorMessage = """
{
"code": 429,
"message": "请求过于频繁,请稍后再试",
"retryAfter": 60,
"timestamp": "%s"
}
""".formatted(LocalDateTime.now());
return exchange.getResponse().writeWith(
Mono.just(exchange.getResponse().bufferFactory().wrap(errorMessage.getBytes()))
);
}
return Mono.error(ex);
};
}
}
监控和指标
监控配置
@Component
public class RateLimitMetrics {
private final MeterRegistry meterRegistry;
@Autowired
public RateLimitMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
public void recordRateLimit(String key, boolean allowed) {
meterRegistry.counter("gateway.rate.limit.requests",
"key", key,
"result", allowed ? "allowed" : "blocked"
).increment();
}
public void recordLatency(String key, long latency) {
meterRegistry.timer("gateway.rate.limit.latency",
"key", key
).record(Duration.ofMillis(latency));
}
}
完整示例:统一限流管理
限流管理器
@Service
public class UnifiedRateLimiter {
@Autowired
private ReactiveStringRedisTemplate redisTemplate;
/**
* 统一的限流入口
*/
public Mono<RateLimitResult> checkRateLimit(String key, RateLimitType type) {
return switch (type) {
case IP -> checkIpRateLimit(key);
case USER -> checkUserRateLimit(key);
case API -> checkApiRateLimit(key);
case CUSTOM -> checkCustomRateLimit(key);
};
}
private Mono<RateLimitResult> checkIpRateLimit(String ip) {
// IP限流:每秒10次,突发20次
return checkLimit("ip:" + ip, 10, 20, 1);
}
private Mono<RateLimitResult> checkUserRateLimit(String userId) {
// 用户限流:每分钟100次
return checkLimit("user:" + userId, 100, 200, 60);
}
private Mono<RateLimitResult> checkApiRateLimit(String apiKey) {
// API限流:每小时1000次
return checkLimit("api:" + apiKey, 1000, 2000, 3600);
}
private Mono<RateLimitResult> checkCustomRateLimit(String key) {
// 自定义限流
return checkLimit("custom:" + key, 50, 100, 60);
}
private Mono<RateLimitResult> checkLimit(String key, int limit, int burst, int windowSeconds) {
String script = """
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local burst = tonumber(ARGV[2])
local window = tonumber(ARGV[3])
local current = redis.call('INCR', key)
if current == 1 then
redis.call('EXPIRE', key, window)
end
local maxAllowed = (current <= burst) and limit or (limit + (burst - limit) * (window - redis.call('TTL', key)) / window)
if current <= maxAllowed then
return {1, current}
else
return {0, current}
end
""";
return redisTemplate.execute(
new DefaultRedisScript<>(script, List.class),
Arrays.asList(key),
String.valueOf(limit),
String.valueOf(burst),
String.valueOf(windowSeconds)
).map(result -> {
List<Long> values = (List<Long>) result;
return new RateLimitResult(values.get(0) == 1,
values.get(1),
limit,
windowSeconds);
});
}
public record RateLimitResult(boolean allowed, long currentCount, long limit, int windowSeconds) {}
}
// 限流类型枚举
public enum RateLimitType {
IP, USER, API, CUSTOM
}
使用示例
在业务逻辑中使用
@RestController
@RequestMapping("/api")
public class TestController {
@Autowired
private UnifiedRateLimiter rateLimiter;
@GetMapping("/test")
public Mono<ResponseEntity<?>> test() {
return rateLimiter.checkRateLimit("test-key", RateLimitType.CUSTOM)
.flatMap(result -> {
if (result.allowed()) {
return Mono.just(ResponseEntity.ok("请求成功"));
} else {
return Mono.just(
ResponseEntity.status(429)
.header("X-RateLimit-Remaining",
String.valueOf(result.limit() - result.currentCount()))
.body("请求过于频繁")
);
}
});
}
}
这个完整的案例提供了多种限流方案,您可以根据实际需求选择合适的实现方式,主要特性包括:
- 基于Redis的令牌桶限流
- 基于IP、用户、API Key的多维度限流
- 动态规则配置
- 全局和局部限流结合
- 监控和指标收集
- 灵活的错误处理机制
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播