Spring Cloud Gateway 全程非阻塞,禁用 Thread.sleep() 和 RestTemplate;必须用 WebClient + Mono/Flux;响应头修改需在 NettyRoutingFilter 前(order ≤ -1);连接池默认 500,需按需调优;HTTP/2、超时等需显式配置。

Spring Cloud Gateway 的请求转发不是靠线程池阻塞等待
它用的是 Netty 的 ChannelHandlerContext 和响应式流(Reactor),整个链路从接收请求、路由匹配、过滤器执行到后端调用,全程无阻塞。你写一个 GlobalFilter 时如果用了 Thread.sleep() 或同步 HTTP 客户端(比如 RestTemplate),会直接卡住整个 EventLoop 线程,导致后续所有请求堆积——这不是“慢”,是“全挂”。
常见错误现象:
- CPU 很低但请求大量超时(ReadTimeoutException)
- 日志里反复出现 io.netty.util.concurrent.BlockingOperationException
- 同一实例下,某个路由出问题,其他路由也跟着 503
- 必须用
WebClient替代RestTemplate,且所有调用要保持Mono/Flux链式传递 - 自定义
GlobalFilter中禁止任何阻塞 I/O,包括File.readAllBytes()、JDBC同步查询 - 若真需同步逻辑(如读本地配置文件),用
publishOn(Schedulers.boundedElastic())切换线程,但要注意这会增加调度开销
Netty 的 Channel 是怎么被复用的?
Spring Cloud Gateway 启动时会初始化一个共享的 ConnectionProvider,默认最大连接数是 500(对应 reactor.netty.resources.ConnectionProvider.elastic() 的变体)。后端服务每个 host:port 组合会被缓存为一个连接池,而不是每次请求都新建 TCP 连接。
使用场景:
- 你配置了 lb://user-service,Gateway 实际会解析成多个 IP + port,对每个 endpoint 单独建池
- 如果后端服务扩缩容频繁,连接池不会自动感知,旧连接可能 FIN_WAIT2 堆积
- 检查连接泄漏:抓包看
TCP RST是否突增,或监控reactor.netty.connection.provider.activeConnections指标 - 调大连接池:在
application.yml加spring.cloud.gateway.httpclient.pool.max-idle-time=30000 - 禁用连接复用(仅调试):设
spring.cloud.gateway.httpclient.pool.max-life-time=-1,但会显著降低吞吐
为什么加了自定义 Filter 后响应头丢失?
因为 Netty 的 HttpResponse 是只写一次的,一旦 writeWith 或 writeAndFlush 被触发,后续再 try 写 header 就会静默失败。Spring Cloud Gateway 在 NettyRoutingFilter 里已经把 response 写回客户端了,你的 filter 如果在它之后执行(比如 order=200),再想改 ServerHttpResponse 的 header 就晚了。
常见错误现象:
- response.getHeaders().set("X-Trace-ID", "xxx") 完全没生效
- WebClient 返回的 ClientResponse header 正常,但最终客户端收不到
- 修改响应头必须在
NettyRoutingFilter执行前完成,即 order ≤ -1 - 如果只是想透传上游 header,用内置的
AddResponseHeaderGatewayFilterFactory更安全 - 需要动态计算 header(比如签名)?得用
ServerHttpResponseDecorator包装原始 response,重写writeWith方法
WebClient 底层的 Netty HttpClient 怎么调参?
Spring Cloud Gateway 默认用 reactor.netty.http.client.HttpClient,它的行为不完全由 Spring Boot 自动配置控制。比如超时、SSL 验证、HTTP/2 支持,都得显式配在 spring.cloud.gateway.httpclient 下,否则走 Netty 默认值(例如连接超时是 30 秒,不是你以为的 10 秒)。
参数差异:
- connect-timeout 控制 TCP 握手耗时,单位毫秒;response-timeout 控制从发送完 request 到收到第一个 byte 的最大间隔
- ssl.use-insecure-trust-manager: true 只应在测试环境开,生产必须配 ssl.trust-manager.key-store
- 启用 HTTP/2:确保后端支持,然后加
spring.cloud.gateway.httpclient.http2=true - 禁用重试:默认会重试 GET 请求,设
spring.cloud.gateway.httpclient.response-timeout=60000并配合retry过滤器显式控制 - 日志调试:加
-Dreactor.netty.http.client.level=DEBUG,能看到真实连接建立和 pipeline 事件
Netty 的 channel 生命周期和响应式流背压耦合得很紧,改一个参数可能影响整条链路的吞吐和错误传播方式。别只盯着 timeout,connection pool size 和 max life time 往往才是压测时最先暴露的瓶颈点。










