Spring Reactive Webclient的请求级背压?

时间:2019-01-31 06:24:31

标签: spring spring-boot spring-webflux project-reactor

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

我正在考虑当以响应方式使用Spring WebClient时如何为HTTP客户端实现反压。对我来说,听起来好像要走的路是让WebClient知道HTTP语义并将反向压力施加到例如状态“ 429-太多请求”。我还没有找到任何有关这方面的文档,这使我有点怀疑是否要这样做。

问题:

  1. 基于HTTP响应标头的背压是否有意义(例如,基于429或503状态代码和Retry-After标头)?还是对于非流式传输(请求-响应)用例,有更好的方法通过HTTP施加反压吗?
  2. 在Webclient或其他一些与Spring反应式回声系统配合良好的库中是否实现了这种功能?
  3. 如果当前没有类似的东西存在并且认为有意义,那么简单地重试在Retry-After标头中设置的超时时间是否有意义?

2 个答案:

答案 0 :(得分:4)

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

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

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

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

在Spring的HTTP上下文中,我们在接受新连接时不强制实施反压,但是在读取/写入TCP缓冲区时会使用此信息。这些信息不会跨网络,因此我们在这里仅依靠TCP流控制。

如果要在协议中提供真正的背压支持,则需要在协议本身中提供支持。这就是Spring the future RSocket support的目的。

答案 1 :(得分: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,而不是内部的 Retry.backoff()。关键是您可以在知道服务器建议的值的情况下动态构建它。

希望这个样本有用。