当前位置: > Linux新闻 >

HTTP/2 最后通牒

时间:2014-10-19 23:22来源:linux.it.net.cn 作者:it
IETF HTTP 工作组对提出的HTTP/2标准发布了最后的通告,这意味着在提交到RFC成为草案之前,已经进入了开放社区的审查流程。jetty已经实现了该协议,并且在这个站点中成功运行。关于这个标准已经拥有了很多的赞美之词,但是我仍然对这个协议一些丑陋的地方保留意见。

HTTP/2 是google开发的 SPDY协议的一个子集,在SPDY的照耀下,HTTP/2有着以下显而易见的优点。

特点:

    HTTP/2 支持RFC7230中指明的HTPP/1.1的所有语义。这使得可以在不改变任何代码的情况下,仅仅通过升级客户端和服务器端的基础结构来获得HTTP/2的优点。

    HTTP/2 是一个可以在同一个TCP/IP连接中同时发起多个request,接收多个response的复用协议。它可以区分不同的response,因此将不会遇到HTTP/1.1中存在的Head of Line Blocking问题。所以,当需要多个资源渲染页面时,客户端将不再因为服务质量而向同一个目标服务器发起多个连接来获取资源。这意味着将显著减少服务器所消耗的资源以及负载均衡软件的sticky session问题。

    HTTP header字段是非常累赘和多余的。HTTP/2 为HTTP量身定制一个高效的压缩算法(HPACK)来避免使用TSL协议时使用一般压缩算法导致的安全问题。减少header字段的使得在一个新创建的TCP/IP连接上可以一次性发送多个request,避免了因拥塞控制窗口的增长到限定值而导致的等待。这能显著地减少渲染页面时的网络往返次数。

    HTTP/2 支持推送资源,因此后端服务器可以预估相关资源的请求并且推送它们到客户端的缓存中,进一步节省了网络的往返次数。

你可以通过这些关键特性看到,HTTP/2 主要注重于提升渲染页面的速度,这是一个很好的关注点(与 book of speed   观点相同)。在一定程度上,这个处理过程还考虑到了吞吐量和服务器资源,但是这不是关键因素,实际上在HTTP/2协议下的数据传输过程中,服务器还会因此而受苦,因为服务器需要为每一个连接提供更多的资源,这个资源消耗量比降低连接数而节约下来的资源还要多。(译者注:原文through put 是写错了,正确的是 throughput,吞吐量的意思 )。
 

劣势


只能使用一个!(二选一的意思)

当工作组被特许解决滥用HTTP1.1作为底层传输(比如 long polling 即长轮询)的时候,并没有考虑到其他工作组关于 HTTP/2.0兼容WebSocket语义的扩展。当 websocket over http2 的草案开始撰写时,一些草案中引用的特点随后被移除出HTTP/2,因为HTTP/2主要着重于提供HTTP的语义。

拟议中的协议没有明确划分框架层和HTTP语义。HTTP语义可以由框架层携带。我很期待看到一个明确的多路复用、流控制的框架层,可用于许多不同的语义包括HTTP和webSocket。相反,我们有一个框架协议主要针对HTTP。下面的话引用于草案:

我对合并层是否有显著性效果表示半信半疑,我相信这样的设计会使得它更难于在http2帧层上携带WebSocket或者其它新的网络语义。HTTP语义很难被封装进帧,所以中间代理(路由器、集线器、负载平衡器、防火墙等)将被部署,那样将让HTTP语义异常怪异。任何未来的网络语义能够在未来的网络上传输的唯一方法就是将它伪装成HTTP这个小窍门,不过这的确是对底层传输层的滥用,这也是HTTP/2准备解决的问题。我知道这很难从一个例子中概括出来,但是今天我们在网络上广泛的使用HTTP和WebSocket,所以在设计下一代的网络层时已经意识到要考虑两个例子对等。
 

Meta Data Meltdown

在早期的协议版本中,对于头部有了一个压缩的算法,这个算法应对一个流的头部的加密/解密对于另外的一个头部加密/解密高质量的完成。这样产生出这样一个限定的协议,阻止头部帧传播到其他帧当中,而且,头部会会拒绝多路控制算法,因为一旦加密传播不能被推迟没有停止,对于其他的加密/解密。

提出的标准有了小状态的压缩算法,以至于现在在技术上面可能插入一些帧在头部的一些信息中,他仍旧不能做到控制流的头部,但是没有这样技术的话,会使得和其他的流对接时候形成一定的阻碍,然而这样的服务工作的提升还是值得期待的,只是还需要具体的商议一下插入的价值和关于插入信息的规范

