在公司产品中发现某个网页加载速度比较慢,打开F12查看“网络”发现有大概300个并发请求,包括html,js,image,API等,而且很多请求都会排队很长时间,在Chrome中观察每次最多是并发处理6个请求,所以可能是浏览器的行为导致了并发请求处理慢,在网上找到了官方解释,每个浏览器有同域名请求的最大并发限制。如果同时只有6个并发连接数数量,那网页打开的时候只能依赖于这6条线程,前面如果有打开慢的内容,就会直接影响到后面的内容打开。如果同时有更多的并发连接数,这样就会大大的提高网页加载速度。但是浏览器为什么限制并发请求数呢?有过多线程编程经验的开发人员应该明白这个道理,如果浏览器启用太多的线程,线程上下文切换会带来很大的系统开销,过多的连接也会导致操作系统的TCP/IP协议栈资源迅速耗尽,因此负责任的浏览器才有对请求并发数的限制。
浏览器的限制
一些主流浏览器对HTTP 1.1和HTTP 1.0的最大并发连接数目,可以参考如下表格:
浏览器 | HTTP /1.0 | HTTP /1.1 |
---|
IE(6,7) | 2 | 4 |
IE8 | 6 | 6 |
Firefox | 6 | 6 |
Safari | 4 | 4 |
Chrome | 6 | 6 |
Opera | 4 | 4 |
我们通过修改配置也能修改并发连接数,IE就可以通过修改注册表来修改最大并发连接数,很多客户端软件可以修改电脑的最大连接数,比如:迅雷、暴风影音等。
问题分析
既然每种浏览器对于HTTP /1.0和HTTP /1.1都有限制,而且是因为请求排队导致网页加载慢。因此,一种方法是重构代码,尽量把多个请求合并成一个请求,减少请求数。第二种方法就是突破浏览器同源请求并发数的限制。第一种方法,改动比较大,服务器和前端程序都需要重构,代价比较大。因此想从第二种方案入手,了解到HTTP/2可能是一种方案,因为HTTP/2使用的是多路复用技术,支持在同一个TCP连接上发送无限个HTTP请求,且这些请求的生命期可以重叠,因此避免了同源并发个数限制的问题。
初识HTTP/2
HTTP/2 (原名HTTP/2.0)即超文本传输协议 2.0,是下一代HTTP协议。是由互联网工程任务组(IETF)的Hypertext Transfer Protocol Bis (httpbis)工作小组进行开发。是自1999年http1.1发布后的首个更新。HTTP 2.0在2013年8月进行首次合作共事性测试。在开放互联网上HTTP 2.0将只用于https://网址,而 http://网址将继续使用HTTP/1,目的是在开放互联网上增加使用加密技术,以提供强有力的保护去遏制主动攻击。DANE RFC6698允许域名管理员不通过第三方CA自行发行证书。HTTP/2使用的是SPDY协议,下面是维基百科的定义
SPDY(发音如英语:speedy),一种开放的网络传输协议,由Google开发,用来发送网页内容。基于传输控制协议(TCP)的应用层协议 。Google最早是在Chromium中提出的SPDY协议。目前已经被用于Google Chrome浏览器中来访问Google的SSL加密服务。SPDY并不是首字母缩略字,而仅仅是"speedy"的缩写。SPDY现为Google的商标。
SPDY当前并不是一个标准协议,但SPDY的开发组已经开始推动SPDY成为正式标准(现为互联网草案,HTTP/2主要以SPDY技术为主。Google Chrome,Mozilla Firefox,Opera和Internet Explorer[]均已支持SPDY协议。SPDY协议类似于HTTP,但旨在缩短网页的加载时间和提高安全性。SPDY协议通过压缩、多路复用和优先级来缩短加载时间。
HTTP/2优势
多路复用
请求都是通过一个 TCP 连接并发完成。HTTP/1.x 虽然能利用一个连接完成多次请求,但是多个请求之间是有先后顺序的,后面发送的请求必须等待上一个请求返回才能发送响应。这会很容易导致后面的请求被阻塞,而 HTTP/2 做到了真正的并发请求。同时, 流还支持优先级和流量控制。
压缩头部
HTTP/2 对消息头采用 HPACK 进行压缩传输,能够节省消息头占用的网络的流量。而 HTTP/1.x 每次请求,都会携带大量冗余头信息,浪费了很多带宽资源。头压缩能够很好的解决该问题。
二进制传输
HTTP/2 采用二进制格式传输数据,而非 HTTP/1.x 的文本格式。二进制格式在协议的解析和优化扩展上带来更多的优势和可能。HTTP/2引入二进制数据帧和流的概念,其中帧对数据进行顺序标识,浏览器收到数据之后,就可以按照序列对数据进行合并,而不会出现合并后数据错乱的情况。同样是因为有了序列,服务器就可以并行的传输数据,这就是流所做的事情。
Server Push
服务端能够更快的把资源推送给客户端。例如服务端可以主动把 JS 和 CSS 文件推送给客户端,而不需要客户端解析 HTML 再发送这些请求。当客户端需要的时候,它已经在客户端了。
比如说你有一个网站,所有的页面都会在一个名为 styles.css 的外部样式表中,定义各种样式。当用户向服务器请求 index.html 时,我们可以在发送 index.html 的同时,向用户推送 styles.css。
相比等待服务器发送 index.html,然后等待浏览器请求并接收 styles.css,用户现在只需等待1次服务器响应,就可在初次请求同时使用 index.html 和 styles.css。
Nginx中HTTP/2配置
HTTP/2大部分浏览器都已经支持,大部分的Web Server都可以配置,比如Tomcat,Nginx,IIS等。我们的项目使用的是Nginx,下面我介绍一下在Nginx中如何配置HTTP2.
步骤一,安装Nginx
Nginx支持HTTP2需要满足以下三个条件:
- nginx的版本必须在1.9.5以上
- openssl的版本必须在1.0.2e及以上
- Nginx中需要添加--with-http_v2_module模块
- 必须有自签证书或者CA证书,支持HTTPS
我项目中使用的是openrestry,使用的是Docker安装,镜像来自docker-openresty,包括了with-http_v2_module和openssl,都已经满足HTTP/2的要求,只需要配置自签证书。可以通过以下命令查看你的环境下的Nginx是否满足要求。
/usr/local/nginx/sbin/nginx -V
步骤二,生成自签证书
1: 到需要放置证书的目录(选在nginx的conf目录下就可以),建立服务器的私钥(此过程需输入密码短语)
openssl genrsa -des3 -out server.key 10242: 创建证书签名请求csr
openssl req -new -key server.key -out server.csr3:对于使用上面私钥启动具有ssl功能的nginx,有必要移除输出的密码
cp server.key server.key.org
openssl rsa -in server.key.org -out server.key4: 使用上面的私钥和CSR对证书进行签名
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
步骤三,配置证书
server {listen 443 ssl;server_name localhost;ssl_certificate server.crt;ssl_certificate_key server.key;
}
步骤四,配置HTTP/2
配置HTTP/2比较简单,如下
server {listen 443 ssl http2;server_name localhost;ssl_certificate server.crt;ssl_certificate_key server.key;
}
步骤五,验证配置是否生效
使用Chrome打开网站,检查Protocol是否是h2,默认浏览器没有显示Protocol这一列,右键列头,选中Protocol,Protocol这一列会出现,如果没有生效,会显示http/1.1,如果生效,则会显示h2,如下图。
写在最后
HTTP/2 除了突破了浏览器并发请求数的限制外,还带来另外一个好处。传统网页性能优化的常用方法是JS合并,通过JS打包工具,比如webpacker,把多个js文件打包成一个JS文件,然后前端请求时只需请求一个js文件,大大减少了HTTP的请求次数。但也会导致一个问题,任意一个js文件发生了修改,都会重新打包,浏览器会重新请求服务器,而不是从缓存中加载,但HTTP/2,模块就可以单独的压缩上线,而不影响其他没有修改的模块。
参考文章
https://segmentfault.com/a/1190000011172823
https://www.cnblogs.com/bugutian/p/6628455.html
https://blog.csdn.net/wetest_tencent/article/details/78808337