http1.1与http2.0
简介
http1.0: 1.0版本中每个TCP连接只能发送一个请求,数据发送完毕连接就关闭,如果还要请求其他资源,就必须重新建立TCP连接。(TCP为了保证正确性和可靠性需要客户端和服务器三次握手和四次挥手,因此建立连接成本很高)
http1.1:
长连接:新增Connection字段,默认为keep-alive,保持连接不断开,即 TCP 连接默认不关闭,可以被多个请求复用;
管道化:在同一个TCP连接中,客户端可以发送多个请求,但响应的顺序还是按照请求的顺序返回,在服务端只有处理完一个回应,才会进行下一个回应;
host字段:Host字段用来指定服务器的域名,这样就可以将多种请求发往同一台服务器上的不同网站,提高了机器的复用,这个也是重要的优化;
http2.0:
二进制格式:1.x是文本协议,然而2.0是以二进制帧为基本单位,可以说是一个二进制协议,将所有传输的信息分割为消息和帧,并采用二进制格式的编码,一帧中包含数据和标识符,使得网络传输变得高效而灵活;
多路复用:2.0版本的多路复用多个请求共用一个连接,多个请求可以同时在一个TCP连接上并发,主要借助于二进制帧中的标识进行区分实现链路的复用;
头部压缩:2.0版本使用使用HPACK算法对头部header数据进行压缩,从而减少请求的大小提高效率,这个非常好理解,之前每次发送都要带相同的header,显得很冗余,2.0版本对头部信息进行增量更新有效减少了头部数据的传输;
服务端推送:在2.0版本允许服务器主动向客户端发送资源,这样在客户端可以起到加速的作用;
性能比较
官方demo:https://http2.akamai.com/demo
自测demo:http1.1:https://47.95.8.93:441 , http2.0: https://47.95.8.93:442
pingdom 测试结果:
Tokyo-load-time(s) | London-load-time(s) | Page-size(KB) | Requests | |
---|---|---|---|---|
http1.1 | 4.16~4.75 | 14.79~17.54 | 779.6 | 257 |
http2.0 | 3.79~4.33 | 5.78~6.54 | 745.5 | 257 |
本地demo:http1.1: https://localhost:441, http2.0: https://localhost:442(参见:http1-vs-http2)
什么场景下http2.0性能提升明显?
时延(ms) | 带宽(Mbit/s) | load-time(s) | Requests | |
---|---|---|---|---|
http1.1 | 100 | – | 4.65 | 257 |
http2.0 | 100 | – | 0.79 | 257 |
http1.1 | – | 1 | 7.17 | 257 |
http2.0 | – | 1 | 8.77 | 257 |
http1.1 | 100 | 1 | 7.19 | 257 |
http2.0 | 100 | 1 | 10.10 | 257 |
http1.1 | 100 | 5 | 4.75 | 257 |
http2.0 | 100 | 5 | 2.29 | 257 |
http1.1 | 200 | 5 | 9.14 | 257 |
http2.0 | 200 | 5 | 2.48 | 257 |
可以看到http2.0针对一些网站并非像官方提供的demo中提升巨大,这是因为不同的网络环境有不同的结果,这里先给出结论:
结论:http2.0针对网络延时优化更好,但同时网络带宽也需要相对较大,如果网络带宽足够,请求数量大,请求静态资源多,http2.0相对于http1.1提升明显
提升原因
影响网络性能的关键因素:“带宽” 和 “延时”
Mike Belshe关于网络性能及其影响因素做了测试,可以看到:按照目前网络发展速度,带宽提升带来的收益远远小于延时优化带来的收益,每20毫秒的延迟提高,页面加载时间就会近似线性提高!Mike Belshe的这项研究是谷歌开发SPDY协议的起点,该协议后来成为HTTP/2协议的基础。
事实证明,对于大多数Web应用程序来说,带宽不是限制性能的因素。相反,瓶颈是客户端和服务器之间的网络往返延迟。
二进制分帧层:— http2.0的基石
在二进制分帧层上,http2.0会将所有传输信息分割为更小的消息和帧,并对它们采用二进制格式的编码将其封装,新增的二进制分帧层同时也能够保证http1.X的各种动词,方法,首部都不受影响,兼容上一代http标准。其中,http1.X中的首部信息header封装到Headers帧中,而request body将被封装到Data帧中。
HTTP/2中最小的通信单元,每个单元都包含一个帧头,该帧头至少标识帧所属的流。
所有通信都通过单个TCP连接进行,该连接可以承载任意数量的双向流。
每个流都有一个唯一的标识符和可选的优先级信息,用于传输双向消息。
每条消息都是逻辑HTTP消息,如请求或响应,由一个或多个帧组成。
帧是承载特定类型数据的最小通信单元——例如HTTP标头、消息有效负载等。来自不同流的帧可以交错,然后通过每个帧标题中的嵌入式流标识符重新组装。
多路复用:—连接共享
使用HTTP/1.x,如果客户端想提出多个并行请求来提高性能,则必须使用多个TCP连接。这是HTTP/1.x框架的直接后果,该模型确保每个连接一次只能交付一个响应(响应排队)。更糟糕的是,这也会导致线头阻塞和底层TCP连接的使用效率低下。
HTTP/2中新的二进制帧层允许客户端和服务器将HTTP消息分解为独立帧,将它们交织在一起,然后在另一端重新组装它们,从而实现完整的请求和响应复用,这是HTTP/2最重要的增强功能。
TTFB:表示客户端从发出请求后到收到服务器响应的第一个字节的时间,即包含了一个c/s的网络来回时间和服务器处理请求的时间
可以看到http1.1在一个TCP连接中只有等一个请求处理完成之后才能处理下一个请求,而http2.0依赖于二进制分帧层和多路复用技术可以同时并行处理请求,减少了http1.1中的阻塞问题,这也是http2.0对网络时延优化好的重要原因;
http1.1协议中请求一个服务端一般允许开放6个tcp连接,而http2.0只有1个tcp连接,虽然节省了资源,但是在比较特殊的场景:小时延(忽略不计),小带宽的场景中,http1.1相当于6个管道下载资源,http2.0则是一个管道,此时http2.0的加载速度反而不如http1.1;
当然这种场景如今已经不多见了,随着互联网的高速发展,带宽已经不是影响响应的主要因素,大部分的情况下,延迟是影响响应速度的主要因素。
流优先级
把http消息分为很多独立帧之后,就可以通过优化这些帧的交错和传输顺序进一步优化性能,HTTP/2标准允许每个流具有相关的权重和依赖性:分配处理资源和客户端与服务器间的带宽,不同优先级的混合也是必须的。客户端会指定哪个流是最重要的,有一些依赖参数,这样一个流可以依赖另外一个流。优先级别可以在运行时动态改变,当用户滚动页面时,可以告诉浏览器哪个图像是最重要的,你也可以在一组流中进行优先筛选,能够突然抓住重点流(偏向但并不是绝对的优先)。
优先级最高:主要的html
优先级高:CSS文件
优先级中:js文件
优先级低:图片
每个服务器源一个链接
受益于的二进制框架,HTTP/2不再需要使用多个TCP并行连接;每个流被拆分为多个帧,可以并行、交错和优先排序。所有HTTP/2连接都是持久的,每个源只需要一个连接,通过重用相同的连接,HTTP/2既能更有效地利用每个TCP连接(TCP慢启动),又能显著减少整体协议开销,有助于提高吞吐量和降低运营成本。
减少连接数量是提高HTTPS部署性能的一个特别重要的功能:这意味着减少昂贵的TLS握手,更好的会话重用,以及全面减少所需的客户端和服务器资源。
在特定场景中,多个TCP连接可能证明是有益的。然而,HTTP/2的实验证据表明,单个连接是首选策略
头部压缩
每个HTTP传输都包含一组标头,描述传输的资源及其属性。在HTTP/1.x中,此元数据始终以纯文本形式发送,每次传输添加500-800字节的开销,如果使用HTTP Cookie,有时会增加千字节;HTTP/2使用HPACK压缩算法压缩请求和响应头元数据,HTTP/2的HPACK算法使用一份索引表来定义常用的http Header,把常用的 http Header 存放在表里,请求的时候便只需要发送在表里的索引位置即可。
服务端推送
HTTP/2的另一个强大的新功能是服务器能够为单个客户端请求发送多个响应。也就是说,除了响应原始请求外,服务器还可以向客户端推送其他资源,而无需客户端请求每个资源!
升级难度
根据上述得到的结论:HTTP2.0主要针对网络时延的优化,在不考虑网络延时的情况下,HTTP1.1与HTTP2.0性能相差不大,甚至HTTP1.1性能更好。对于在服务端内部:是否要升级HTTP2.0,个人理解,服务端服务器本身相近,甚至反向代理前后端服务部署在同一台服务器,本身就没有时延,升级带来的优化并不会有大跨度提升;
注:【在互联网架构中,web 服务器:一般指像 nginx,apache 这类的服务器,他们一般只能解析静态资源。应用服务器:一般指像 tomcat,jetty,resin 这类的服务器可以解析动态资源也可以解析静态资源,但解析静态资源的能力没有 web 服务器好。一般只有 Web 服务器才能被外网访问,应用服务器只能内网访问。】
如果想尝试在服务端内部使用HTTP2.0,也可以进行相关配置,HTTP2.0有两种协议版本:H2C和H2,其中:
H2C是HTTP2.0的明文版本,不需要经过证书认证,按理说这是服务端进行内部调用的正确选择,然而在Spring boot 2.0的官方文档来看,它明确指出“Springboot不支持h2c“,如果想使用springboot支持h2c可以参考这篇文章;
springboot虽然支持H2协议,但其有诸多限制:首先使用H2的条件是支持HTTPS,这就需要后端服务的调用进行证书认证,这就不尽合理;其次,大部分后端服务现在仍在使用Java1.8,但是在原生的JDK8中是不支持H2协议的,直到JDK9,Java自带的HTTP client(HttpURLConnection)才支持H2,因此还需要选择支持HTTP/2的应用服务器:
Undertow 1.4.0+:如果您使用Java 8,则无需额外的配置来支持HTTP2。
Jetty 9.4.11:如果您使用Java 8,您还需要加密类库,并需要依赖Jetty的以下两个模块:
org.eclipse.jetty:jetty-alpn-conscrypt-server org.eclipse.jetty.http2:http2-server
Tomcat 9.0.x:如果您使用Java 8,您还需要单独下载libtcnative类库(使用APR连接器并将升级协议设置为Http2Protocol),并在启动Tomcat时添加JVM启动参数,如下所示:
-Djava.library.path=/usr/local/opt/tomcat-native/lib
Tomcat 9.0.x:如果您使用Java 9,则不需要额外的配置来支持HTTP2。然而springboot2默认的tomcat是8.5+,
具体的详细配置请参见这边文章
目前项目中常用的微服务之间的调用工具Openfeign、restTemplate工具底层都使用了HTTP client,默认都是JavaJDK中的HttpURLConnection,但可以进行替换第三方的HTTP Client使用,常见的HTTP client:
基于HttpURLConnection的SimpleBufferingClientHttpRequest和SimpleStreamingClientHttpRequest,不支持HTTP2
基于OkHttpClient的OkHttp3ClientHttpRequest,支持HTTP2
基于Apache HttpComponents HttpClient,不支持HTTP2
基于Netty HttpClient的ReactorClientHttpConnector(Netty4ClientHttpRequest已过时),支持HTTP2(还需要第三方APLN实现)spring5中新提供的webclient,默认底层使用Netty,内置支持Reactor反应性HttpClient实现,目前不支持HTTP2。
同时,也可以通过编码的方式实现ClientHttpConnector接口自定义新的底层库;如切换Jetty实现
综上所述:后端服务,服务服务之间没有必要使用HTTP2.0协议,整体来看,整体环境支持体系并不完善,且在小时延场景下,性能并不会有大幅提升,更重要的是HTTP2.0是基于HTTPS的协议,在后端服务之间使用并不合适,如果优化不当,甚至适得其反;
应用HTTP2.0
如果你使用 SSL/TLS(简称 TLS),那么 HTTP/2 可以提升网站性能。如果你没有,那在使用 HTTP/2 之前要先支持 TLS。这时候,使用 TLS 的性能损耗大致可以被使用 HTTP/2 的性能提升抵销。不过还是建议你在实际应用之前先测试一下。
事实上,部署 HTTP/2 并不难。如果使用 NGINX,只要在配置文件中启动相应的协议就可以了。浏览器和服务器会协商采用什么协议,如果浏览器支持 HTTP/2(而且也在使用 TLS),就会使用 HTTP/2。
HTTP/2 要求 Nginx 1.9.5+,,OpenSSL 1.0.2+
nginx配置http2.0:
server {
listen 442 ssl http2;
#证书
ssl_certificate /usr/local/etc/nginx/ssl-cert.pem;
ssl_certificate_key /usr/local/etc/nginx/ssl-key.pem;
add_header Cache-Control no-store; #浏览器加载不使用缓存
location / {
root /usr/local/share/nginx/html;
index index2.0.html;
}
}
HTTP的应用程序语义相同,没有对提供的功能或核心概念进行更改,如HTTP方法、状态代码、URI和标头字段
性能瓶颈:启用http2.0后会给性能带来提升,但同时也会带来新的性能瓶颈。因为现在所有的压力集中在底层一个TCP连接之上,TCP很可能就是下一个性能瓶颈,比如TCP分组的队首阻塞问题,单个TCP packet丢失导致整个连接阻塞,无法逃避,此时所有消息都会受到影响。未来,服务器端针对http 2.0下的TCP配置优化至关重要。
前端改动:前端针对http1.1的优化可能不在需要