一、Jetty作为Spring Cloud Gateway底层服务器的适用场景
1.1 典型应用场景
微服务架构里,API网关是流量的核心入口,比如电商大促的秒杀活动、订单查询这类场景,短时间内会有海量请求涌入。若网关扛不住流量,就会导致用户请求失败,直接影响业务。Jetty作为轻量级底层服务器,比默认的Netty更灵活,参数调整更精准,刚好适配网关需要高弹性、高并发的特性。比如618大促时,网关要同时处理百万级请求,还要防止下游订单、商品服务被冲垮,用Jetty+Gateway的组合就能更好控制流量和资源。
1.2 技术优缺点
优点:Jetty内存占用比传统Tomcat低,启动速度快,适合快速部署;采用NIO线程模型,一个线程能处理多个连接,比传统IO阻塞模型效率高;参数调整灵活,可精准控制连接和线程数量,适配网关这类需要精细调优的场景。缺点:对新手来说,Jetty参数比Netty复杂,需理解线程模型原理;参数调错反而会降低性能;需要替换默认依赖,有一定配置成本。
二、Jetty底层服务的弹性参数调整
2.1 依赖替换(必须先做的准备)
Spring Cloud Gateway默认用Netty作为底层服务器,要换成Jetty,必须先排除Netty依赖,加入Jetty相关包,这是新手最容易踩的坑。如果没做这一步,Jetty配置不会生效,启动后还是用Netty。
<!-- 替换Spring Cloud Gateway底层服务器为Jetty,技术栈:Spring Boot 2.7.12 + Spring Cloud Gateway 2021.0.5 + Jetty 11 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<!-- 排除默认Netty服务器依赖,这一步不可或缺 -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-reactor-netty</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 引入Spring Boot的Jetty启动器,替换底层服务器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<!-- Jetty响应式HTTP客户端,配合Gateway处理路由请求 -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-reactive-httpclient</artifactId>
<version>1.1.10</version>
</dependency>
2.2 Jetty核心弹性参数配置
Jetty弹性参数主要包括线程池、acceptor和selector线程,这些参数决定了底层服务的流量承载能力,配置在application.yml中,用生活化语言说明:
server:
jetty:
threads:
minThreads: 15 # 最小存活线程数,类似公司最少留15人值班,不能全空
maxThreads: 300 # 最大线程数,最多允许300人同时干活,太多会挤,太少不够用,按CPU核心数×2调整
idleTimeout: 60000 # 线程空闲60秒就销毁,节省资源,类似临时员工没活就下班
acceptors: 2 # acceptor线程数,负责接收新连接请求,按CPU核心数1/2设置,比如4核就设2,太多会抢资源
selectors: 4 # selector线程数,负责处理连接读写,一般等于CPU核心数,专门处理请求传输
这里要注意,maxThreads不能盲目设大,若4核服务器设300,压测时CPU使用率超过80%,反而会因为线程上下文切换频繁降低性能,需结合实际负载调整。
三、Gateway层结合Jetty的限流策略配置
仅调整底层Jetty参数不够,还要在Gateway层配置限流,防止请求过多冲垮下游服务。这里用Redis结合Gateway的RequestRateLimiter,是常用的可靠限流方案,示例如下:
3.1 限流KeyResolver配置
需定义限流的唯一标识,比如客户端IP,避免单个IP请求影响其他用户:
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
// 技术栈:Spring Boot 2.7.12 + Spring Cloud Gateway + Redis 6.2.7
@Component
public class IpKeyResolver implements KeyResolver {
// 用客户端公网IP作为限流唯一标识,简单有效,适合网关层限流
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
// 获取请求远程地址,提取IP地址
return Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
}
3.2 Gateway路由限流配置
在application.yml中配置Gateway限流规则,配合Jetty参数设置合理阈值,保证流量可控:
spring:
cloud:
gateway:
routes:
- id: order-service-route # 路由唯一标识
uri: lb://order-service # 负载均衡到order-service微服务
predicates:
- Path=/order/** # 匹配所有/order开头的请求路径
filters:
- name: RequestRateLimiter # 启用请求限流过滤器
args:
key-resolver: "#{@ipKeyResolver}" # 使用刚才定义的IP作为限流Key
redis-rate-limiter.replenishRate: 500 # 每秒允许处理500个请求,和Jetty maxThreads匹配留余量
redis-rate-limiter.burstCapacity: 600 # 令牌桶最大容量,允许瞬时突发600个请求,应对流量高峰
redis-rate-limiter.requestedTokens: 1 # 每个请求消耗1个令牌,规则简单清晰
这里的replenishRate和burstCapacity需和Jetty的maxThreads配合,比如Jetty最大线程300,设限流500看起来超过,但令牌桶允许突发,只要Jetty连接数没超配置值,请求会正常处理,既保证流量又不冲垮下游。
四、调优过程中的注意事项
4.1 依赖替换的正确性
一定要排除Spring Boot默认的reactor-netty依赖,否则启动后还是用Netty,Jetty配置无效。若启动时报Jetty相关错误,优先检查依赖是否排除Netty。
4.2 参数的匹配性
Jetty的maxThreads和Gateway限流阈值要匹配,比如Jetty最大线程300,限流QPS设为400不合理,因为最多只能处理300个请求,剩下100会排队超时,限流阈值不能超过Jetty最大承载请求数。另外,Jetty的connectionTimeout要和Gateway路由超时一致,比如都设为5秒,避免超时不一致导致请求异常。
4.3 熔断降级的配合
限流触发后不能直接返回500错误,要结合Resilience4j或Sentinel,返回友好提示,比如“当前访问人数过多,请稍后再试”,同时对下游服务降级,比如无订单数据时返回默认值,提升用户体验。
4.4 压测验证
所有参数调整后必须做压测,用JMeter或Locust模拟大流量,监控Jetty的CPU、内存使用率,Gateway的响应时间,确认限流生效、无请求堆积。比如压测时,请求超限流阈值后,Gateway返回429错误,Jetty连接数不超配置最大值,才是正确的。
五、总结和落地建议
总的来说,用Spring Cloud Gateway搭配Jetty时,弹性与限流调整分三步:第一步正确替换依赖,把底层换成Jetty;第二步调整Jetty的线程和连接参数,让底层承载足够流量;第三步配置Gateway限流策略,防止冲垮下游;最后配合熔断降级和压测,确保系统稳定。落地时先从最小参数调整,逐步增加,压测验证,直到达到预期效果,就能打造出高可用、高弹性的微网关,应对各类高并发场景。
Comments