【问题标题】:What's the proper heartbeat/keep-alive technology/layer for Java REST? Http? Tcp? Encoding: chunked?Java REST 的正确心跳/保持活动技术/层是什么?网址? tcp?编码:分块?
【发布时间】:2019-07-19 05:40:16
【问题描述】:

设置:

我们有一个https://Main.externaldomain/xmlservlet 站点,例如,它正在对http://London04.internaldomain/xmlservlet 进行身份验证/验证/地理定位和代理(稍作修改)请求。

根本无法直接访问向最终用户公开的内部域。站点之间的通信偶尔会中断,有时内部域节点会变得不可用/死机。

主站点使用 org.apache.http.impl.client.DefaultHttpClient(我知道它已被弃用,我们正在逐步升级此遗留代码),并将 readTimeout 设置为 10.000 毫秒。 请求和响应具有可变长度的xml有效负载/正文,使用Transfer-Encoding: chunked,也使用Keep-Alive: timeout=15

问题:

有时 London04 实际上需要超过 10 秒(比如说 2 分钟)来执行。有时它会不优雅地崩溃。有时会发生其他(网络)问题。 有时在这 2 分钟内 - response-xml-data 的部分被逐渐填充,部分之间没有 10 秒的间隙,因此永远不会超过 readTimeout, 有时会有 10 多秒的间隔,并且 HttpClient 超时...

我们可以尝试增加 Main 端的超时,但这很容易使侦听器池膨胀/过载(仅通过常规流量,甚至还没有被 DDOS 攻击)。 我们需要一种方法来区分 internal-site-still-working-on-generating-the-response 和它真正崩溃/network_lost/等的情况。 最好的感觉是交流期间的某种心跳(每 5 秒)。

我们认为 Keep-Alive 会拯救我们,但它似乎只能保护请求之间的间隙(而不是在请求期间)而且它似乎没有间隙期间的任何心跳(只是有/waiting_for 超时)。

我们认为分块编码可以通过发送一些心跳(0-bytes-sized-chunks)让对方知道来拯救我们,但似乎没有这样/默认的实现以这种方式支持任何心跳,而且看起来那个 0 字节大小的块本身就是一个 EOD 指标...

问题:

如果我们正确假设 KeepAlive/ChunkedEncoding 不会帮助我们实现 keepAlive/heartbeat/fastDetectionOfDeadBackend,那么:

1) 应该在哪一层实现这样的心跳?网址? tcp?

2) 任何标准框架/库/设置/等已经实现了吗? (如果可能:Java、REST)


更新

我还研究了 WADL/WSDL 的心跳实现器,虽然没有找到 REST,但检查了 WebSockets... 还研究了 TCP-keepalives,这似乎是该任务的正确功能:

但是根据那些我必须设置类似的东西:

  • tcp_keepalive_time=5
  • tcp_keepalive_intvl=1
  • tcp_keepalive_probes=3

这似乎是一个反建议(建议 2 小时,10 分钟已经显示为奇数,5 秒是正常/安全的吗??如果是 - 可能是我的预先解决方案......)

我应该在哪里配置这个?单独在 London04 上还是在 Main 上? (如果我在 Main 上设置它 - 它不会淹没客户端 - >主要前端通信吗?或者站点之间的 NATs/etc 是否会轻易破坏 keepalive 意图/支持?)

附:欢迎任何指向 RTFM 的链接 - 我可能只是遗漏了一些明显的东西 :)

【问题讨论】:

    标签: java rest keep-alive heartbeat tcp-keepalive


    【解决方案1】:

    【讨论】:

    • 来自stackoverflow.com/help/how-to-answer:为链接提供上下文 鼓励链接到外部资源,但请在链接周围添加上下文,以便您的其他用户了解它是什么以及它为什么存在。始终引用重要链接中最相关的部分,以防目标站点无法访问或永久离线。
    • javax.ws.rs.sse 看起来是一个非常可行的选择(除了心跳必须是服务器端驱动的,而不是让客户端响应 i'm-still-here 心跳) -谢谢,将投票。虽然我没有看到 EventBus 是相关的。
    • 现在我遵循你对 EventBus 的意思(看看他们的 over-http-communication-protocol 的 tcpdump 会很有趣),但遗憾的是 vertx 的所有功能都需要它启动一个独立的服务/侦听器(与现有的 webapp 容器分开)。我找到了一个通过 Tomcat 容器代理/桥接它的工作选项,但该选项似乎通过在 vertx 通信之上的预缓冲/等开销来影响 vertx 功能:stackoverflow.com/questions/36432903/deploy-vert-x-on-tomcat 我将坚持使用 WebSockets 的答案,因为易于将现有代码切换到它,谢谢!
    【解决方案2】:

    我的建议是不要使用心跳。让您面向外部的 API 返回一个 303 See Other,其标头指示所需响应何时何地可用。

    所以你可以打电话:

    POST https://public.api/my/call
    

    然后回来

    303 See Other
    Location: "https://public.api/my/call/results"
    Retry-After: 10
    

    如果您的服务器可以猜测构建响应需要多长时间,它应该将其计入Retry-After 值。如果稍后对新位置进行了GET 调用,并且尚未完成构建结果,则返回带有更新的Retry-After 值的响应。所以也许你尝试10,如果这不起作用,你告诉客户再等一个110,总共需要两分钟。

    或者,使用旨在长时间保持开放的协议,例如WebSockets

    【讨论】:

    • 轮询不是一个好的解决方案(尤其是响应缓冲和不可预测的重试后的 RAM 开销)。我们研究了 WebSockets(请参阅问题),但是在您将其作为一个选项重新提出之后 - 发现一些很好的客户端和服务器部分的默认(弹簧)实现可能与我们的代码完全兼容(只有传输正在改变) -会试一试,谢谢!
    • 接受答案的 WebSocket 部分,谢谢!
    猜你喜欢
    • 2011-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    • 2011-12-06
    相关资源
    最近更新 更多