微服务网关设计与实现

前言

在微服务架构中,API网关是不可或缺的组件。它作为系统的入口,承担着路由转发、安全认证、流量控制等关键职责。本文将深入探讨API网关的设计理念和实现方案,帮助你构建高性能、高可用的网关系统。


一、为什么需要API网关

1.1 微服务面临的挑战

问题1:客户端复杂性

1
2
3
4
客户端 → 用户服务 (http://user-service:8001)
→ 订单服务 (http://order-service:8002)
→ 商品服务 (http://product-service:8003)
→ 支付服务 (http://payment-service:8004)

客户端需要:

  • 维护多个服务地址
  • 处理不同的协议
  • 实现重试和容错逻辑
  • 管理认证凭证

问题2:横切关注点

  • 认证授权:每个服务都要实现?
  • 限流熔断:如何统一管理?
  • 日志监控:分散在各个服务?
  • 协议转换:HTTP、gRPC、WebSocket?

1.2 API网关的作用

1
2
3
4
5
6
7
8
客户端 → [API网关] → 微服务集群
↓
• 路由转发
• 认证授权
• 限流熔断
• 负载均衡
• 协议转换
• 日志监控

核心价值:

  1. 简化客户端:单一入口
  2. 集中管理:统一的横切关注点
  3. 解耦服务:服务位置透明
  4. 提升安全:统一认证鉴权

二、网关核心功能

2.1 路由转发

基于路径路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1

- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=1

基于请求头路由:

1
2
3
4
5
6
7
8
9
10
routes:
- id: api-v1
uri: http://api-v1.example.com
predicates:
- Header=X-API-Version, v1

- id: api-v2
uri: http://api-v2.example.com
predicates:
- Header=X-API-Version, v2

基于参数路由:

1
2
3
4
5
routes:
- id: beta-users
uri: http://beta.example.com
predicates:
- Query=beta, true

2.2 认证授权

JWT认证:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@Component
public class JwtAuthenticationFilter implements GlobalFilter, Ordered {

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();

// 白名单路径直接放行
if (isWhiteList(request.getPath().value())) {
return chain.filter(exchange);
}

// 获取token
String token = request.getHeaders().getFirst("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
return unauthorized(exchange);
}

// 验证token
try {
Claims claims = JwtUtil.parseToken(token.substring(7));

// 将用户信息添加到请求头
ServerHttpRequest mutated = request.mutate()
.header("X-User-Id", claims.get("userId", String.class))
.header("X-User-Name", claims.get("username", String.class))
.build();

return chain.filter(exchange.mutate().request(mutated).build());

} catch (Exception e) {
return unauthorized(exchange);
}
}

private Mono<Void> unauthorized(ServerWebExchange exchange) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}

@Override
public int getOrder() {
return -100; // 高优先级
}
}

2.3 限流

令牌桶算法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Component
public class RateLimitFilter implements GlobalFilter, Ordered {

private final Map<String, RateLimiter> limiters = new ConcurrentHashMap<>();

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String clientId = getClientId(exchange);

// 获取或创建限流器(每秒10个请求)
RateLimiter limiter = limiters.computeIfAbsent(
clientId,
k -> RateLimiter.create(10.0)
);

// 尝试获取许可
if (!limiter.tryAcquire()) {
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return exchange.getResponse().setComplete();
}

return chain.filter(exchange);
}

private String getClientId(ServerWebExchange exchange) {
// 可以基于IP、用户ID等
return exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
}

@Override
public int getOrder() {
return -50;
}
}

Redis分布式限流:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Component
public class RedisRateLimitFilter implements GlobalFilter, Ordered {

@Autowired
private StringRedisTemplate redisTemplate;

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String key = "rate_limit:" + getClientId(exchange);

return Mono.fromCallable(() -> {
Long count = redisTemplate.opsForValue().increment(key);

if (count == 1) {
redisTemplate.expire(key, 1, TimeUnit.SECONDS);
}

return count;
})
.flatMap(count -> {
if (count > 10) { // 每秒10个请求
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
});
}

@Override
public int getOrder() {
return -50;
}
}

2.4 熔断降级

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@Component
public class CircuitBreakerFilter implements GlobalFilter, Ordered {

private final CircuitBreakerRegistry circuitBreakerRegistry;

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String serviceName = getServiceName(exchange);
CircuitBreaker circuitBreaker = circuitBreakerRegistry.circuitBreaker(serviceName);

return Mono.defer(() -> chain.filter(exchange))
.transformDeferred(CircuitBreakerOperator.of(circuitBreaker))
.onErrorResume(throwable -> {
// 熔断降级处理
return fallbackResponse(exchange, throwable);
});
}

private Mono<Void> fallbackResponse(ServerWebExchange exchange, Throwable throwable) {
exchange.getResponse().setStatusCode(HttpStatus.SERVICE_UNAVAILABLE);

String fallbackBody = """
{
"error": "Service temporarily unavailable",
"message": "Please try again later"
}
""";

DataBuffer buffer = exchange.getResponse()
.bufferFactory()
.wrap(fallbackBody.getBytes(StandardCharsets.UTF_8));

return exchange.getResponse().writeWith(Mono.just(buffer));
}

@Override
public int getOrder() {
return 0;
}
}

