Pages

Sunday, 6 September 2015

让你的网站支持HTTP2/spdy

HTTP2和SPDY

SPDY是Google的研究人员为了加速Web浏览体验搞出来的一个试验性协议,旨在降低网络延迟。据这帮研究人员报告,使用SPDY协议的网站平均等待时间只有用HTTP/1.1协议网站的几分之一。SPDY协议发展到2.0版的时候突然声名雀起,几乎每个浏览器都开始支持它——没错,连最顽固的微软IE浏览器也支持了。
然而就在这个SPDY一统天下的大好时代,Google宣布放弃SPDY协议。当然Google只是放弃SPDY这个名字而已,SPDY协议中绝大部分的优化手段都被Google写进了HTTP2标准草案里。如今HTTP2协议定稿在即,Google才大方出来宣言放弃SPDY,力争推动各厂尽快切换到HTTP2上。
虽然HTTP2在浏览器上的普及势如破竹比当年SPDY不惶多让,可惜主流的开源Web服务器跟进并不迅速,Apache的nginx目前都只有SPDY模块的支持。还好spdylay的开发团队动作迅速,马上提供了HTTP2的实现,让我们可以不必多加改动地把服务器部署上HTTP2。
下面介绍一下怎么让自己的网站同时支持SPDY和HTTP2协议。

准备工作

因为SPDY只能支持SSL/TLS加密的连接,我假设网站已经有证书和密钥。如果网站还没有这两样东西,请按这里-https://www.google.co.jp/search?btnG=1&pws=0&q=ssl+%E8%AF%81%E4%B9%A6%E7%94%9F%E6%88%90&gws_rd=cr,ssl&ei=I-_rVZfQEMjN0gTQi4rQDQ

我在使用的是Ubuntu 14.04 LTS 64bit 系统,因为系统没有自带spdylay的软件包,所以需要从源码编译。如果服务器只想支持HTTP2而不想支持SPDY协议,也可以不安装spdylay。直接开始nghttp2的安装。
首先要安装编译环境和spdylay的依赖库:
# apt-get install build-essential pkg-config zlib1g-dev libssl-dev libxml2-dev libevent-dev libevent-openssl-2.0-5
再去spdylay的网站下载spdylay的源代码包:
# wget 'https://github.com/tatsuhiro-t/spdylay/releases/download/v1.3.2/spdylay-1.3.2.tar.xz'

安装spdylay

解包和配置:
# tar xpf spdylay-1.3.2.tar.xz
# cd spdylay-1.3.2
# ./configure
配置完成之后会显示一个配置表:
Version:        1.3.2 shared 9:0:2
Host type:      x86_64-unknown-linux-gnu
Install prefix: /usr/local
C compiler:     gcc
CFLAGS:         -g -O2
LDFLAGS:
LIBS:           -lz
CPPFLAGS:
C preprocessor: gcc -E
C++ compiler:   g++
CXXFLAGS:       -g -O2
CXXCPP:         g++ -E
Library types:  Shared=yes, Static=yes
CUnit:          no
OpenSSL:        yes
Libxml2:        yes
Libevent(SSL):  yes
Src:            yes
Examples:       yes
请注意Libevent(SSL)务必要显示为yes,不然编译出来的软件包里不会包含spdy的反向代理。检查好了就可以编译和安装:
# make && make install
# ldconfig
因为新安装的lib不会马上被系统读到,导致运行spdylay程序出现.so文件找不到的情况,所以需要运行ldconfig让系统重新载入动态链接库
此时可以运行一下SPDY的反向代理程序,看看是否工作良好:
# shrpx
Usage: shrpx [-Dh] [-s|--client|-p] [-b <HOST,PORT>]
             [-f <HOST,PORT>] [-n <CORES>] [-c <NUM>] [-L <LEVEL>]
             [OPTIONS...] [<PRIVATE_KEY> <CERT>]

A reverse proxy for SPDY/HTTPS.

[FATAL] Too few arguments
       (shrpx.cc:1167)
出现这个提示说明spdylay已经安装正常。

安装nghttp2

先要安装nghttp2依赖的软件包:
# apt-get install libev-dev libjansson-dev libjemalloc-dev python-dev cython
下载nghttp2的源代码包:
# wget 'https://github.com/tatsuhiro-t/nghttp2/releases/download/v0.7.11/nghttp2-0.7.11.tar.xz'
解压和配置:
# tar xpf nghttp2-0.7.11.tar.xz
# cd nghttp2-0.7.11
# ./configure
配置输出一个更长的信息表:
Version:        0.7.11 shared 13:0:8
Host type:      x86_64-unknown-linux-gnu
Install prefix: /usr/local
C compiler:     gcc
CFLAGS:         -g -O2
WARNCFLAGS:
LDFLAGS:
LIBS:
CPPFLAGS:
C preprocessor: gcc -E
C++ compiler:   g++
CXXFLAGS:       -g -O2 -std=c++11
CXXCPP:         g++ -E
Library types:  Shared=yes, Static=yes
Python:
  Python:         /usr/bin/python
  PYTHON_VERSION: 2.7
  pyexecdir:      ${exec_prefix}/lib/python2.7/dist-packages
  Python-dev:     yes
  PYTHON_CPPFLAGS:-I/usr/include/python2.7
  PYTHON_LDFLAGS: -L/usr/lib -lpython2.7
  Cython:         cython
