Request-level Spring Reactive Webclient 的背压?
Request-level backpressure for Spring Reactive Webclient?
这与 类似,但适用于 Spring 回显系统。
我正在考虑在以反应方式使用 Spring WebClient 时如何为 HTTP 客户端实现 back-pressure。对我来说,这听起来像是让 WebClient 了解 HTTP 语义并对例如应用背压。状态“429 - 请求太多”。我没有找到任何关于此的文档,这让我有点怀疑这是否是可行的方法。
问题:
- 基于 HTTP 响应 header 的反压是否有意义(例如,基于 429 或 503 状态代码和
Retry-After
header)?或者对于 non-streaming (request-response) 用例 ? 是否有更好的方法通过 HTTP 执行 back-pressure
- 是否在 Webclient 或其他一些与 Spring 反应式 echo-system 配合良好的库中实现了类似的东西?
- 如果目前不存在这样的东西并且考虑到它有意义,那么简单地重试
Retry-After
header 中设置的超时是否有意义?
TL;DR: Spring Framework 和 Reactor Netty 不提供这种支持,我不知道有任何库提供这种支持。
您可以使用 WebFilter
来实现您所描述的行为,它会在传入请求分派给处理程序之前拦截它们,并使用您选择的任何 HTTP status/header 进行回复。
唯一棘手的部分是决定是否应该拒绝请求。您可以配置一个不超过的固定吞吐量,或者依赖于其他一些 JVM 指标?
现在我不会称它为 "backpressure",至少在 Spring 的上下文中不会。在反应流中,背压大致意味着消费者向生产者提供有关其可以发送的消息数量的信息。根据规范,客户端发送的消息不能超过允许的数量。
在 Spring 中的 HTTP 上下文中,我们在接受新连接时不强制执行背压,但在 reading/writing 到 TCP 缓冲区时会使用此信息。此信息不通过网络,因此我们在这里仅依赖 TCP 流量控制。
如果你想在协议中支持真正的背压,你需要在协议本身中支持它。这就是 Spring 中的 the future RSocket support 的意义所在。
我在实施 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()
里面,你可以构建任何重试。关键是您可以动态构建知道服务器建议的值。
希望这个样本有用。
这与 类似,但适用于 Spring 回显系统。
我正在考虑在以反应方式使用 Spring WebClient 时如何为 HTTP 客户端实现 back-pressure。对我来说,这听起来像是让 WebClient 了解 HTTP 语义并对例如应用背压。状态“429 - 请求太多”。我没有找到任何关于此的文档,这让我有点怀疑这是否是可行的方法。
问题:
- 基于 HTTP 响应 header 的反压是否有意义(例如,基于 429 或 503 状态代码和
Retry-After
header)?或者对于 non-streaming (request-response) 用例 ? 是否有更好的方法通过 HTTP 执行 back-pressure
- 是否在 Webclient 或其他一些与 Spring 反应式 echo-system 配合良好的库中实现了类似的东西?
- 如果目前不存在这样的东西并且考虑到它有意义,那么简单地重试
Retry-After
header 中设置的超时是否有意义?
TL;DR: Spring Framework 和 Reactor Netty 不提供这种支持,我不知道有任何库提供这种支持。
您可以使用 WebFilter
来实现您所描述的行为,它会在传入请求分派给处理程序之前拦截它们,并使用您选择的任何 HTTP status/header 进行回复。
唯一棘手的部分是决定是否应该拒绝请求。您可以配置一个不超过的固定吞吐量,或者依赖于其他一些 JVM 指标?
现在我不会称它为 "backpressure",至少在 Spring 的上下文中不会。在反应流中,背压大致意味着消费者向生产者提供有关其可以发送的消息数量的信息。根据规范,客户端发送的消息不能超过允许的数量。
在 Spring 中的 HTTP 上下文中,我们在接受新连接时不强制执行背压,但在 reading/writing 到 TCP 缓冲区时会使用此信息。此信息不通过网络,因此我们在这里仅依赖 TCP 流量控制。
如果你想在协议中支持真正的背压,你需要在协议本身中支持它。这就是 Spring 中的 the future RSocket support 的意义所在。
我在实施 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()
里面,你可以构建任何重试。关键是您可以动态构建知道服务器建议的值。
希望这个样本有用。