目前 Nginx 开启 http2 已经是常识。但是我所不解的是,Nginx 默认的反向代理(proxy_pass)http 协议只能支持到 1.1。
在 官网文档 查找发现,对于 proxy_http_version
只能支持到 1.1,而且默认开启的是 1.0。官方备注说明 1.1 是留给长连接(websocket 等)的,因此可以理解为如果没有长连接需求保留默认即可。那么反向代理的协议不同是否会带来影响?
官方邮件 给出了答案(添加了自己的理解):
- http2 的解决问题在于 tcp 的连接重用.对于端(edge)用户到服务器,光是三次握手都可能带来巨大开销,此时重用效果很明显。对于国外应用,往往 ping 100 以上是常态,此时更加明显。但是对于反向代理的服务,我们往往放在内网,延迟低于 1ms,重用不重用影响不大。(在这里 有所提到)
- 如果上面只是对重用没有必要说明的话,那么后面这一条就直接说明不可能了。http2 只会建立一条 tcp 隧道,这不符合我们的代理模型(多个不同 session,多服务负载均衡)。
在这里保存疑问,为什么 Nginx 不能与 upstream 建立多个持久 tcp 连接(http2),http 协议本身无状态,只需要将数据传输到代理端即可,这样似乎不会产生问题。
做出这个想法的原因是 Nginx 很多时候 reverse proxy 的一方不是本地,比如说各种反代站点。这些站点与被反代站点延迟就不是 1ms 了。在这种情况下,也许会发生即使 Nginx 声明了 http2,由于与反代站点通讯是 1.1 甚至以下,导致出现性能瓶颈(个人没有性能需求,因此上述只是想 法,不会进行实验测试)。
我想到的一个理由为反代站长期与被代理站点建立 TCP 长连接,而不是像浏览器一样随着关闭断开,可能导致被代理站点长期资源消耗。
顺便思考一下,反向代理网站从这一点来说安全性未知。因为你直接通讯的证书是反代站点的,即使声明了 proxy_pass 为 tls 流量,Nginx 在 pass 时完全可以解析包内容,这使用 lua 等可以非常方便的处理。
不管怎样,上面提到的邮件是 14 年的。现在是 21 年,这么多年过去 Nginx 没有实现,那么将来也不会。也许基于 UDP 的 QUIC 会带来变化,但是谁知道呢?
对于常规部署在本地的反代站点,1.1 协议不会成为性能瓶颈。但是一个问题是 1.1 协议会导致每一个 TCP 连接占用一个端口,换句话说 Nginx 瞬时单机并发受到反向代理限制,低于 65535。
对大型站点要进行突破 65535 限制,最简单的方案是分配多 ip。对个人站点,使用 unix socket 可能是更好选择。unix socket 的协议栈更浅,性能更好。它的缺点是不方便做负载均衡,因为 socket 要求开启在本地。