三、Spring Cloud Gateway实战

3.1 项目搭建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!-- pom.xml -->
<dependencies>
<!-- Spring Cloud Gateway -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

<!-- Nacos服务发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

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

<!-- Resilience4j熔断器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
</dependency>
</dependencies>

3.2 配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# application.yml
server:
port: 8080

spring:
application:
name: api-gateway

cloud:
nacos:
discovery:
server-addr: localhost:8848

gateway:
# 服务发现路由
discovery:
locator:
enabled: true
lower-case-service-id: true

# 路由配置
routes:
# 用户服务
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
- name: CircuitBreaker
args:
name: userServiceCircuitBreaker
fallbackUri: forward:/fallback/user
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: "#{@ipKeyResolver}"

# 订单服务
- id: order-service
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=1
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY,SERVICE_UNAVAILABLE
methods: GET
backoff:
firstBackoff: 10ms
maxBackoff: 50ms
factor: 2

# 全局过滤器配置
default-filters:
- AddResponseHeader=X-Response-Time, ${response-time}
- AddResponseHeader=X-Gateway-Version, 1.0

redis:
host: localhost
port: 6379

# Resilience4j配置
resilience4j:
circuitbreaker:
configs:
default:
slidingWindowSize: 100
permittedNumberOfCallsInHalfOpenState: 10
waitDurationInOpenState: 10000
failureRateThreshold: 50
slowCallRateThreshold: 50
slowCallDurationThreshold: 2000

3.3 自定义过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
@Component
public class CustomGatewayFilterFactory
extends AbstractGatewayFilterFactory<CustomGatewayFilterFactory.Config> {

public CustomGatewayFilterFactory() {
super(Config.class);
}

@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();

// 记录请求开始时间
exchange.getAttributes().put("startTime", System.currentTimeMillis());

// 添加自定义请求头
ServerHttpRequest mutated = request.mutate()
.header("X-Custom-Header", config.getValue())
.build();

return chain.filter(exchange.mutate().request(mutated).build())
.then(Mono.fromRunnable(() -> {
// 记录请求耗时
Long startTime = exchange.getAttribute("startTime");
if (startTime != null) {
long duration = System.currentTimeMillis() - startTime;
log.info("Request to {} took {}ms",
request.getURI(), duration);
}
}));
};
}

public static class Config {
private String value;

// getter/setter
}
}

四、性能优化

4.1 连接池优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
spring:
cloud:
gateway:
httpclient:
# 连接超时
connect-timeout: 1000
# 响应超时
response-timeout: 5s
# 连接池配置
pool:
type: ELASTIC
max-connections: 1000
max-idle-time: 30s
max-life-time: 60s

4.2 缓存优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
@Component
public class CacheFilter implements GlobalFilter, Ordered {

@Autowired
private StringRedisTemplate redisTemplate;

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();

// 只缓存GET请求
if (!request.getMethod().equals(HttpMethod.GET)) {
return chain.filter(exchange);
}

String cacheKey = generateCacheKey(request);

// 尝试从缓存获取
return Mono.fromCallable(() -> redisTemplate.opsForValue().get(cacheKey))
.flatMap(cachedResponse -> {
if (cachedResponse != null) {
// 返回缓存响应
return writeCachedResponse(exchange, cachedResponse);
}

// 缓存未命中,继续处理
return cacheResponse(exchange, chain, cacheKey);
});
}

private Mono<Void> cacheResponse(ServerWebExchange exchange,
GatewayFilterChain chain,
String cacheKey) {
ServerHttpResponse originalResponse = exchange.getResponse();
DataBufferFactory bufferFactory = originalResponse.bufferFactory();

// 包装响应以拦截数据
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
if (body instanceof Flux) {
return super.writeWith(
Flux.from(body).buffer().map(dataBuffers -> {
// 合并所有数据
DataBuffer joinedBuffer = bufferFactory.join(dataBuffers);
byte[] content = new byte[joinedBuffer.readableByteCount()];
joinedBuffer.read(content);

// 缓存响应
redisTemplate.opsForValue().set(
cacheKey,
new String(content, StandardCharsets.UTF_8),
5,
TimeUnit.MINUTES
);

return bufferFactory.wrap(content);
})
);
}
return super.writeWith(body);
}
};

return chain.filter(exchange.mutate().response(decoratedResponse).build());
}

@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 10;
}
}

