Nginx 中启用 HTTP/3

上一篇文章中,介绍了 Http/3 的基本原理和优化,本节介绍下如何在 CentOS 7 环境上通过 Nginx 启用 Quic 协议

环境准备

如果不愿意折腾,可以在文末下载博主编译好的 nginx-quic 可执行文件,跳过坎坷的编译安装步骤(),快速体验

准备编译环境

yum install -y build-essential ca-certificates zlib1g-dev libpcre3 libpcre3-dev tar unzip libssl-dev wget curl git cmake3 ninja-build golang
# 然后执行
yum install -y hgsubversion

升级 GCC

注意,CentOS 通过 yum 直接安装、升级的 GCC 版本过老,并不能直接使用,需要进行升级。升级时推荐采用下列的办法进行升级。当然也可以手动编译 GCC 的源码来级,但是会更加……坎坷。

# 安装 devtoolset-9
yum install devtoolset-9

安装好后,替换掉系统的 gcc, g++, c++

# 备份原gcc, g++, c++
cp /usr/bin/gcc /usr/bin/gcc4.8.5
cp /usr/bin/g++ /usr/bin/g++4.8.5
cp /usr/bin/c++ /usr/bin/c++4.8.5

# 设置软连接
ln -s /opt/rh/devtoolset-9/root/bin/gcc /usr/bin/gcc
ln -s /opt/rh/devtoolset-9/root/bin/g++ /usr/bin/g++
ln -s /opt/rh/devtoolset-9/root/bin/c++ /usr/bin/c++

准备好后,执行 c++ --version,即可查看当前使用的 C++ 版本

需要注意,需要 9 以上版本,否则无法编译

安装

编译安装 BoringSSL

编译安装谷歌的 boringSSL,以获得 QUIC 支持,后面编译 nginx-quic 需要使用

# 克隆 Boringssl 代码
git clone --depth=1 https://github.com/google/boringssl.git

# 修改 CMakeList.txt 文件,添加如下内容(用于解决某些情况下的报错,可以先跳过,如遇报错再来添加)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-implicit-fallthrough -Wno-format-signedness")

# 编译安装
cd boringssl
mkdir build
cd build
cmake -GNinja ..
ninja

编译安装 Nginx-quic

首先获取 Nginx 的编译参数,即 nginx -V 指令回显中的 configure arguments 项

将该项的 --with-openssl 删除后,在末尾添加 --with-http_v3_module --with-stream_quic_module --with-cc-opt=-I../boringssl/include --with-ld-opt='-L../boringssl/build/ssl -L../boringssl/build/crypto 后,记下来,后续编译时需要使用

需要注意 BoringSSL 的路径,要指向上一步的使用的 boringSSL 路径

# 获取 Nginx-quic 代码,或者去网站下载自己需要的版本:https://hg.nginx.org/nginx-quic/tags
hg clone -b quic https://hg.nginx.org/nginx-quic

# 编译安装
cd nginx-quic
./auto/configure 上面记下来的选项,拷到这里
# 一核就 -j2,四核就 -j8
make -j2

结束后,Nginx 二进制文件会生成在 objs 路径下

启用

替换 Nginx

# 查看当前用的 Nginx 在哪
which nginx

# 备份
cp /Nginx路径/nginx /Nginx路径/nginx_bak

# 替换为 Nginx-quic
cp ./objs/nginx /Nginx路径/

make upgrade

修改 Nginx 配置文件

Nginx 配置文件通常会在 /etc/nginx/nginx.conf,修改其中的内容如下

    server {
        # 注意是 Http2
        listen       443 ssl http2;
        # 加上这行,注意是 QUIC,http3 已弃用
        listen       443 quic reuseport;
        server_name  域名;

        ssl_certificate  /证书路径.crt;
        ssl_certificate_key  /证书路径.key;
        ssl_session_cache  shared:SSL:1m;

        location /home/ {
            # 加上这行
            add_header Alt-Svc 'h3=":443"; ma=86400';
            root   /home/www;
            index  index.html index.htm;
        }
    }

修改完成后,执行 nginx -s reload 以更新配置

此时如果 Nginx 会监听 443 的 UDP 端口,说明配置成功,可以执行 lsof -i:443 进行查看,可以得到如下显示

COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
nginx 3267 www 7u IPv4 33064242 0t0 TCP *:https (LISTEN)
nginx 3267 www 11u IPv4 33591364 0t0 UDP *:https
nginx 12777 root 7u IPv4 33064242 0t0 TCP *:https (LISTEN)
nginx 12777 root 11u IPv4 33591364 0t0 UDP *:https

端口放行

需要为 443 端口的 UDP、TCP 协议开启放行

客户端设置

Chrome 浏览器可以访问 chrome://flags,搜索 quic 开启 QUIC 支持
Chrome 开启 QUIC 支持

浏览器启用后,可以通过这个 URL 进行测试,页面上会提示你的浏览器是否可以使用 QUIC

需要注意,如果开启了代理服务,可能导致 QUIC 不生效,需要关掉后进行测试

参考

Http/3.0 测评

多资源

在一个页面中加载大量资源,下列各图为单个页面加载 200 个单像素图片,在 Http 各协议环境下的效果

Http/1.1 表现

浏览器为 Http/1.1 开启了 6 个连接来处理这些图片的请求

Http/2 表现

Http/3 表现

结论:在 Http/2 和 Http/3 中,浏览器都复用单个连接来加载资源,比 6 个连接的 Http/1.1 速度还快很多,可见 Http/2 的优化不是盖的,而且 Http/3 完全保留了这些特征。但是 Http/2 和 Http/3 相比差距不大。

大文件

Http/3.0 加载大文件时表现怎样,直接上图,作为对照,先看 Http/2 的表现:

Http/2 大文件5M

Http/2 协议下,2M 带宽加载 5M 的文件,耗时 16.23s,算是跑满了带宽,估计 Http/3 也出色不了更多

Http/3 大文件

不是放错图了,它确实报错了。测试期间切换了各种时间、空间,更换了各种网络环境,开关了系统的各种代理、VPN 设置,都是这个结果:加载途中中断。

进行一番搜索,发现也有不少人遇到这个问题的样子,解决办法似乎只有关掉 QUIC 支持这一个办法能彻底奏效~~(那还测个寂寞呀)~~。

结论:貌似 QUIC 的应用现阶段似乎还是不太成熟的(本打算跳过这个测试的,但测试的目的并不是为了给 QUIC 打广告)

网络延迟环境

500ms 延迟

Http/2 500ms 延迟

Http/3 500ms 延迟

在具有一定延迟的环境下,Http/2 和 Http/3 的差距已经很明显,或者说基本没差别

5s 延迟

Http/2 5s 延迟

Http/3 5s 延迟

在高延迟的网络环境下,Http/3 的表现仍然很出色

结论:QUIC 在高延迟的网络环境下表现很优秀

丢包网络环境

20% 丢包

Http/2 20%丢包

Http/3 20%丢包

在具有一定丢包的网络环境下,http/3 的表现比 Http/2 优秀不少

50% 丢包

Http/2 50%丢包

Http/3 50%丢包

在高丢包的网络环境下,Http/2 的表现十分尴尬,但 Http/3 受到的影响却很小

结论:QUIC 在高丢包的网络环境下表现极佳

后记

Http/3.0 在弱网环境(丢包、延迟)下,表现比较优秀。但是与过去不同,现在通常使用的网络状况都比较良好,HTTP/3 的优势似乎并没办法发挥出来。