SPDY 是 Google 开发的基于传输控制协议 (TCP) 的应用层协议 ,开发组正在推动 SPDY 成为正式标准(现为互联网草案)。SPDY 协议旨在通过压缩、多路复用和优先级来缩短网页的加载时间和提高安全性。(SPDY 是 Speedy 的昵音,意思是更快)
SPDY 与 HTTP 的关系
SPDY 协议只是在性能上对 HTTP 做了很大的优化,其核心思想是尽量减少连接个数,而对于 HTTP 的语义并没有做太大的修改。具体来说是,SPDY 使用了 HTTP 的方法和页眉,但是删除了一些头并重写了 HTTP 中管理连接和数据转移格式的部分,所以基本上是兼容 HTTP 的。
Google 在 SPDY 白皮书里表示要向协议栈下面渗透并替换掉传输层协议(TCP),但是因为这样无论是部署起来还是实现起来暂时相当困难,因此 Google 准备先对应用层协议 HTTP 进行改进,先在 SSL 之上增加一个会话层来实现 SPDY 协议,而 HTTP 的 GET 和 POST 消息格式保持不变,即现有的所有服务端应用均不用做任何修改。
因此在目前,SPDY 的目的是为了加强 HTTP,是对 HTTP 一个更好的实现和支持。至于未来 SPDY 得到广泛应用后会不会演一出狸猫换太子,替换掉 HTTP 并彻底颠覆整个 Internet 就是 Google 的事情了。
为什么要重新建立一个 SPDY ?
距离万维网之父蒂姆・伯纳斯-李发明并推动 HTTP 成为如今互联网最流行的协议已经过去十几年了(现用 HTTP 1.1 规范也停滞了 13 年了),随着现在 WEB 技术的飞速发展尤其是 HTML5 的不断演进,包括 WebSockets 协议的出现以及当前网络环境的改变、传输内容的变化,当初的 HTTP 规范已经逐渐无法满足人们的需要了,HTTP 需要进一步发展,因此 HTTPbis 工作组已经被组建并被授权考虑 HTTP 2.0 ,希望能解决掉目前 HTTP 所带来的诸多限制。而 SPDY 正是 Google 在 HTTP 即将从 1.1 跨越到 2.0 之际推出的试图成为下一代互联网通信的协议,长期以来一直被认为是 HTTP 2.0 唯一可行选择。
HTTP 协议的不足
1. 单路连接 请求低效
HTTP 协议的最大弊端就是每个 TCP 连接只能对应一个 HTTP 请求,即每个 HTTP 连接只请求一个资源,浏览器只能通过建立多个连接来解决。此外在 HTTP 中对请求是严格的先入先出(FIFO)进行的,如果中间某个请求处理时间较长会阻塞后面的请求。
(注:虽然 HTTP pipelining 对连接请求做了改善,但复杂度增加很大,并未普及)
2. HTTP 只允许由客户端主动发起请求
服务端只能等待客户端发送一个请求,在可以满足预加载的现状是一种桎梏。
3. HTTP 头冗余
HTTP 头在同一个会话里是反复发送的,中间的冗余信息,比如 User-Agent、Host 等不需要重复发送的信息也在反复发送,浪费带宽和资源。
SPDY 协议的优点
1. 多路复用 请求优化
SPDY 规定在一个 SPDY 连接内可以有无限个并行请求,即允许多个并发 HTTP 请求共用一个 TCP会话。这样 SPDY 通过复用在单个 TCP 连接上的多次请求,而非为每个请求单独开放连接,这样只需建立一个 TCP 连接就可以传送网页上所有资源,不仅可以减少消息交互往返的时间还可以避免创建新连接造成的延迟,使得 TCP 的效率更高。
此外,SPDY 的多路复用可以设置优先级,而不像传统 HTTP 那样严格按照先入先出一个一个处理请求,它会选择性的先传输 CSS 这样更重要的资源,然后再传输网站图标之类不太重要的资源,可以避免让非关键资源占用网络通道的问题,提升 TCP 的性能。
2. 支持服务器推送技术
服务器可以主动向客户端发起通信向客户端推送数据,这种预加载可以使用户一直保持一个快速的网络。
3. SPDY 压缩了 HTTP 头
舍弃掉了不必要的头信息,经过压缩之后可以节省多余数据传输所带来的等待时间和带宽。
4. 强制使用 SSL 传输协议
Google 认为 Web 未来的发展方向必定是安全的网络连接,全部请求 SSL 加密后,信息传输更加安全。
SPDY 协议的意义
按照 Google 的说法,SPDY 被创造出来的唯一目的就是让 Web 更快(strive to make the whole web fast),其名字 SPDY(Speedy) 也似乎在暗示着这一点。那么 SPDY 的意义又在哪里呢?
1. 普通用户:
对于使用者来说,隐藏在浏览器下面的 SPDY 相比 HTTP 没有任何区别,但是我们可以感觉到 Google 服务在 Chrome 下异常的快,这就是 SPDY 的功劳了。此外网站信息传输加密后不用担心信息被截取等,大大增加了安全性和保密性。
2. 前端人员:
对于前端工程师们来说,提升页面效率是一件很重要的事情,目前大多采用像 CSS Sprites 等方法来优化网站,对于因为页面加载时每张图片、icon 都请求一个连接甚至采用在不同页面引用不同图片来降低一个页面内图片的请求数量。而现在有了 SPDY 的请求优化可以将请求顺序进行重排,这样可以在很大程度上缓解页面加载时图片请求带来的影响。例如像极客公园的报名页面,如果报名用户过多,例如极客公园2012年创新大会或极客公园第 27 期长城会,可以很明显的感觉出头像的请求会拖累整体页面加载变慢甚至变卡,相信对于这点,经常上淘宝或刷微博的会深有体会,一旦网速稍微慢点就会出现页面加载异常,还有像苹果 App Store(除去服务器因为地区的延迟),豌豆荚这类应用分发平台上应用图标刷新缓慢等,如下面这个视频所示。
3. 运维人员:
SPDY 在降低连接数目的同时,还使得服务器上每个客户端占用的资源也减少,从而可以释放出更多内存和 CPU 。此外 SPDY 综合起来可以将浏览速度提升一倍,页面加载延迟方面的改进达 64% 。
众家支持的 SPDY 协议
如果你在使用 Chrome 浏览器,同时使用像 Gmail 等 Google 的网络服务的话,其实你已经不再是通过 HTTP 访问这些服务了。在浏览器打开 chrome://net-internals/#spdy 就会发现你已经在使用 SPDY 协议了。(除了包括 Google 自家的 Gmail、Google Plus 等 Google 系服务外,其他公共站点例如 Twitter 和 Webtide 也已经支持该协议。在国内,基于 WebKit 的豌豆荚 2.0 也曾表示将引进Chrome的SPDY技术来进一步提升速度。
SPDY 的实现需要浏览器客户端和 Web 服务器同时支持。在客户端浏览器这快 Google自家的 Chrome 和Chromium 全系列不用说,都已经支持SPDY; Mozilla 家的 Firefox 自 Firefox 13 也默认开启对 SPDY 的支持。而亚马逊家的 Silk 利用 SPDY 的深度其实不比 Google 自家的 Chrome 和 Firefox 差。
在Web 服务器方面包括最流行和最广泛的 Apache 在内,Netty、Jeety、Varnish、Erlang 和 Hightide 应用服务器以及面向 node.js 的服务器也都已经宣布支持 SPDY。( Nginx 也表示将支持 SPDY)
如何部署 SPDY?
近日 Google 正式发布了适用于最流行 Web 服务器 Apache 的插件 mod_spdy,将其下载安装后你的 Apache 服务器就能使用 SPDY 协议与兼容 SPDY 协议的浏览器如 Chrome、FireFox 等进行通信。像之前所说的那样,SPDY 是运行在 HTTPS 上,非 HTTPS 流量并不会受到 mod_spdy 影响。
SPDY 部署要求:
1. Apache 2.2 (≥2.2.4)
2. mod_ssl 模块开启
SPDY 部署步骤:
1. 下载 mod_spdy 模块
到下载页面下载对应系统的安装包
2. 安装 mod_spdy 模块
在系统终端运行下面命令行
dpkg -i mod-spdy-*.deb
apt-get -f install
-系统为 Debian/Ubuntu
------------------------------------------------------------
yum install at (if you do not already have 'at' installed)
rpm -U mod-spdy-*.rpm
-系统为 CentOS/Fedora
3. 重启服务器(Apache)
sudo /etc/init.d/apache2 restart (Debian/Ubuntu)
4. 确定开启与否
打开 Chrome 浏览器,输入并前往 chrome://net-internals/#spdy 页面,查看主机名称是否出现在标识栏中。如果出现说明已经部署完毕,如果没有出现去服务器错误日志(error.log)里查询。
未来的web基础?
在最新的协议文档里 Google 重新将 SPDY 分为了两层,其中一层被描述为 HTTP-like,大有取代 HTTP 的意图(Google 最近的一篇文章已经直呼 SPDY 为“a replacement for HTTP”)。同时 HTTP 2.0 标准制定工作组(HTTPbis)也表示,SPDY 很有希望接替当前的 HTTP 传输实现。
考虑到 Chrome 和安卓的份额以及标准的推动,相信 SPDY 会有一个好前景。因此选择此刻支持 SPDY 也是明智的选择。
本文主要是参考Google SPDY项目主页的一些文档总结而来,目的整体上介绍SPDY协议的定义为主。后续,我将写一系列的文章分析SPDY的一些项目(如:Nginx),SPDY的性能测试以及如何部署SPDY到实际生产应用。
一、HTTP协议存在的一些主要问题
1、一个连接一个请求。浏览器和web server之间都是以短连接方式交互,一个连接只服务一次请求,对于一个需要加载多个资源的页面来说,将会带来很高的延迟。
2、只能由客户端发起请求,服务器完成响应。服务器不能主动的将一些必须的资源推送给客户端。
3、HTTP协议只能对body进行压缩处理,不能压缩header。在一个cookie较多的站点,将对带宽造成严重的浪费。
http的问题在10年前的web中,是无关紧要的。然而今天的web已不再像10年的web那般简单了,同时用户对web应用的体验要求也将是越来越高,所以Google发起了“Let's make the web faster“项目,SPDY正是此项目的一部分。
二、SPDY的目标
起初,SPDY项目并不只是为了加速http,更多的是要致力于改进传输层和会话层协议。比如: Stream Control Transmission Protocol (SCTP), 一个用于替换TCP的传输层协议。除此之外还有一些其他方面的研究,可以在相应的white paper上找到。开发一个新的传输层协议也许很简单,但考虑到后期的部署、推广和兼容历史等因素,这估计是一个非常糟糕的决定,等待的结果必然是失败。因此,目前的SPDY主要还是集中应用层协议的改进,加速HTTP。
SPDY的主要目标:
1、单个tcp连接支持并发的Http请求。这主要是解决目前http协议的一个连接只能服务一次请求的问题。
2、压缩请求/响应头。
3、定义spdy为一个相比http容易实现的协议。
4、使用ssl加密连接,用户数据更加安全的同时也解决了对已有网络体系的兼容问题。其实,TLS的强制,更多的是解决历史兼容问题,而不是安全考虑,后面详细介绍。
5、服务器可以主动的向客户端发起连接,并推送数据。
三、SPDY协议栈
在http协议栈中引入spdy后,大概就是下图(来自Google官方)的样子:
关键就是在tcp连接上面加入了spdy session层,这一层根据spdy draft又可以称为framing层,主要提供stream机制和消息组帧的实现。下文介绍具体协议的时候,再谈。
四、TLS-NPN
TLS-NPN全称是Transport Layer Security - Next Protocol Negotiation,NPN是Google为了支持SPDY协议作为一个应用层协议使用,而为TLS定义的一个扩展。NPN扩展的出现仅仅是为了更好的部署和使用SPDY,任何时候它都不会是SPDY的一部分。关于NPN扩展的详细介绍请看这里:http://technotes.googlecode.com/git/nextprotoneg.html 。
既然TLS-NPN并不是SPDY协议的一部分,那为什么要强制TLS?为何不能像HTTP一样根据用户自由选择是否SSL呢?Google这样做,必然是有道理的:
1、目前整个互联网可以说只有80和443两个端口可用,如果SPDY跑在一个新的端口上提供web服务,就极有可能会被诸如防火墙等设施给阻止掉。要想推动整个网络系统引入一个新的等同于80和443的标准端口,我想这绝对不是一件容易的事情,因此聪明的Google必须考虑兼容现在的网络体系环境,而不是自作聪明的推动新的端口。
2、放弃使用新端口的方案,就只能在80和443上面选择了。然而,目前很多的web中间代理设施只认80端口跑http协议,一旦SPDY跑在80端口上,必然会被这些代理给阻止掉。80端口显然也不能使用。
3、没了80端口,就只能选择443了,443目前是https协议加密数据传输,理论上443端口上经过加密的套接字可以传输任何应用层协议数据。
因此,为了在SSL上能够协商使用SPDY协议,Google就定义了NPN扩展,此扩展目前已经在OpenSSL、NSS等实现了。
五、SPDY-draft2
Google已经放出的SPDY协议草案在此: http://www.chromium.org/spdy/spdy-protocol ,目前已经到draft4了,但本文参考的是draft2,因为目前Nginx的SPDY实现是基于draft2而来。
SPDY在逻辑上由部分构成,一是framing layer,其主要负责组装帧消息,为了request/response提供基础;二是HTTP layer,它定义了request/response的相关行为。
根据上面这个简单的模型,从总体上看一下SPDY的3个重要组成部分――TCP connection、framing layer、http layer。
上图描述的是client和server之间的一个TCP连接;这个TCP连接上面有两个stream,一个stream就负责了一次request/response;一个request/response由多个frame(一个小箭头就是一个frame)组成;frame又分为了control frame (红色箭头)和data frame (蓝色箭头)。framing layer主要是定义一个frame消息,HTTP layer主要是定义request/response。
一次request/response完成后,就释放此stream,但不会释放TCP connection。要发起新的request,首先得建立一个stream,由此可看出SPDY在TCP connection上加入了stream机制来模拟了http的短连接。stream其实只是TCP上面的一个逻辑层,它的建立和释放非常快,没有TCP的多次握手,这就解决了TCP的Slow Start问题。换个角度想想,如果TCP connection的建立和释放本来就无延迟,非常的快速,那么http就没有改进的必要了,我猜想这也是一开始Google想从传输协议TCP入手解决问题的考虑。
Framing
Framing分为control和data两种,下面详细介绍SPDY定义了哪些control frame和data frame,他们的作用是什么。
control frame结构
+----------------------------------+
|C| Version(15bits) | Type(16bits) |
+----------------------------------+
| Flags (8) | Length (24 bits) |
+----------------------------------+
| Data |
+----------------------------------+
上图可以看到一个control frame至少有8个字节的头部信息。
C: 占一个bit,用来识别此frame是control还是data之用。
Version: 占15个bit,是SPDY的版本号,目前是2。
Type: 占16个bit,control frame的类型,表示此control frame具体是干什么用,后面将介绍每种类型的control frame。
Flags: 占8个bit,一个附加的属性域。
Length: 占24个bit,其实是一个无符号的24位整数,表示Length域后面的数据长度。
data frame结构
+----------------------------------+
|C| Stream-ID (31bits) |
+----------------------------------+
| Flags (8) | Length (24 bits) |
+----------------------------------+
| Data |
+----------------------------------+
同样可以看出一个data frame至少也有8个字节的头部信息。
C: 同control frame。
Stream-ID: 占31bit,一个stream的标志id。
Flags和Length: 同control frame。
stream
SPDY的一个stream既可以被client创建,也可以被server创建,这就说明SPDY不但允许由client发起请求,也可以由server发起请求。如果你愿意,还可以创建一个单向stream,只需要发送特定的control frame就可以了,单向stream可以认为是只有请求,永远不会有响应。stream的创建、关闭等操作都是由control frame实现的。
control frames
SPDY定义了不少的control frames,这里简单的列举一下它们,不作详细的介绍,如果你在实现SPDY的时候,请求看具体draft。
SYN_STREAM control frame -
是发送者用来创建一个stream。
SYN_REPLY control frame - SYN_STREAM接受者用此control frame去开始响应对方。
RST_STREAM control frame - 可以用来中断一个stream。
SETTINGS control frame - 可以用来改变一个stream的状态,属性等。
NOOP control frame - 是一个无操作的control frame了,接受者直接忽略它。
PING control frame - 类似ping命令的功能,可以用来测量一个rtt时间。ping工具是工作在4层,此处的PING control frame却是工作在7层上。
GOAWAY control frame - 发送者用来告诉对端,不再接受新的stream了。可以理解为不久将要关键当前的TCP connection。
HEADERS control frame - 给stream添加一些附加的header。
到此,各种control frame都简单的介绍完了,每个frame的具体定义还得参考draft。至于datat frame,相比control frame就简单多了,它没有这么类型,它只做一件事情――就是在某个stream上传输数据。
HTTP layer
为了兼容目前的所有应用,尽量做到应用不做任何修改,或者尽可能少的修改。因此http layer定义了如何将http request/response跑在framing之上。
客户端通过SYN_STREAM control frame发起一个请求,请求相关的所有header放在SYN_STREAM frame中发送,如果请求有body将在data frame中发送,最后一个data frame必须设置FIN_FLAG标志请求结束。
服务器通过SYN_REPLY control frame响应客户端,响应的所有header放在SYN_REPLY frame中发送,响应数据通过data frame来发送,同样最后一个data frame需要设置FIN_FLAG标志响应结束。
SPDY还详细的定义http request/response headers的异同,具体看草案。
server push
有了push功能就可以针对一个客户端请求响应多个应答,这样可以避免针对每个资源的获取,客户端都要主动来请求一次;相反,服务器主动将这样一些明知客户端需要的资源推送给客户端。push功能的实现感觉还是挺复杂的,具体参考spdy-draft。
SPDY 部署
1、服务器通过Alternate-Protocol header来建议使用SPDY
服务器收到一个普通的http请求的时候,可以通过在响应header里添加Alternate-Protocl来告知客户端可以发送SPDY。客户端收到Alternate-Protocl header后,就尝试去通过SPDY发送请求给服务器,如果失败了,在当前域下,就再也不要去尝试做这件事情了。
2、服务器通过TLS-NPN扩展来建议使用SPDY
服务器在443端口收到一个携带有TLS-NPN扩展的连接,就告诉客户端自己所支持的spdy版本号,然后客户端就通过SPDY来和服务器通信。通过TLS-NPN扩展的方式应该是唯一的途径在整个互联网上使用。Alternate-Protocol的方式只有在确定客户端和服务器中间没有拒绝其他端口的防火墙等设施才ok。
SPDY的现状
目前Google,twitter,facebook等公司都已经开始着手部署spdy来加速自己的web应用了。在服务器方面,Apache、Nginx、Netty、Jetty、node.js等都已经开始初步的支持SPDY。浏览器方面,chrome已经支持SPDY,firefox貌似也开始支持了。其次,在github上搜索一下SPDY,可以看到有不少spdy的项目存在了。