在微服务架构中,网关作为系统的入口,承担着流量控制、请求路由和灰度发布等核心功能。本文将展示如何使用 Spring Cloud Gateway 和 Nacos 配置中心,实现动态的 流量复制 和 权重灰度发布 功能,并支持实时配置更新。
功能简介
1. 流量复制
流量复制功能可以将进入网关的请求完整地复制到多个目标服务,用于以下场景:
- 数据同步。
- 线上与线下环境的结果对比。
- 日志追踪与流量回放。
2. 权重灰度发布
权重灰度发布功能可以根据预设的权重,将流量按比例分发到多个目标服务,用于以下场景:
- 新旧版本的平滑灰度发布。
- 增量用户的功能验证。
3. 动态配置
借助 Nacos 配置中心,您可以:
- 动态调整流量复制目标和灰度发布规则。
- 启用或禁用流量复制功能,无需重启网关。
技术栈
- Spring Cloud Gateway:实现网关核心功能。
- Spring Cloud Nacos Config:实现动态配置的加载与刷新。
- Nacos:集中化管理流量规则。
- Reactor:基于 Reactor 的响应式编程模型。
实现步骤
1. Nacos 配置示例
在 Nacos 配置中心创建配置文件 gateway-config.yaml
,并将其发布到 DEFAULT_GROUP
分组下。内容如下:
traffic:
replication:
enabled: true
rules:
- path: "/api/v1/orders"
targets:
- "http://service-a"
- "http://service-b"
- path: "/api/v1/users"
targets:
- "http://service-c"
gray-release:
weights:
- server: "http://service-a"
weight: 70
- server: "http://service-b"
weight: 30
2. 引入依赖
在 pom.xml
文件中添加以下依赖:
<dependencies>
<!-- Spring Cloud Gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- Spring Cloud Nacos Config -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<version>2021.1</version> <!-- 根据项目需求调整版本 -->
</dependency>
</dependencies>
3. 本地配置
在 application.properties
文件中配置 Nacos 服务地址和基础信息:
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.file-extension=yaml
spring.cloud.nacos.config.shared-dataids=gateway-config.yaml
spring.cloud.nacos.config.group=DEFAULT_GROUP
spring.cloud.nacos.config.refresh-enabled=true
4. 规则加载器
流量复制规则加载器
从 Nacos 动态加载流量复制规则:
@Component
@RefreshScope
@ConfigurationProperties(prefix = "traffic.replication")
public class ReplicationRuleLoader {
private boolean enabled;
private List<TrafficRule> rules;
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public List<TrafficRule> getRules() {
return rules;
}
public void setRules(List<TrafficRule> rules) {
this.rules = rules;
}
}
权重灰度规则加载器
从 Nacos 动态加载权重灰度规则:
@Component
@RefreshScope
@ConfigurationProperties(prefix = "traffic.gray-release")
public class GrayReleaseRuleLoader {
private List<GrayReleaseRule> weights;
public List<GrayReleaseRule> getWeights() {
return weights;
}
public void setWeights(List<GrayReleaseRule> weights) {
this.weights = weights;
}
public static class GrayReleaseRule {
private String server;
private int weight;
public String getServer() {
return server;
}
public void setServer(String server) {
this.server = server;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
}
}
5. 流量复制过滤器
此过滤器根据规则将请求复制到多个目标服务,并记录请求和响应日志。
@Component
public class TrafficReplicationFilter implements GlobalFilter {
private final WebClient webClient;
private final ReplicationRuleLoader ruleLoader;
private final RequestLogService logService;
public TrafficReplicationFilter(WebClient.Builder webClientBuilder, ReplicationRuleLoader ruleLoader, RequestLogService logService) {
this.webClient = webClientBuilder.build();
this.ruleLoader = ruleLoader;
this.logService = logService;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
if (!ruleLoader.isEnabled()) {
return chain.filter(exchange); // 如果复制功能关闭,直接继续主请求
}
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
ruleLoader.getRules().stream()
.filter(rule -> rule.getPath().equals(path))
.findFirst()
.ifPresent(rule -> rule.getTargets().forEach(target -> replicateRequest(request, target)));
return chain.filter(exchange);
}
private void replicateRequest(ServerHttpRequest request, String targetUrl) {
webClient.method(org.springframework.http.HttpMethod.valueOf(request.getMethodValue()))
.uri(targetUrl + request.getURI().getPath())
.headers(headers -> headers.addAll(request.getHeaders()))
.retrieve()
.bodyToMono(String.class)
.subscribe(response -> System.out.println("Replicated to: " + targetUrl),
error -> System.err.println("Failed to replicate to: " + targetUrl));
}
}
6. 权重灰度过滤器
此过滤器根据预设的权重,将请求按比例分发到不同的目标服务。
@Component
public class WeightedGrayReleaseFilter implements GlobalFilter {
private final LockFreeWeightedRoundRobin roundRobin;
public WeightedGrayReleaseFilter(GrayReleaseRuleLoader ruleLoader) {
List<LockFreeWeightedRoundRobin.ServerWeight> serverWeights = ruleLoader.getWeights().stream()
.map(rule -> new LockFreeWeightedRoundRobin.ServerWeight(rule.getServer(), rule.getWeight()))
.collect(Collectors.toList());
this.roundRobin = new LockFreeWeightedRoundRobin(serverWeights);
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String target = roundRobin.next();
ServerHttpRequest modifiedRequest = exchange.getRequest().mutate().uri(target).build();
return chain.filter(exchange.mutate().request(modifiedRequest).build());
}
}
7. 动态配置生效
- 在 Nacos 中设置
traffic.replication.enabled: false
即可关闭流量复制。 - 修改目标服务的路径或权重,配置立即生效,无需重启网关服务。
总结
通过本文的实现,您可以:
- 实现动态的流量复制,用于日志追踪、流量回放等场景。
- 实现权重灰度发布,用于新旧版本的平滑过渡。
- 利用 Nacos 配置中心,实现高效的动态配置管理。
这种方式不仅提升了网关的灵活性,还降低了配置更新的运维成本,非常适合现代微服务架构的需求。