4.3 并发优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@Configuration
public class GatewayConfig {

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("parallel-requests", r -> r
.path("/api/dashboard")
.filters(f -> f.filter(new ParallelRequestFilter()))
.uri("no://op"))
.build();
}
}

public class ParallelRequestFilter implements GatewayFilter {

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 并行请求多个服务
Mono<UserResponse> userMono = callUserService();
Mono<OrderResponse> orderMono = callOrderService();
Mono<ProductResponse> productMono = callProductService();

return Mono.zip(userMono, orderMono, productMono)
.flatMap(tuple -> {
DashboardResponse response = new DashboardResponse(
tuple.getT1(),
tuple.getT2(),
tuple.getT3()
);

return writeResponse(exchange, response);
});
}
}

五、监控与可观测性

5.1 Metrics集成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@Configuration
public class MetricsConfig {

@Bean
public MetricsFilter metricsFilter(MeterRegistry meterRegistry) {
return new MetricsFilter(meterRegistry);
}
}

@Component
public class MetricsFilter implements GlobalFilter, Ordered {

private final MeterRegistry meterRegistry;
private final Counter requestCounter;
private final Timer requestTimer;

public MetricsFilter(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;

this.requestCounter = Counter.builder("gateway.requests")
.description("Total gateway requests")
.register(meterRegistry);

this.requestTimer = Timer.builder("gateway.request.duration")
.description("Gateway request duration")
.register(meterRegistry);
}

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
Timer.Sample sample = Timer.start(meterRegistry);

return chain.filter(exchange)
.doFinally(signalType -> {
requestCounter.increment();
sample.stop(requestTimer);

// 记录按路由的指标
String route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);
if (route != null) {
meterRegistry.counter("gateway.requests", "route", route).increment();
}
});
}

@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}

5.2 日志追踪

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Component
public class TraceFilter implements GlobalFilter, Ordered {

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String traceId = UUID.randomUUID().toString();

// 添加trace ID到请求头
ServerHttpRequest mutated = exchange.getRequest().mutate()
.header("X-Trace-Id", traceId)
.build();

// 添加到响应头
exchange.getResponse().getHeaders().add("X-Trace-Id", traceId);

// 记录请求日志
log.info("[{}] {} {} from {}",
traceId,
exchange.getRequest().getMethod(),
exchange.getRequest().getURI(),
exchange.getRequest().getRemoteAddress()
);

return chain.filter(exchange.mutate().request(mutated).build())
.doFinally(signalType -> {
// 记录响应日志
log.info("[{}] Response status: {}",
traceId,
exchange.getResponse().getStatusCode()
);
});
}

@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}

六、高可用架构

6.1 集群部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# Kubernetes部署
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-gateway
spec:
replicas: 3
selector:
matchLabels:
app: api-gateway
template:
metadata:
labels:
app: api-gateway
spec:
containers:
- name: gateway
image: api-gateway:1.0
ports:
- containerPort: 8080
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "1Gi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 10
periodSeconds: 5

---
apiVersion: v1
kind: Service
metadata:
name: api-gateway
spec:
selector:
app: api-gateway
ports:
- port: 80
targetPort: 8080
type: LoadBalancer

6.2 灰度发布

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@Component
public class GrayReleaseFilter implements GlobalFilter, Ordered {

@Value("${gray.version}")
private String grayVersion;

@Value("${gray.traffic.ratio}")
private double grayTrafficRatio;

@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 检查是否为灰度用户
String userId = exchange.getRequest().getHeaders().getFirst("X-User-Id");
boolean isGrayUser = checkGrayUser(userId);

// 或基于流量比例
boolean isGrayTraffic = Math.random() < grayTrafficRatio;

if (isGrayUser || isGrayTraffic) {
// 路由到灰度版本
ServerHttpRequest mutated = exchange.getRequest().mutate()
.header("X-Service-Version", grayVersion)
.build();

return chain.filter(exchange.mutate().request(mutated).build());
}

return chain.filter(exchange);
}

@Override
public int getOrder() {
return -200;
}
}

七、最佳实践

7.1 设计原则

  1. 单一职责:网关只做路由和策略,不处理业务逻辑
  2. 高性能:异步非阻塞,减少延迟
  3. 高可用:集群部署,无状态设计
  4. 可扩展:插件化架构,易于定制

7.2 安全建议

  • 启用HTTPS
  • 实施速率限制
  • 验证输入数据
  • 防止SQL注入和XSS
  • 定期更新依赖

7.3 监控指标

  • QPS/TPS
  • 响应时间(P50/P95/P99)
  • 错误率
  • 熔断次数
  • 限流次数

八、总结

API网关是微服务架构的关键组件,合理的设计和实现可以:

  1. 简化客户端:统一入口
  2. 提升安全:集中认证鉴权
  3. 保障稳定:限流熔断
  4. 优化性能:缓存、并行请求

掌握这些技能,你就能构建高性能的微服务网关系统!


参考资料