Skip to content

Retry GatewayFilter 工厂

Retry GatewayFilter 工厂支持以下参数:

  • retries:应尝试的重试次数。
  • statuses:应该重试的 HTTP 状态码,使用 org.springframework.http.HttpStatus 表示。
  • methods:应该重试的 HTTP 方法,使用 org.springframework.http.HttpMethod 表示。
  • series:应该重试的状态码系列,使用 org.springframework.http.HttpStatus.Series 表示。
  • exceptions:应该重试的抛出异常列表。
  • backoff:为重试配置的指数退避(exponential backoff)。
    • 重试将在 firstBackoff * (factor ^ n) 的退避间隔后执行,其中 n 是迭代次数。
    • 如果配置了 maxBackoff,应用的最大退避时间将被限制为 maxBackoff
    • 如果 basedOnPreviousValue 为 true,则退避时间通过 prevBackoff * factor 计算。
  • jitter:为重试配置的随机抖动(random jitter)。
    • 生成一个介于 [backoff - backoff*randomFactor, backoff + backoff*randomFactor] 之间的退避时间。
  • timeout:为重试配置的超时时间。

如果启用了 Retry 过滤器,默认配置如下:

  • retries:3 次
  • series:5XX 系列
  • methods:GET 方法
  • exceptionsIOExceptionTimeoutException
  • backoff:禁用
  • jitter:禁用
  • timeout:无限制

以下示例配置了一个 Retry GatewayFilter:

application.yml

yaml
spring:
  cloud:
    gateway:
      routes:
      - id: retry_test
        uri: http://localhost:8080/flakey
        predicates:
        - Host=*.retry.com
        filters:
        - name: Retry
          args:
            retries: 3
            statuses: BAD_GATEWAY
            methods: GET,POST
            backoff:
              firstBackoff: 10ms
              maxBackoff: 50ms
              factor: 2
              basedOnPreviousValue: false
            jitter:
              randomFactor: 0.5
            timeout: 100ms

注意

Retry 过滤器与 forward: 前缀的 URL 一起使用时,应仔细编写目标端点。 在发生错误的情况下,目标端点不应执行任何可能导致响应被发送到客户端并已提交(committed)的操作。 例如,如果目标端点是一个带注解的 Controller,则目标 Controller 方法不应返回带有错误状态码的 ResponseEntity。 相反,它应该抛出一个 Exception 或发出的错误信号(例如,通过 Mono.error(ex) 返回值),以便 Retry 过滤器可以捕获并处理重试。

注意

使用 Retry 过滤器时,它将重试紧随其后的所有过滤器。请确保位于 Retry 过滤器之后的过滤器在多次执行时结果符合预期(即它们应当是幂等的)。

警告

当对任何带有请求体(Body)的 HTTP 方法使用 Retry 过滤器时,请求体将被缓存,这可能会导致网关内存受限(OOM 风险)。 请求体缓存在由 ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR 定义的请求属性中。对象的类型是 org.springframework.core.io.buffer.DataBuffer

可以使用简化的“快捷方式”表示法,仅指定 statusmethod

以下两个示例是等效的:

application.yml

yaml
spring:
  cloud:
    gateway:
      routes:
      - id: retry_route
        uri: https://example.org
        filters:
        - name: Retry
          args:
            retries: 3
            statuses: INTERNAL_SERVER_ERROR
            methods: GET
            backoff:
              firstBackoff: 10ms
              maxBackoff: 50ms
              factor: 2
              basedOnPreviousValue: false
            jitter:
              randomFactor: 0.5
            timeout: 100ms

      - id: retryshortcut_route
        uri: https://example.org
        filters:
        - Retry=3,INTERNAL_SERVER_ERROR,GET,10ms,50ms,2,false,0.5,100ms

补充教学 —— 如何优雅地配置重试?

1. 什么是 Backoff(退避)? 如果服务器挂了,不要立即疯狂重试,否则可能会把它彻底压垮(雪崩效应)。 “退避”就是“歇一会儿再试”。

  • Exponential Backoff(指数退避):越试越慢。第一次歇 10ms,第二次歇 20ms,第三次歇 40ms... 让服务器有喘息的机会。

2. 什么是 Jitter(抖动)? 如果 1000 个用户同时重试,并且都等待严格的 10ms,那么 10ms 后服务器会突然收到 1000 个请求,再次崩溃。 “抖动”就是加点随机数。比如在 5ms ~ 15ms 之间随机选一个时间重试,把流量错峰打开。

3. 内存爆炸警告 千万小心对 上传文件大 Body 请求 配置重试。 Spring Cloud Gateway 为了能够重发请求,必须把 Request Body 缓存在内存里。如果你允许重试一个 100MB 的文件上传请求,内存立马就少 100MB。并发一高,网关直接 OOM(内存溢出)挂掉。

最佳实践

  • 只对 幂等 的请求(如 GET)开启重试。
  • 对 POST/PUT 请求开启重试时要极其谨慎,确保业务逻辑支持重复提交,且 Payload 不大。
  • 一定要配置 timeout,防止重试导致请求响应时间过长,拖死客户端。

Based on Spring Framework.