微服务并发增加后,先守住哪条线
微服务并发增加后,先守住哪条线
并发上来后,最先要守住的是入口的容量边界、排队策略和降级条件,而不是急着增加线程。本文的压测数字只用于说明观测方法,实际阈值应由服务容量测试确定。
Prometheus 监控监控曲线上,reactor-http-nio 线程全被堵在等待大模型推理服务的 Response 上。紧接着,下游订单微服务和风控微服务的 RPC 调用开始大面积超时,整条 Spring Cloud 调用链发生级联雪崩。
在大模型与预测建模接入 Spring Cloud 微服务体系后,系统的瓶颈不再是 CPU 和 DB,而是长尾等待延时极高的大模型服务。
传统微服务里每秒处理 5000 个 HTTP 请求轻轻松松,但只要其中有 100 个请求需要调用 LLM 预测接口,连接就会在 Spring Cloud Gateway 挂起数秒。
当并发陡增时,第一条必须守住的防线就是:网关层的背压(Backpressure)与隔离闸门。
# 启动 10000 QPS 持续 30 秒的压测击打 Spring Cloud Gateway
echo "GET ${GATEWAY_BASE_URL}/api/v1/ai/predict" | vegeta attack -rate=<rate> -duration=<duration> | vegeta report
# 查看 Spring Cloud Gateway 线程状态,排查是否有大量 NIO 线程处于 Blocked / Waiting 状态
jstack 88210 | grep -A 10 "reactor-http-nio" | grep "State:" | sort | uniq -c
# 查看 Actuator 暴露的 Resilience4j 熔断器实时指标
curl -s "http://localhost:8080/actuator/metrics/resilience4j.circuitbreakers.calls?tag=state:successful"
流量冲击下的双重背压隔离架构
在 Spring Cloud 体系中引入长耗时 AI 推理服务时,物理上必须将“高频轻量业务”与“长耗时 AI 业务”进行线程与信号量级别的物理隔离。
防护体系建立在两个关键原则上:
- 舱壁隔离(Bulkhead):强行给 AI 推理接口设定独立的最大并发连接数(如 200)。即便 200 个连接全部卡死在 LLM 响应上,另外 14800 个标准微服务请求依然能在 10ms 内快速处理。
- 响应式背压(Reactive Backpressure):利用 Project Reactor 的
onBackpressureDrop或request(n)机制,当下游消费跟不上上游推送时,网关直接拒绝新连接,而不是把请求堆在 JVM 内存队列里。
生产级 Reactive 网关背压与舱壁过滤器实现
基于 Spring Cloud Gateway 的 AbstractGatewayFilterFactory 实现一套兼具限流、信号量隔离与背压控制的生产级 Filter。
package com.company.cloud.gateway.filter;
import io.github.resilience4j.bulkhead.BulkheadFullException;
import io.github.resilience4j.reactor.bulkhead.operator.BulkheadOperator;
import io.github.resilience4j.bulkhead.ReactiveBulkhead;
import io.github.resilience4j.bulkhead.ReactiveBulkheadRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
@Component
public class AIBackpressureGatewayFilterFactory extends AbstractGatewayFilterFactory<AIBackpressureGatewayFilterFactory.Config> {
private static final Logger log = LoggerFactory.getLogger(AIBackpressureGatewayFilterFactory.class);
private final ReactiveBulkhead aiServiceBulkhead;
public AIBackpressureGatewayFilterFactory(ReactiveBulkheadRegistry bulkheadRegistry) {
super(Config.class);
// 初始化针对 AI 服务的响应式舱壁,限定最大并发数为 200
this.aiServiceBulkhead = bulkheadRegistry.bulkhead("aiInferenceService");
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
// 拦截 AI 推理路由
return chain.filter(exchange)
.transformDeferred(BulkheadOperator.of(aiServiceBulkhead))
.onErrorResume(BulkheadFullException.class, ex -> handleOverload(exchange, "AI 推理通道并发过载,已触发快速拒绝"))
.onErrorResume(Throwable.class, ex -> handleGenericError(exchange, ex));
};
}
private Mono<Void> handleOverload(ServerWebExchange exchange, String reason) {
log.warn("网关背压触顶: Path={}, Reason={}", exchange.getRequest().getPath(), reason);
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
String jsonFallback = """
{
"code": 429,
"message": "AI 服务繁忙,已触发服务背压防护",
"fallback": true
}
""";
byte[] bytes = jsonFallback.getBytes(StandardCharsets.UTF_8);
return exchange.getResponse().writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(bytes)));
}
private Mono<Void> handleGenericError(ServerWebExchange exchange, Throwable ex) {
log.error("网关异常: {}", ex.getMessage());
exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
return exchange.getResponse().setComplete();
}
public static class Config {
// 可扩充配置项
}
}
并在 application.yml 里面进行微服务网关路由配置:
spring:
cloud:
gateway:
routes:
- id: ai_inference_route
uri: lb://ai-predict-service
predicates:
- Path=/api/v1/ai/**
filters:
- name: AIBackpressureGatewayFilter
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 100
redis-rate-limiter.burstCapacity: 200
流量突发时的容量估算公式与防线部署
在生产环境部署 Spring Cloud 微服务时,防线的容量估算必须遵循严密的物理公式,不能凭感觉设置并发数。
1. AI 接口并发容量估算公式
$$ConcurrentLimit = \frac{ClusterTargetQPS \times P99Latency(s)}{InstanceCount}$$
假设生产环境预计承受的 AI 预测流量峰值为 $2000\text{ QPS}$,当前 AI 后端模型推理的 P99 延迟为 $1.5\text{ 秒}$,部署了 $10$ 台 Spring Cloud Gateway 实例。那么每台网关实例分配给 AI 路由的舱壁上限为:
$$Limit = \frac{2000 \times 1.5}{10} = 300\text{ 并发连接}$$
2. 线程池与 Netty 堆外内存防线
在 Spring Cloud Gateway 中,由于使用了 Netty 响应式网络通信,如果大量的请求在等待 AI 服务返回 Body,每个连接都会占用一定量的 Direct Memory(堆外内存)。
# 检查 Spring Cloud Gateway 进程的堆外内存占用情况
jcmd 88210 VM.native_memory baseline
jcmd 88210 VM.native_memory detail.diff | grep "Other"
如果堆外内存随并发飙升,必须在 JVM 启动参数中显式设置 -XX:MaxDirectMemorySize=2G,防止因为 Reactive 背压失效导致操作系统触发 OOM Killer 杀掉网关进程。
当并发洪峰涌入时,守住舱壁隔离和响应式背压这两条底线,Spring Cloud 微服务集群才不会因为某个慢服务的挂起而瘫痪。
更多推荐



所有评论(0)