资讯动态

从线程模型到动态路由:Spring Cloud Gateway性能调优实战

发布时间:2026/10/3 7:07:10 来源:尧图企业网站定制
我在好几个微服务项目里都遇到过类似的情况网关的CPU不高、内存也不高但下游服务的P99延迟就是上不去。排查到最后发现Spring Cloud Gateway的很多默认配置是被当“黑盒”用掉的——大家习惯在yml里堆路由和过滤器然后直接拿去抗生产流量。等路由量从十几条涨到上百条或者某个过滤器里混进了同步调用网关的线程模型和连接管理就开始拖后腿。这篇文章不打算做成一份入门教程而是从我实际调优和管理网关的经验出发把Spring Cloud Gateway性能提升和灵活管理这条线拆开讲清楚。主要内容包括底层线程模型怎么影响吞吐、路由匹配在路由量变大后的隐性成本、过滤器链路和HTTP连接池怎么调、以及动态路由、灰度、限流这些管理功能如何落地。最后我会分享压测时容易被误读的指标还有几个生产环境高频问题的排查链路。如果你正在维护网关或者准备把网关从“配置玩具”变成真正能抗压的基础组件这篇内容应该对你有用。1. 从线程模型说起网关性能瓶颈的真正位置1.1 为什么加机器解决不了根本问题很多从Zuul 1.x或者Spring MVC迁过来的团队下意识会把网关当成一个“多线程并发服务”来理解。在Tomcat的同步模型下一个请求占用一个线程调大max-threads确实能直接提升并发能力代价是线程数越多上下文切换越频繁。但Spring Cloud Gateway的运行时是Spring WebFlux和Reactor Netty它走的是事件循环模型不是每个请求一个线程。事件循环模型的核心逻辑是少数几个EventLoop线程负责所有连接的读写事件一个线程上挂着成千上万个连接。某个连接上的请求在处理过程中如果发生阻塞占用的不是“这个请求的线程”而是整个EventLoop上所有连接共享的时间片。同样一个上游接口平时响应5毫秒看不出来一旦某个过滤器里出现一次几百毫秒的同步调用整个EventLoop上的流量都会跟着慢这就是为什么很多团队发现网关“莫名抖动”加机器也没有明显改善。举个实际例子我在一个项目中遇到过网关P99从80毫秒涨到300毫秒的情况业务方一直怀疑是下游服务变慢。后来用jstack抓线程栈发现大量请求堆在某个Filter的同步RPC调用上那个Filter从Redis里读配置用的还是阻塞客户端。问题不在下游而在网关自身的线程模型被破坏。把那段逻辑改成异步后P99立刻回落。所以调优网关性能的第一步是接受“这个组件不是同步线程模型”这个事实。1.2 Netty线程模型下最常被忽视的两个参数Reactor Netty的EventLoop线程默认数量通常是可用CPU核数的两倍线程名一般是reactor-http-nio-*。很多调优文章会建议你调大reactor.netty.ioWorkerCount这个参数但实际生产环境中这个参数需要谨慎处理。我先说一个反例某台4核8线程的机器上有人把ioWorkerCount调到了32结果吞吐反而下降。原因很简单EventLoop线程多了之后线程切换成本上去了而且网关的瓶颈往往不在“事件循环线程数量”上而在“某个事件循环线程上是否有阻塞操作”。如果每个EventLoop上的请求都是非阻塞流转默认线程数完全够用。真正值得关注的是两类资源一是连接管理二是业务执行线程池。另一个容易被忽视的参数是spring.codec.max-in-memory-size。默认值是256KB这决定了请求体缓冲的上限。如果接口会接收比较大的JSON报文超过这个大小后网关会直接报DataBufferLimitException。很多人第一次遇到这个问题时会去调过滤器、调路由结果改了半天发现是内存缓冲限制。根据下游接口的实际报文大小把这个值调到一个合理范围比如2MB或4MB同时注意不要设置得过大否则高并发下内存压力会很明显。1.3 重计算任务改道不要再阻塞EventLoop网关这类组件的定位是路由和数据转发它天生不该承担太多业务计算。但在实际项目中很多团队会把签名校验、加解密、参数校验这些逻辑放进过滤器里。这些操作本身是CPU密集型的如果直接在EventLoop线程上同步执行一个耗时的RSA验签操作就能让线程卡顿几十毫秒这一个EventLoop上的其他请求全部遭殃。我在做网关优化时的一个习惯是把这类有实际计算量的任务包装成Mono.fromCallable然后用subscribeOn(Schedulers.boundedElastic())扔到弹性线程池去执行。示例代码如下Override public MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) { return Mono.fromCallable(() - doSignatureCheck(exchange)) .subscribeOn(Schedulers.boundedElastic()) .then(chain.filter(exchange)); }boundedElastic是Reactor提供的一个有界弹性线程池默认线程数是CPU核数的10倍任务队列有上限不会无限创建线程。需要注意的是不要随手用Schedulers.parallel()来处理这类阻塞任务parallel调度器本身是给并行计算任务用的同样存在阻塞整个调度器的风险。我还会建议把这类“重计算”过滤器尽量精简能放业务侧就放业务侧网关只保留必要的鉴权和签名校验。网关每多做一次计算不只是多花一点CPU而是在事件循环上增加了一次阻塞风险这在流量突增时是非常致命的。2. 路由匹配的隐性成本路由量大了之后P99为什么爬升2.1 每次请求都在重复做路由构建与断言匹配Spring Cloud Gateway处理一个请求时会经过路由匹配阶段RoutePredicateHandlerMapping从RouteLocator拿到当前的路由集合逐个执行路由的Predicate断言第一个匹配命中的路由就是当前请求的路由。这里有两个成本容易被忽略。第一个是路由对象的构建。RouteDefinition要转换成Route转换过程会实例化断言对象和过滤器对象。路由数量少的时候这个开销可以忽略不计但当路由表到了几十条甚至上百条时每次请求都重新构建一遍累积的时间就不小了。第二个成本是断言匹配本身比如Path断言、Header断言、Query参数断言每一条都要执行一遍直到命中第一个匹配为止。如果把所有路由的order都设为0那每次请求都要线性扫一遍全部路由。我实际测过一个项目路由从12条涨到160条后其他条件不变的条件下单次请求在路由匹配阶段的开销从大约0.3毫秒涨到了2.5毫秒以上。在网关这种千万级请求量的入口这个增长直接反映在P99上压测数据显示P99从约80毫秒涨到了约260毫秒。这个现象非常典型业务方第一反应是下游变慢了实际上光路由匹配就占了不少时间。2.2 用Caffeine做一层路由结果缓存既然瓶颈在于“每次请求都重新构建Route列表并逐个匹配”那一个直接的优化思路就是给RouteLocator包一层缓存。这里我推荐用Caffeine命中率高、淘汰策略灵活而且对GC友好。核心实现是一个自定义的RouteLocatorComponent public class CachingRouteLocator implements RouteLocator { private final RouteLocator delegate; private final CacheString, ListRoute cache Caffeine.newBuilder() .maximumSize(1) .expireAfterWrite(Duration.ofSeconds(30)) .build(); public CachingRouteLocator(RouteLocator delegate) { this.delegate delegate; } Override public FluxRoute getRoutes() { return Flux.fromIterable( cache.get(allRoutes, k - delegate.getRoutes().collectList().block()) ); } public void evict() { cache.invalidateAll(); } }这个方案的关键在于两点第一缓存的是转换后的Route列表而不是RouteDefinition这样省去了每次请求构建对象的开销第二动态更新路由后必须手动调用evict()清空缓存否则新路由不会生效。过期时间我一般设30秒到2分钟作为兜底机制防止某个环节忘记主动清缓存导致路由变更迟迟不生效。这里说明一下Spring Cloud Gateway不同版本对路由缓存的内部实现有差异与其依赖某个版本里的缓存行为不如自己控制这一层。这个自定义方案侵入性低只要在配置里替换掉原有的RouteLocator即可。2.3 断言的书写顺序与路由排序规则除了加缓存路由本身的写作习惯也会影响匹配效率。Spring Cloud Gateway的路由匹配是“首个命中即返回”不是“全部匹配后选最优”。所以路由的order字段非常关键order越小越先匹配。合理的做法是把更具体的、更高优先级的规则放到更小的order上灰度路由通常设置成负数确保它在普通路由之前命中。还有一个我踩过的小坑很多人为了省事所有路由的order都是0。路由少的时候还行路由多的时候每次请求就要从头扫到尾。更合理的做法是公共兜底路由比如404处理放到最后核心业务路由根据重要程度设置1、2、3这样的顺序灰度路由放到负数区域。另外自定义断言要尽量轻量。Path断言内部有PathPattern的优化机制匹配效率很高而如果自己在断言里写正则、查Redis、查数据库那每个请求的路由匹配阶段都会被拖慢。遇到这种情况先想想这个判断逻辑是否真的属于“路由层”很多业务判断应该放到Filter里做而不是塞进断言。3. 过滤器链路与连接管理从转发到返回的全路径调优3.1 别让全局过滤器成为系统性开销Spring Cloud Gateway的过滤器大致分两类GlobalFilter全局过滤器和路由级的GatewayFilter。全局过滤器对所有请求生效路由级过滤器只对匹配到该路由的请求生效。很多人图省事什么逻辑都写成GlobalFilter这是性能优化的一个潜在隐患。每个GlobalFilter都像一个套在请求路径上的洋葱层按Order顺序依次包裹。单看一个过滤器可能只是加个请求头、打个日志、插个traceId耗时都在微秒级。但五六个全局过滤器叠加起来高并发下的累积耗时就很可观。我在一个项目里数过网关上有七个GlobalFilter其中有两个功能很接近一个加请求ID一个加用户上下文它们各自读取请求头、各自做一次MDC写入。合并之后单请求省了将近0.8毫秒。看起来不多但对P99的贡献是实打实的。我的建议是能用GatewayFilter路由级解决的就别用GlobalFilter多个filter共用的前置逻辑考虑合并成一个。同时定期检查那些网上抄来的“通用过滤器”很可能存在重复逻辑。3.2 HTTP连接池参数被误读最多的配置项Spring Cloud Gateway作为网关还承担HTTP客户端的角色。NettyRoutingFilter会把请求转发到下游服务这背后用的是Reactor Netty的HttpClient底层有一套连接池。压测时最常见的报错之一是连接池耗尽很多人上来就调maxConnections但实际很多情况是连接复用策略和超时设置不合理。我通常会通过自定义HttpClient来管理这些参数ConnectionProvider provider ConnectionProvider.builder(gateway-pool) .maxConnections(500) .pendingAcquireMaxCount(1000) .pendingAcquireTimeout(Duration.ofMillis(3000)) .maxIdleTime(Duration.ofSeconds(45)) .build(); HttpClient httpClient HttpClient.create(provider) .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000) .responseTimeout(Duration.ofSeconds(10)) .doOnConnected(conn - conn.addHandlerLast(new ReadTimeoutHandler(10)));几个参数的实际含义和设置思路maxConnections连接池的最大连接数。不要随便设置成几千而是根据下游服务的吞吐能力和网关所在机器的网络连接数上限来决定。pendingAcquireTimeout等待获取连接的超时时间。高并发下如果下游响应慢连接不够用请求会进入等待队列这个值设置太短会直接报错设置太长会拖长P99。maxIdleTime连接最大空闲时间。这里有一个非常重要的匹配原则我在生产环境踩过一个大坑下游服务的容器配置了60秒空闲断开连接而网关连接池的maxIdleTime是90秒导致网关复用了一个即将被下游断开的连接请求刚到下游就被关闭了。连接池和下游服务的空闲超时时间必须匹配。稳妥的做法是让连接的maxIdleTime略小于下游服务的空闲超时时间比如下游60秒网关就设45秒避免复用“僵尸连接”。3.3 压缩与请求体大小吞吐与延迟的平衡很多人会想到给网关开压缩降低带宽占用。但内部网关一般不建议开压缩。原因很简单内网带宽充足压缩引入的CPU开销和压缩延迟不值得。如果是对外API网关需要考虑降低公网带宽成本可以开启压缩但要选一个合适的压缩级别。server: compression: enabled: true mime-types: application/json,application/xml,text/plain min-response-size: 1024注意min-response-size的意思是只有响应体超过1KB才压缩避免小报文被压缩功能白白消耗CPU。压缩级别不建议开到最大我习惯用默认级别已经能在体积和CPU开销之间取得一个可接受的平衡。请求体大小的配置前面提过spring.codec.max-in-memory-size会影响请求体缓冲上限。如果下游接口接收大文件或大报文需要合理调大但不要无脑调成100MB否则很容易把网关的堆内存打爆。更合适的做法是配合DataBuffer的流式处理避免一次性把整个请求体加载到内存。4. 灵活管理从静态路由到热更新、灰度、限流的落地4.1 为什么静态yml路由在生产环境不够用我把路由配置写在yml里是最简单的方案但一旦路由数量多了、服务上线频繁静态配置就会变得很难受。每次新增一个上游服务或者某个服务需要切流量都要改配置文件然后重启网关。网关是多个微服务共用的入口重启一次意味着所有经过网关的业务全部中断哪怕只是几秒钟的抖动在线上也是不可接受的。所以动态路由管理的目标很明确路由的新增、修改、删除、启停都通过运行时操作完成不影响其他路由也不重启网关进程。这个诉求在微服务数量超过三四十个之后几乎是刚需。4.2 基于配置中心的路由热更新用Nacos、Consul这类配置中心做路由配置管理是最容易起步的方案。把路由的spring.cloud.gateway.routes配置放到配置中心的配置文件中网关实例监听配置变更。这里有一个非常容易踩的坑RefreshScope能刷新大部分配置但刷新不了网关的路由表。路由表需要发布一个RefreshRoutesEvent事件网关收到事件后才会重新拉取路由。只靠RefreshScope是没用的路由不会自动变。监听配置变更后必须手动发布事件Component public class RouteConfigListener { Autowired private ApplicationEventPublisher publisher; public void refresh() { publisher.publishEvent(new RefreshRoutesEvent(this)); } }这个方案适合静态路由的集中管理配置变更后的生效速度取决于配置中心的监听延迟和网关的刷新逻辑。不过它有个局限如果你的路由管理不只是改一条yml还要做灰度权重调整、限流参数调整、路由上下线控制纯配置中心方案会越来越别扭。4.3 自建轻量路由管理模块的思路当动态路由的管理场景变复杂时我建议做一套轻量的路由管理模块核心思路是用数据库存储路由定义网关通过一个RouteDefinitionLocator从数据库读取管理端操作后主动通知网关刷新。数据库表结构大致是这样的CREATE TABLE gateway_route ( id BIGINT PRIMARY KEY AUTO_INCREMENT, route_id VARCHAR(64) NOT NULL UNIQUE, uri VARCHAR(255) NOT NULL, predicates TEXT NOT NULL COMMENT JSON数组, filters TEXT COMMENT JSON数组, route_order INT DEFAULT 0, status TINYINT DEFAULT 1, version INT DEFAULT 1, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP );网关侧的核心实现是一个自定义的RouteDefinitionLocatorComponent public class DbRouteDefinitionRepository implements RouteDefinitionLocator { Autowired private GatewayRouteMapper gatewayRouteMapper; Override public FluxRouteDefinition getRouteDefinitions() { return Flux.fromIterable(gatewayRouteMapper.selectAllEnabled()) .map(row - { RouteDefinition definition new RouteDefinition(); definition.setId(row.getRouteId()); definition.setUri(URI.create(row.getUri())); definition.setPredicates(parseJson(row.getPredicates())); definition.setFilters(parseJson(row.getFilters())); definition.setOrder(row.getRouteOrder()); return definition; }); } }管理端做完增删改操作后调用RouteDefinitionWriter保存路由然后发布RefreshRoutesEvent。这里要特别注意数据库方案的优势是路由管理可控、有审计记录劣势是每次路由变更都要保证数据库和网关内存一致。所以版本号这个字段建议保留管理端修改时递增版本号网关侧可以记录当前生效版本防止并发变更时出现路由错乱。一个小提示路由的增删改操作建议做成同步接口管理端调用后等待网关刷新完成再返回。如果异步处理可能管理端显示“已生效”实际网关还没来得及刷新线上就出现了短暂不一致。4.4 灰度发布与动态限流的组合用法动态路由管理最典型的落地场景有两个灰度发布和动态限流。灰度发布我用的是Weight路由断言。通过权重配置让一定比例的请求路由到新版本服务spring: cloud: gateway: routes: - id: order-service-v1 uri: lb://order-service predicates: - Weightorder-service, 90 filters: - StripPrefix1 - id: order-service-v2 uri: lb://order-service-gray predicates: - Weightorder-service, 10 filters: - StripPrefix1权重调整时同样的套路修改路由定义后发布RefreshRoutesEvent。灰度发布过程要和监控指标配合比如先切5%观察下游服务错误率和P99没有问题再逐步切到50%、100%。限流方面Spring Cloud Gateway官方方案是RequestRateLimiter过滤器基于Redis做令牌桶算法。关键参数有三个replenishRate代表每秒补充的令牌数也就是平均速率burstCapacity代表桶容量允许的突发流量requestedTokens代表每次请求消耗的令牌数一般设为1。再加上一个KeyResolver来确定限流维度Bean public KeyResolver userKeyResolver() { return exchange - Mono.just( exchange.getRequest().getHeaders().getFirst(X-User-Id) ! null ? exchange.getRequest().getHeaders().getFirst(X-User-Id) : anonymous ); }动态调整限流参数本质上也是更新路由定义中的过滤器参数然后刷新路由。在实际项目中”动态限流“最大的价值不是让运维去改参数而是和监控联动当某个接口的流量异常上涨时系统自动把限流阈值降下来保护下游服务。这个思路可以延伸到很多场景核心在于动态路由机制本身要足够可靠。5. 用压测数据验证优化效果读懂指标与常见误判5.1 一次完整调优前后的数据对比性能优化如果没有压测数据支撑很容易变成自我感觉良好。我习惯在一个固定场景下做前后对比控制变量记录吞吐量、P99延迟、GC暂停等关键指标。以我之前调优的一个项目为例压测环境是8核16G的物理机下游是一个模拟接口平均响应5毫秒压测工具用的wrk并发数保持在1000。调优前的状态是默认线程模型、160条静态路由、5个全局过滤器、默认HTTP连接池参数。调优后的状态是加了Caffeine路由缓存、同步阻塞逻辑全部切到boundedElastic、全局过滤器合并成3个、连接池按下游吞吐重新设置、路由order做了梳理。数据对比大致如下指标调优前调优后吞吐量约8200 req/s约11300 req/sP99响应时间约260ms约120msGC暂停P99约85ms约40ms路由匹配阶段平均耗时约2.6ms约0.4ms需要强调这个数据只代表那一个项目的硬件和业务场景不同机器、不同下游服务、不同路由数量结果都会不一样。重点是看趋势吞吐量提升了近40%P99降了一半以上GC暂停也明显下降。这说明优化方向是对的但每个参数都要在自己的环境里验证不要把一个项目的数字直接当标准。5.2 判断线程饥饿还是连接瓶颈的快速方法性能出问题时最需要判断的是瓶颈到底在哪个环节。我常用的快速定位方法有三个。第一看EventLoop线程的利用率。如果reactor-http-nio-*线程长时间处于RUNABLE状态CPU占用却不高大概率是某些操作在等待外部资源比如同步RPC、数据库查询。这种情况下查一下线程栈看看卡在哪个调用上基本能找到阻塞点。第二看连接池的等待情况。如果压测日志里出现Connection pool exhausted或者Pending Acquire耗时飙升说明连接获取环节出了问题。这时要分清是连接池太小还是下游响应太慢占用了太多连接。一个快速判断方法把maxConnections临时调大一倍再压测如果吞吐没有提升问题就不在连接池大小而在下游或者网关自身。第三用jstack或者Arthas抓线程快照。大量线程停在IO读写上是正常现象但如果看到大量线程停在某个同步框架的调用上比如java.net.SocketInputStream下的阻塞读或者某个同步HTTP客户端的等待那就说明业务过滤器里混进了阻塞操作。5.3 监控接入从Actuator到Prometheus的指标选择网关的监控不能只靠看日志Tail-View式的日志排查在灰度发布和动态路由场景下效率太低。Spring Boot Actuator提供了网关专属的端点最常用的是/actuator/gateway/routes查看当前所有路由确认动态刷新是否生效。/actuator/gateway/globalfilters列出全局过滤器及顺序排查过滤器是否存在冗余。/actuator/gateway/routefilters列出路由级过滤器。接入Prometheus和Grafana时有一个容易踩的坑很多人默认去看Tomcat线程池指标但Spring Cloud Gateway不是Tomcat模型那些指标没有参考价值。真正要关注的是Netty相关指标以及Micrometer采集的gateway_requests_seconds这类和网关转发相关的指标。我在实际监控面板上固定保留几类指标请求量QPS、P99/P95延迟、当前路由数、动态刷新次数、Netty事件循环线程繁忙度、上游连接池的活跃连接数和等待获取连接数。这些指标组合起来基本能覆盖网关的绝大部分问题场景。6. 生产环境三个高频问题的排查链路6.1 Connection prematurely closed BEFORE response这个报错在网关日志里出现的频率非常高而且容易误导排查方向。它的字面意思是“在响应返回之前连接被关闭了”但到底是谁关的需要一步步定位。排查链路我一般这样走先看报错时间点网关和上游服务的日志。如果上游服务日志里有连接被异常关闭的记录那问题大概率出在上游如果上游没有异常记录问题很可能出在网关连接池复用了一个已经失效的连接。最常见的场景是这样的上游服务设置了空闲连接超时比如60秒网关连接池却允许连接空闲90秒。一个请求到达网关时网关从这个“即将过期”的连接池里挑了一个连接转发给上游连接刚发出去上游就主动断开了请求自然失败。解法上面提过让网关连接池的maxIdleTime小于上游的空闲超时时间。这里我再补充一点如果上游是容器化部署节点经常弹性伸缩旧连接被清掉的情况会更频繁这种情况下可以适当调低maxIdleTime并配合请求重试机制。但重试要小心接口必须是幂等的否则重试会带来数据问题。6.2 内存缓慢上涨与路由对象堆积动态路由用起来之后内存缓慢上涨是常见问题。最典型的情况是频繁发布RefreshRoutesEvent每次刷新都会构建新的RouteDefinition和Route对象。如果这些旧对象被某个缓存持有不能及时被GC回收内存就会慢慢涨上去。排查时我会先看堆内存里Route相关对象的数量变化。用jmap抓一个快照jmap -histo:live pid | grep -E Route|Predicate|Filter对比路由变更前后的对象数量。如果数量只增不减基本可以确定有缓存或者事件监听器在持有旧对象。处理方法分两步第一步检查自定义缓存比如前面写的Caffeine缓存是否有maximumSize限制没有的话赶紧加上第二步检查ApplicationListener和消息监听器是否持有路由对象引用动态刷新后要清理旧引用。另一个容易被忽视的点是Metaspace。如果路由断言、过滤器的类型是通过Groovy或SPEL动态生成的每次刷新都可能在Metaspace留下类定义时间长了一样会OutOfMemory。这种情况的解法是尽量别用动态脚本做断言改用固定的Java类型。6.3 灰度切换后部分请求仍然打到旧实例灰度发布时调整权重后如果发现还有请求打到旧实例不要急着怀疑路由刷新失败。需要排查的点往往在服务发现那一层。Spring Cloud Gateway通过lb://前缀转发时使用的是Spring Cloud LoadBalancer底层会缓存服务实例列表。灰度权重调整后如果LoadBalancer的缓存没有及时刷新请求还是会按旧列表分发。有些版本的缓存默认几十秒甚至更长灰度过程中出现一部分请求打到旧实例是很正常的。处理方案是调整服务发现缓存刷新时间同时主动触发缓存刷新。比如在路由刷新的同时调用LoadBalancer的缓存管理器清理对应服务的缓存Autowired private LoadBalancerCacheManager cacheManager; public void evictServiceCache(String serviceId) { cacheManager.getCache(serviceId).clear(); }这个细节如果没处理好灰度发布的效果就会被“幽灵流量”干扰看起来权重已经改了实际并没有完全生效。6.4 最后一套我常用的网关快速体检清单在收尾之前分享一套我每次上线网关配置前都会快速过一遍的清单。这套清单不需要高级工具按顺序检查就能避免大部分线上事故路由总数和order分布是否存在大量order为0的兜底路由全局过滤器列表是否有重复逻辑或可以合并的过滤器所有过滤器链路中是否存在同步阻塞操作确认是否已切换到boundedElastic或异步化HTTP连接池的maxIdleTime是否与上游服务空闲超时匹配请求体大小限制spring.codec.max-in-memory-size是否适配实际报文动态路由刷新事件是否有监控最近一次刷新是否成功灰度权重配置和LoadBalancer缓存刷新联动是否正常。这套清单看起来简单但每一项都在生产环境里付出过代价。我后来养成的习惯是每次网关发布前花十分钟过一遍线上出问题的频率确实降了不少。网关这种基础设施稳定比功能多更重要能够在配置阶段提前拦截风险比事后拼命排查要有价值得多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