在 Dropbox ,我们的运维团队于近日升级了前端 Nginx 服务器开启了 web 服务的 HTTP/2 支持。在本篇文章中,我们将就此次 HTTP/2 的升级过渡,分享我们的一些经验以及相关发现。总体来说此次升级还算平滑,然而依旧踩了很多的“坑”碰到了不少注意事项,希望会对他人有所帮助。
背景:HTTP/2 以及 Dropbox web 服务架构
HTTP/2(
RFC 7540)是新一代的 HTTP 协议版本,它基于
SPDY,相比于 HTTP/1.1 提供了数项性能优化。这些优化包括:更高效的首部压缩(Header compression)、服务端推送(Server push)、同一连接上的流复用(Stream multiplexing),等等。如今,
HTTP/2 已经被大部分浏览器所支持。
Dropbox 使用开源的 Nginx 处理 SSL 连接并且对 web 流量进行七层的负载均衡。在升级之前我们前端的 Web 服务器运行的是 Nginx 1.7 并且支持 SPDY。另一个顾虑则是 Chrome 虽同时支持 SPDY 以及 HTTP/2 ,但是官方将会
在 5 月 15 起,停止对 SPDY 的支持。如果那时我们仍然不能提供 HTTP/2 的支持的话,意味着我们的 Chrome 客户将会从使用 SPDY 回退到 HTTP/1.1。
HTTP/2 升级过程
整个 HTTP/2 升级过程很平稳,Nginx 1.9.5 增加了 HTTP/2 模块(由 Dropbox 联合赞助)默认抛弃了对 SPDY 的支持。就我们而言,我们打算升级到 Nginx 1.9.15 ,也就是最新的 stable 版本。
Nginx 的升级包括基本的配置文件修改,启用 HTTP/2 的支持,需要将
http2
指令添加到
listen
字段。就我们而言,因为之前已经开启 SPDY,所以只需将
spdy
替换成
http2
就行了。
|
当然,如果你有相关的额外需求的话,也可以调节其他 Nginx HTTP/2 的配置选项。
我们在 Canary 版本的机器上部署了 HTTP/2 大约一周的时间,而此时生产环境使用的仍然是 SPDY。在验证正确性以及相关性能评估之后,我们为 Web 服务全线开启了 HTTP/2。
从 SPDY 到 HTTP/2 平稳过渡(60 分钟的流量情况)
该图展示了从 SPDY 至 HTTP/2 的过渡情况。 HTTP/1.1 连接并没有在该图展示出,我们分别在 23、26 以及 50 分钟的时候 ,逐渐在前端 Web 服务器上启用了 HTTP/2 支持。在此之前,流量则共同来自 Canary 机器上部署的 HTTP/2 以及生产环境中的 SPDY 。如图所示,最终我们则全线迁移到了 HTTP/2。
相关观察
我们在 canary 机器上详细监测了开启 HTTP/2 之后的性能情况,我们的观察点包括开启 HTTP/2 之后的性能效果,以及 HTTP/2 之后发现的问题,毕竟 HTTP/2 应用于生产还不太成熟。
性能提升
得益于更高效的的首部压缩算法(HPACK),我们注意到入口流量带宽的大幅度减少。
入口带宽流量情况(24 小时内流量)
上图显示了 Canary 和生产机器每台机器上面的平均流量带宽情况,我们只在 Canary 机器上开启了 HTTP/2。每台 Canary 以及生产机器上都从负载均衡服务器上接收几乎是相同的流量。如图所示,在开启 HTTP/2 之后入口带宽明显减少(将近 50%)。值得注意的是,尽管我们之前在 Canary 和生产机器上使用 SPDY ,我们并没有开启 SPDY 首部压缩支持的原因是因为一个安全问题(CVE-2012-4929)。至于出口流量,并没有显著变化,因为响应首部只占响应流量的一小部分。
一些注意事项
POST 请求延迟的增加。当我们在 Canary 机器上启用 HTTP/2 时,我们注意到中间延迟显著增加。下图展示了在 Canary 机器上开启 HTTP/2 后,相对于生产机器上增加了大约 50% 的请求延迟。经过调查我们发现激增的延迟来自 POST 请求。经过一番深入研究,我们发现这个问题是 Nginx 1.9.15 所固有的问题,相关讨论可以参见 Nginx 的邮件列表。
激增的 50% 请求延迟(24 小时内流量)
注意,增加的 50% 请求延迟(1.5 倍)取决于特定的流量负载。在大多数情况下,对于我们来说额外多了一个 RTT(Round Trip Time),并没有对我们的性能造成关键性影响。然而如果你的负载情况包括大量琐碎并且延迟敏感的 POST 请求,那么当你升级 Nginx 到 1.9.15 的话,激增的延迟就是一个重要的问题了。
小心的启用 HTTP/2 ,尤其是在客户端不可控的情况下。目前 HTTP/2 依旧不太成熟,从我们的经验来看,一些客户端、第三方库以及相关的服务器实现,并没有完全的对 HTTP/2 实现兼容。比如:
- Chrome 没有处理好 RST_STREAM 携带 NO_ERROR 的问题,导致在 Nginx 1.9.14 下会出现这样的问题(Chromium Issue #603182)。相关解决方法已经纳入 Nginx 1.9.15。
- 当窗口空间(window space)耗尽的时候,Nghttp2 并不会发送 END_STREAM ,相关讨论请参见之前提到的 Nginx 的邮件列表
由于我们的 API 用户可能使用的是不同的第三方 HTTP 库,在为我们的 API 启用 HTTP/2 之前,我们需要进行大量的测试。
相关调试工具
CloundFlare 发表过一篇文章,总结一些
好用的 HTTP/2 调试工具,除此之外,我们发现 Chrome net-internals 工具(
chrome://net-internals/#http2
)也可以派上用场。下图则是访问 www.dropbox.com 是打开新的 HTTP/2 会话时的帧交换截图。
总而言之,我们已经平稳过渡到了 HTTP/2 ,下面是从这篇文章的几个相关总结。
- 在 Nginx 中启用 HTTP/2 很简单。
- 首部压缩会明显的减少入口带宽的流量。
- Nginx 1.9.15 上会出现 POST 请求延迟的增加。
- 谨慎的启用 HTTP/2 ,因为还存在一些兼容性问题。
- Canary 验证以及 Nginx 的错误日志检查有助于及早发现潜在的问题。
我们希望这篇文章能为那些热爱网络知识并有兴趣在服务中启用 HTTP/2 的人提供帮助,我们也希望听到大家的意见反馈。
注:
本文由 Leo 翻译自 Dropbox 官方技术 Blog,
原标题:Enabling HTTP/2 for Dropbox web services: experiences and observations