HTTP/2鼓励将应用程序将大量数据移到头部,因为这样数据可以有效的控制整个多路复用的连接,并且以全速传输,而不管任何的http2流控制窗口或者其它需要处理的流。如果应用程序采取这个措施,由多路利用连接提供的服务质量遭受考验,并且HTTP/2着手解决的对头阻塞问题将变成大量头部帧数据影响TCP/IP控制流,然后停止所有流。当它真的发生时,客户端将做在HTTP/1.1时所做的事,忽略任何关于连接限制的规格,然后只管打开更多的连接,这样请求将压倒其它使用大头部来尝试获得共享连接中不公平比例的流。这对服务器来说是场空难,因为这不止会增加HTTP/2连接所需的资源,还会让HTTP/1.1需要多路连接。

我宁愿我是在这儿夸大事实,并且预测一场永远不会发生的灾难。然后HTTP/1.1以来的历史证明速度才是王道,所以厂商准备打破标准,将压力至于服务器端,这样应用程序将在它们的浏览器上跑得更快些,即使这样仅仅持续到其它厂商授受同样的恶习。我觉得我们不必担心这个悲剧协议不能够保护厂商免遭无论如何都需要做防护的DoS攻击。

 

协议设计有许多方面都是丑陋的.但是不幸的是,尽管工作组中有许多人都认同协议确实很丑陋,但是IETF审阅并没有考虑审美要求,认定当前的草案没有问题(尽管许多人争论,丑陋之处意味着将会有许多误解和欠缺的协议实现).我将引用一个主要的点作为例子:

这是结束吗?

一个经典的设计丑陋之处是使用END_STREAM标识.多路复用的流是由一个序列的帧组成,其中一些带有END_STREAM标识,意味着那个方向的流正结束.在下面的图中,草案描述了结果状态机图:

                        +--------+
                  PP    |        |    PP
               ,--------|  idle  |--------.
              /         |        |         \
             v          +--------+          v
      +----------+          |           +----------+
      |          |          | H         |          |
  ,---| reserved |          |           | reserved |---.
  |   | (local)  |          v           | (remote) |   |
  |   +----------+      +--------+      +----------+   |
  |      |          ES  |        |  ES          |      |
  |      | H    ,-------|  open  |-------.      | H    |
  |      |     /        |        |        \     |      |
  |      v    v         +--------+         v    v      |
  |   +----------+          |           +----------+   |
  |   |   half   |          |           |   half   |   |
  |   |  closed  |          | R         |  closed  |   |
  |   | (remote) |          |           | (local)  |   |
  |   +----------+          |           +----------+   |
  |        |                v                 |        |
  |        |  ES / R    +--------+  ES / R    |        |
  |        `----------->|        |<-----------'        |
  |  R                  | closed |                  R  |
  `-------------------->|        |<--------------------'
                        +--------+
     H:  HEADERS frame (with implied CONTINUATIONs)
     PP: PUSH_PROMISE frame (with implied CONTINUATIONs)
     ES: END_STREAM flag
     R:  RST_STREAM frame


那看上去足够简单了,一条流在发送或收到END_STREAM标记前都将被打开,那时候流呈半关闭状态,然后当另一个END_STREAM标记被收到或发送出去后流将完全关闭。别急,还没完!在发出一帧带着END_STREAM标记的数据后,流还可以继续发送几帧类型数据,这些帧数据会包含语义数据(追踪者们)或者必须以此行事的协议行为(做出承诺),以及一些可以简单地被忽略的帧。这使得草案相当复杂,以至于需要7段密密麻麻的文字来说明帧数据的处理必须在一进入关闭状态时完成。看上去TCP/IP好像已经被指定不带CLOSE_WAIT。更糟糕的是你似乎可以在一个socket已经关闭后继续后送紧急的数据。

这个情况已经发生了,这是由于HTTP语义和组帧层的结合所致.表面上END_STREAM是一个由组帧层解释的标识,实际上,这个标识是帧类型的一个函数.这个特别的帧类别,在组帧层的其它标识之前被解释.根据HTTP语义,在一些特别的帧类型上面终止流才是合法的.所以,END_STREAM标识只放到一些特定的帧类型上,以增强部分HTTP帧类型定序(这种情况是要停止一个推送响应流).增强合法类型的定序通常是无意义的尝试,因为有无数的不合法的序列,这些序列必须检查实现并让它们无法发送.只有一些序列让状态机变得复杂,并让未来的非HTTP语义更加困难.这真的是WTF时刻,当你认识到,有效的元数据可以在一个帧中使用END_STREAM标识发送.同时,你需要解释特定的帧类型,以定位实际的流终止之处.



 

(责任编辑:IT)
------分隔线----------------------------
栏目列表
推荐内容