Test:
  CUnit:          no
  Failmalloc:     yes
Libs:
  OpenSSL:        yes
  Libxml2:        yes
  Libev:          yes
  Libevent(SSL):  yes
  Spdylay:        yes
  Jansson:        yes
  Jemalloc:       yes
  Boost CPPFLAGS:
  Boost LDFLAGS:
  Boost::ASIO:
  Boost::System:
  Boost::Thread:
Features:
  Applications:   yes
  HPACK tools:    yes
  Libnghttp2_asio:no
  Examples:       yes
  Python bindings:yes
  Threading:      yes
需要确认Features中的Application是yes。可以编译和安装:
# make && make install
# ldconfig

启动nghttpx反向代理

终于到最后一步,用nghttpx为网站提供HTTP2支持。因为nghttpx是反向代理服务器,如果现在的Web服务器已经启用了https,需要先把https支持关掉,不然会发生端口冲突哦。我们使用nghttpx的Base模式就可以了,在443端口上接收https请求,转发到本机的80端口,在先安装了spdylay的情况下,nghttpx是可以同时支持HTTP/1.1、SPDY/3.1、HTTP2的。
# nghttpx -f *,443 -b localhost,80 /path/to/private.key /path/to/certification.crt
如果没有什么错误,现在网站应该可以用支持http2的浏览器访问了,当然不支持http2的浏览器会自动降级到spdy或者http1.1上。
nghttpx有一堆高级的参数可以使用,比如变成一个daemon进程,还有指定运行的用户和组,还有输出日志的方法格式等等,就不在这里详述了,可以运行nghttpx -h阅读帮助资料。

  1. http://dev.chromium.org/spdy/spdy-whitepaper#TOC-Preliminary-results 
  2. http://blogs.msdn.com/b/ieinternals/archive/2013/09/24/internet-explorer-11-changelist-change-log.aspx 
  3. http://blog.chromium.org/2015/02/hello-http2-goodbye-spdy-http-is_9.html 
  4. http://tatsuhiro-t.github.io/spdylay
related post: http://briteming.blogspot.jp/2015/08/nghttpx-http2.html
-----------------

九评HTTP/2协议


长达18年历史的HTTP/1.1即将随着HTTP/2协议的IETF草案与主流浏览器加入支持而被取代,Google拟定的过渡协议SPDY也将在Chrome未来版本中取消支持。本文的“九评”主要指出9项HTTP/2的特点——

1.向下兼容的HTTP API

推行HTTP/2需要做到向已有的老协议兼容——推行新版HTTP协议是为了改进功能和效率而不是实现一个新协议。
因此HTTP/2并未引入新的方法、更改包头或状态码。已有的程序代码甚至可以不用修改,只把HTTP库更新下就能支持HTTP/2。当然,为了有效利用HTTP/2引入的新机制还是需要调整源码,不过不是必须的。

2.更轻量的HTTP请求

HTTP/1中因为每个HTTP请求较耗资源和时间所以优化的重要一项就是尽量减少请求数量。
HTTP/2中有些奇技淫巧可以免了——引入了批量发送请求的特性,在一次连接中可以一口气发一堆请求。
以及引入了新的包头压缩,广为诟病的历史遗留问题得到了解决。

3.针对服务器和传输的优化

HTTP/2的设计可以减少连接数,所以传输设备和服务器的开销都能降低,在如今HTTP/1多连接并行的情况下这样设计尤为重要。
比如你用手机开了6个TCP连接到不同服务器来下载一个网页上的各种资源(这种情况很常见,比如本站引用的多说评论板、360的字体CDN、Steam状态等等)手机如果性能不好很可能爆buffer导致丢包重传,耗费流量电量拖慢页面速度等。
HTTP/2可以使到一个服务器只保持一个连接,当然站点也得尽量把资源引用在同一个服务器上。

4.缓存推送

HTTP/2的服务器推送机制允许服务器主动把之后可能用到的资源预先推送到客户端缓存,这可以避免来回发连接请求HTML/CSS等。比如一个页面肯定需要引用一个CSS文件,服务器可以不等用户的浏览器读取HTML发现需要CSS后再请求,而是连HTML一起推送到浏览器存着。
当然某些情况下客户端也许不需要推送,因为浏览器本身也有缓存机制或者就是任性,可以用RST_STREAM来阻止。

5.后悔药

HTTP/1中如果客户端发送了某个请求却中途想取消,只能直接关闭连接来节省流量,没有更好方法。
HTTP/2添加了RST_STREAM层来允许客户端反悔。如果浏览器离开某个页面或者中断文件下载,可以不用通过掐断连接就能停止,节约流量同时还贯彻了连接重用的设计。

6.加密

