【问题标题】:HTTP 1.1 PipeliningHTTP 1.1 流水线
【发布时间】:2011-03-18 21:58:39
【问题描述】:

我必须在 Java 中实现一个 HTTP 客户端,并且根据我的需要,似乎最有效的方法是实现 HTTP 管道(根据 RFC2616)。

顺便说一句,我想通过管道发送 POST。 (另外,我不是在谈论多路复用。我在谈论流水线,即在接收任何响应批处理 HTTP 请求之前通过一个连接进行许多请求)

我找不到明确声明它支持流水线的第三方库。但我可以使用例如Apache HTTPCore 构建这样的客户端,或者如果我必须自己构建它。

我的问题是这是否是个好主意。我没有找到任何权威参考资料表明 HTTP 流水线不仅仅是一种理论模型,而是由 HTTP 服务器正确实现的。此外,所有支持流水线的浏览器都默认关闭此功能。

那么,我应该尝试实现这样的客户端,否则由于服务器的实现(或代理),我会遇到很多麻烦。是否有任何参考资料提供这些指导?

如果这是一个坏主意,那么提高效率的替代编程模型是什么?分离 TCP 连接?

【问题讨论】:

  • 不是你所需要的,但是 serf 是一个实现 HTTP 流水线的 C 库code.google.com/p/serf 我不能 100% 确定它是否支持流水线帖子。
  • 谢谢,我得用java做
  • @user384706 从未尝试过 serf,但如果确实做到了您想要的并且其他一切都失败了,那么您可以随时尝试 JNI/JNA。
  • @ luiscubal 谢谢,但我的问题是,如果我什至使用 JNI/JNA 使用 serf,服务器或代理是否正确支持流水线,或者我会遇到麻烦吗?例如我的理解是 apache HTTPClient 故意不支持流水线。找不到权威的参考资料或具体的例子来证明它是一个实际用于提高性能的功能。
  • 供参考:“支持流水线的基于 Java 的 HTTP 客户端”-stackoverflow.com/questions/2777005/…

标签: java http rfc2616 pipelining


【解决方案1】:

POST 不应流水线化

8.1.2.2 流水线

支持持久化的客户端 连接可以“管道”它的 请求(即,发送多个请求 无需等待每个响应)。一种 服务器必须将其响应发送到 这些请求的顺序相同 请求已收到。

假定持久的客户端 立即连接和管道 建立连接后应该 准备好重试他们的连接 如果第一次流水线尝试失败。 如果客户端进行这样的重试,它必须 在它知道之前不是管道 连接是持久的。客户必须 也准备重新发送他们的 请求服务器是否关闭 连接之前发送所有 相应的回应。

客户端不应该管道请求 使用非幂等方法或 方法的非幂等序列 (见第 9.1.2 节)。否则,一个 运输提前终止 连接可能导致不确定 结果。客户希望发送 非幂等请求应该等待 发送该请求,直到它有 收到响应状态 以前的请求。

http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html

【讨论】:

  • 感谢您的回复。但不应意味着:根据 rfc 2119,“当特定行为可接受甚至有用时,在特定情况下可能存在正当理由”。这是其中一种情况。除非在 SHOULD NOT 定义中有暗示,否则我无法理解
  • @user384706 如果你的请求实际上是幂等的,也许你真的在做 PUT?
  • @user384706,这意味着当您管道发布时,糟糕的服务器可能会打嗝。但确实,这不是你的错,但是当事情不工作时,事情就不工作了。不管是谁的错。
【解决方案2】:

我已经实现了一个流水线 HTTP 客户端。基本概念听起来很简单,但错误处理非常困难。性能提升是如此微不足道,以至于我们很久以前就放弃了这些概念。

在我看来,这对正常的用例没有意义。只有当请求具有逻辑连接时,它才有一些好处。例如,您有一个 3 个请求的事务,您可以将它们全部发送。但通常情况下,如果可以流水线化,您可以将它们组合成一个请求。

以下只是我能记住的一些障碍,

  1. TCP 的 keepalive 不能保证持久连接。如果连接中有 3 个请求,服务器会在第一次响应后断开连接。您应该重试接下来的两个请求。

  2. 当您有多个连接时,负载平衡也很棘手。如果没有空闲连接,您可以使用繁忙连接或创建一个新连接。

  3. 超时也很棘手。当一个请求超时时,您必须丢弃所有请求,因为它们必须按顺序返回。

【讨论】:

  • @ZZ 编码器 谢谢!在您的客户端中,您是否也通过管道传输 POST?我的情况不正常。我想流水线实时 POST 触发呼叫中心的操作。感谢您可能记得的任何信息,尤其是有关服务器/代理行为的信息!
  • 是的。它处理 POST。除了在实现重试逻辑时必须记住 body 之外,没有什么区别。
  • @ZZ Coder - 关于 1:在 HTTP 的情况下,无论如何您都必须实现重试逻辑,并且管道连接的重试逻辑没有太大不同(唯一的事情是在重试的情况下管道中断后,您必须等待第一个响应才能查看它是否是管道连接)。现在大多数服务器都默认启用了流水线,所以除了非常糟糕的网络连接之外,我猜应该不会经常发生流水线丢失
  • @ZZ Coder - 关于 3:你能详细说明它的棘手之处吗?这听起来不太棘手。顺便说一句,有些 HTTP 客户端默认启用了流水线(msdn.microsoft.com/en-us/library/…)——我猜使用这些客户端应该相当简单。超时 -> 重试,就像 1.)
【解决方案3】:

流水线对 http 服务器几乎没有影响;他们通常以串行方式处理连接中的请求 - 读取请求,写入响应,然后读取下一个请求......

但客户端很可能会通过多路复用来提高吞吐量。网站通常有多台机器多cpu,为什么要自愿将您的请求限制在一行?今天更多的是关于水平可伸缩性(并发请求)。当然,最好对其进行基准测试。

【讨论】:

  • 在流水线中,至少根据定义,交互不是串行的,因为请求是分批出现的。另外,如果对同一服务器的打开连接数有限制怎么办?
  • 在使用高延迟连接(拨号)时,一切都不同了;当它是一个“长胖管”(卫星)时更是如此。它避免了多个 TCP 连接的开销,但保留了大部分优点。
猜你喜欢
  • 2018-11-25
  • 1970-01-01
  • 2016-04-01
  • 2012-07-31
  • 1970-01-01
  • 2012-01-08
  • 2011-07-04
  • 1970-01-01
  • 2011-01-25
相关资源
最近更新 更多