目录
1.引入依赖
依赖版本尝试了很多次,在网上参考了别人的版本依赖,最后终于没有冲突了
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
</parent>
<groupId>com.hhmt</groupId>
<artifactId>delivery-gateway</artifactId>
<version>1.0.0</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<lombok.version>1.18.24</lombok.version>
<spring-cloud.version>Hoxton.SR9</spring-cloud.version>
<spring-cloud-alibaba.version>2.2.6.RELEASE</spring-cloud-alibaba.version>
<spring-boot.version>2.3.2.RELEASE</spring-boot.version>
<spring-cloud-starter-gateway.version>3.0.4</spring-cloud-starter-gateway.version>
<alibaba-fastjson.version>2.0.20</alibaba-fastjson.version>
<bootstrap.version>3.0.4</bootstrap.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<!-- 启动 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--nacos配置中心-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>${bootstrap.version}</version>
</dependency>
<!-- <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>-->
<!--引入loadbalancer-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>3.1.1</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${alibaba-fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
如果需要限流,可以引入一下依赖
<!--基于Redis实现限流-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
<version>2.2.10.RELEASE</version>
</dependency>
2.添加配置
server:
port: 9432
spring:
cloud:
loadbalancer:
cache:
enabled: true
caffeine:
spec: initialCapacity=500,expireAfterWrite=5s
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
routes:
# 系统模块
- id: delivery-adx-local
uri: lb://delivery-adx-local
predicates:
- Path=/adx/version
filters:
# - StripPrefix=1
- name: RequestRateLimiter
args:
# 限流策略,对应策略的Bean
key-resolver: '#{@pathResolver}'
# 每秒允许处理的请求数量 # 令牌桶每秒填充平均速率
redis-rate-limiter.replenishRate: 10
# 每秒最大处理的请求数量# 令牌桶总容量
redis-rate-limiter.burstCapacity: 30
nacos:
discovery:
server-addr: 139.9.178.38:8848
namespace: 4e335d42-4caa-49b0-b209-0363e1a2071c
group: delivery
redis:
client-name: redis
#host: 139.9.178.38
# 华为云redis分布式缓存服务
host: 127.0.0.1
port: 6369
password: vRCh2zSW
timeout: 3000
jedis:
pool:
max-active: 8
max-wait: -1
max-idle: 8
min-idle: 0
management:
endpoints:
health:
show-details: always
web:
exposure:
include: '*'
3.限流响应信息
package com.hhmt.delivery.filter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.RequestRateLimiterGatewayFilterFactory;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.cloud.gateway.filter.ratelimit.RateLimiter;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
* @Author huachun
* @Email [email protected]
* @CreateTime 2024-02-20 18:27
* @Description 原文参考:https://blog.csdn.net/qq_42628989/article/details/123415786
*/
@Slf4j
@Component
public class GatewayRequestRateLimiterGatewayFilterFactory extends RequestRateLimiterGatewayFilterFactory {
private final RateLimiter defaultRateLimiter;
private final KeyResolver defaultKeyResolver;
public GatewayRequestRateLimiterGatewayFilterFactory(RateLimiter defaultRateLimiter, KeyResolver defaultKeyResolver) {
super(defaultRateLimiter, defaultKeyResolver);
this.defaultRateLimiter = defaultRateLimiter;
this.defaultKeyResolver = defaultKeyResolver;
}
@Override
public GatewayFilter apply(Config config) {
KeyResolver resolver = getOrDefault(config.getKeyResolver(), defaultKeyResolver);
RateLimiter<Object> limiter = getOrDefault(config.getRateLimiter(), defaultRateLimiter);
return (exchange, chain) -> resolver.resolve(exchange).flatMap(key -> {
// if (EMPTY_KEY.equals(key)) {
// if (denyEmpty) {
// setResponseStatus(exchange, emptyKeyStatus);
// return exchange.getResponse().setComplete();
// }
// return chain.filter(exchange);
// }
String routeId = config.getRouteId();
if (routeId == null) {
Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
routeId = route.getId();
}
String finalRouteId = routeId;
return limiter.isAllowed(routeId, key).flatMap(response -> {
for (Map.Entry<String, String> header : response.getHeaders().entrySet()) {
exchange.getResponse().getHeaders().add(header.getKey(), header.getValue());
}
if (response.isAllowed()) {
return chain.filter(exchange);
}
log.warn("已限流: {}", finalRouteId);
ServerHttpResponse httpResponse = exchange.getResponse();
httpResponse.setStatusCode(config.getStatusCode());
if (!httpResponse.getHeaders().containsKey("Content-Type")) {
httpResponse.getHeaders().add("Content-Type", "application/json");
}
DataBuffer buffer = httpResponse.bufferFactory().wrap("{\"msg\":\"访问已受限制,请稍候重试\"}".getBytes(StandardCharsets.UTF_8));
return httpResponse.writeWith(Mono.just(buffer));
// return exchange.getResponse().setComplete();
});
});
}
private <T> T getOrDefault(T configValue, T defaultValue) {
return (configValue != null) ? configValue : defaultValue;
}
}
原文参考:https://blog.csdn.net/qq_42628989/article/details/123415786
配置调整
基于redis限流还需要配置redis实例地址,否则限流不生效
4.启动类
启动类添加注解 @EnableDiscoveryClient
5.测试
使用jmeter编写测试类
查看sentinel,qps被限制在预期范围
6.遇见问题
1.使用lb://service-name不生效问题
找了很多资料,知道看到下面这个图才发现自己的问题,lb://调用的服务需要在同一个分组
2.限流不生效
解决方法:配置redis实例地址
文章评论