HTTP/2不是必须用TLS加密,但可以让加密连接的性能更高。不过鉴于在如此“开放”的网络下想要安全传输只能通过加密,Firefox和Chrome都声明其只接受TLS下的HTTP/2。这么做有两个主要原因,一是推行一个新版HTTP协议很困难,很多“中间人”比如代理服务器、防火墙万年不更新,这些不兼容HTTP/2的东西处理HTTP/2请求可能产生各种问题;二是由于种种原因互联网越来越不安全,用这种方式强行推行加密也是种拯救世界的方式 

7.不再是人类语言

HTTP/1的一个特点就是兼容telnet——手动写HTTP请求然后目测结果 反正都是易懂的明文。不过在HTTP/2没戏了,因为HTTP终于进化成了正经的二进制协议。
抛弃传统的“人类语言包头”可以减少错误、提高程序的读取效率甚至提高安全性,而且再也没有小学生乱写的程序会发送“换行不规范”之类的HTTP协议了。

8.未必能被有效利用

HTTP/2并非仙丹妙药,不可能换上就立马提速一倍——这次更新主要是为解决各种问题提供可能,因此还需服务端和客户端对特性的有效利用。
HTTP/2其实还产生了新的缺陷——让不同TCP拥塞控制算法的区分度更大了。由于所有到同一服务器的传输都交给单个连接,如果一个连接不给力那整个网站都会慢下来。所以以后的性能优化可能更在TCP层面,甚至引入TCP/2? 

9.HTTP/3什么的

如果HTTP/2推行顺利,没多久就会开始计划制定HTTP/3了。其实现在已经提出了不少HTTP/2都没实现的新概念,比如推送TLS证书和DNS解析到客户端等等,没准在HTTP/3就有,当然到时候再出现类似SPDY这样的过渡协议也是很有可能的.
-----------

Nginx启用SPDY协议


把博客改成了SSL访问,突然脑海中就浮现出了SPDY协议。先说说什么是SPDY协议吧,SPDY并不是一种用于替代HTTP的协议,而是对HTTP协议的增强。新协议的功能包括数据流的多路复用、请求优先级,以及HTTP包头压缩。简单来说,通过SPDY协议可以提升网站的加载速度。
启用SPDY协议有两个前提,第一是服务端需要启用SPDY协议,并且是使用SSL 443端口进行访问的,其次是浏览器也需要支持SPDY协议(目前最新版本的Chrome和Firefox都已经支持)。

下面来简单介绍下Nginx如何启用SPDY协议。Nginx从1.4.0稳定版开始就已经支持SPDY协议,不过在编译的时候需要增加相应的配置参数,大家如果是使用LNMP脚本来搭建环境的话,建议可以通过直接修改upgrade_nginx.sh文件后重新编译nginx的方式来进行。打开upgrade_nginx.sh后,找到如下代码,并进行修改:
1
2
3
4
5
6
修改前  
cd nginx-$nginx_version/  
./configure --user=www --group=www --prefix=/wp-content/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_gzip_static_module --with-ipv6  
修改后  
cd nginx-$nginx_version/  
./configure --user=www --group=www --prefix=/wp-content/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_gzip_static_module --with-ipv6 --with-http_spdy_module
重新编译安装后,需要对nginx的conf文件进行如下修改:
1
2
3
4
5
6
7
8
server  
  {  
  listen 443 ssl spdy;//在这里加入spdy,这样即可启用SPDY协议  
  ssl on;  
  ssl_certificate /wp-content/local/nginx/conf/jayshao.crt;  
  ssl_certificate_key /wp-content/local/nginx/conf/jayshao.key;
  ...
  }
重启Nginx,经过上述步骤,即可启用Nginx的SPDY协议了,打开博客后可以通过输入chrome://net-internals/#spdy 来查看你的网址是否成功启用。
-----------------------------

网站启用HTTPS和SPDY

 

Google开发的SPDY协议(已成为HTTP/2.0的模板)可以很好的克服HTTP/1.1的许多不足。SPDY协议本身可以不使用HTTPS,但是Google的实现(包括apache的mod_spdy和Chrome浏览器)都强制要求SPDY基于HTTPS进行传输,因为SPDY是Google牵的头,大家基本也默认了这一点。SPDY在与服务器通讯过程中只使用一条连接,因此HTTPS的握手过程也只有一次,可以说基本上克服了使用了HTTPS带来的开销。SPDY使用的分帧、首部压缩等技术可以很好的克服HTTP/1.1时代的队首阻塞、首部过大等问题,使HTTP性能得到提升。

目前大多数最新的浏览器都支持SPDY协议,包括IE11、Chrome、Firefox。服务器方面,apache有mod_spdy,nginx的较新版本内置了对SPDY的支持,只需编译时加上--with-http_spdy_module选项即可。

我使用的版本是nginx 1.62,Ubuntu 14.04的更新源中的nginx版本较低,无法通过简单的配置启用SPDY,所以我加入了nginx的ppa源:add-apt-repository ppa:nginx/stable,这样再安装nginx就是1.62版本了,配置nginx,将listen 443 ssl修改为listen 443 ssl spdy即可,非常简单。

-----------

相关帖子:https://briteming.blogspot.com/2015/03/googlespdy.html