Spring Reactive Webclient 的请求级背压?

Posted

技术标签:

【中文标题】Spring Reactive Webclient 的请求级背压?【英文标题】:Request-level backpressure for Spring Reactive Webclient? 【发布时间】:2019-06-24 13:22:52 【问题描述】:

这类似于How to do akka-http request-level backpressure?,但用于 Spring 回声系统。

我正在考虑在以响应方式使用 Spring WebClient 时如何为 HTTP 客户端实现背压。对我来说,这听起来像是让 WebClient 了解 HTTP 语义并对例如应用背压的方式。状态“429 - 请求过多”。我没有找到任何关于此的文档,这让我有点怀疑这是否是要走的路。

问题:

    基于 HTTP 响应标头的背压是否有意义(例如,基于 429 或 503 状态代码和 Retry-After 标头)?或者有没有更好的方法通过 HTTP 对非流式(请求-响应)用例进行反压? 是否在 Webclient 或其他与 Spring 反应式回声系统配合良好的库中实现了类似的功能? 如果目前不存在这样的情况并且考虑到它是有意义的,那么简单地使用 Retry-After 标头中设置的超时重试是否有意义?

【问题讨论】:

【参考方案1】:

在实现 Spotify API 客户端时,我遇到了同样的挑战。 我需要根据错误响应进行动态退避。

我就是这样做的:

webClient
    ... // you request
    .onStatus(status -> status.equals(HttpStatus.TOO_MANY_REQUESTS), this::exctractBackOffException) // e.g. build your exception with backoff response value
    .retryWhen(Retry.withThrowable(throwableFlux ->
                    throwableFlux.map(throwable ->
                    
                        int backoff = // exctract from throwable
                        return Retry.backoff(2, Duration.ofSeconds(backoff));
                    )))
    ...

代替Retry.backoff() 在里面,你可以构建任何重试。关键是您可以在知道服务器提出的值的情况下动态构建它。

希望这个示例有用。

【讨论】:

【参考方案2】:

TL;DR:Spring Framework 和 Reactor Netty 不提供这种支持,我不知道有任何库提供这种支持。

您可以使用WebFilter 来实现您所描述的行为,该WebFilter 在传入请求被分派到处理程序之前拦截它们并使用您选择的任何HTTP 状态/标头进行回复。

唯一棘手的部分是决定是否应该拒绝请求。您可以配置一个不超过的固定吞吐量,或者依赖其他一些 JVM 指标?

现在我不会称之为“背压”,至少在 Spring 的上下文中不会。在反应式流中,背压大致意味着消费者向生产者提供有关它可以发送的消息数量的信息。根据规范,客户端不能发送超过允许数量的消息。

在 Spring 中的 HTTP 上下文中,我们在接受新连接时不强制执行背压,但在读取/写入 TCP 缓冲区时会使用此信息。这些信息不会通过网络,所以我们这里只是依靠 TCP 流控制。

如果你想在协议中支持真正的背压,你需要在协议本身中支持它。这就是 Spring 中的 the future RSocket support 的全部意义所在。

【讨论】:

以上是关于Spring Reactive Webclient 的请求级背压?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Spring Security OAuth 时 Spring Boot Reactive WebClient “serverWebExchange must be null”

spring 5 webclient使用指南

Spring reactive WebClient GET json response with Content-Type "text/plain;charset=UTF-8"

Spring Webflux Webclient |内容类型标题设置问题

Spring WebClient vs. RestTemplate

Spring WebClient 作为 RestTemplate 的替代品