uWebSockets.js 遇见Http3
HTTP/3 引入运行在 UDP 上的新(不同)传输协议 QUIC 意味着理论上和目前实验上的延迟减少,目前标准已发布,在开始之前可以参阅《WebSockets和HTTP》
uWebSockets.js 现在已经增加了实验性 HTTP/3 支持,值得一试。由于是实验性质,存在一些先决条件:
- 不是所有的平台都能够正常运行起来,文章涉及的代码只在
x64 Linux
上运行成功,基于 Docker 容器运行 - 如果
localhost
接口没有ipv6
地址,将无法工作,但可以通过./quiche-client --no-verify https://[::1]:9004/
来进行访问
quiche-client 安装
quiche 是 IETF 指定的 QUIC 传输协议和 HTTP/3
的实现,提供了用于处理 QUIC (《QUIC 简介及 NodeJs 简单示例》) 数据包和处理连接状态的低级 API。应用程序负责提供 I/O(例如套接字处理)以及支持计时器的事件循环。
具体的安装可以参阅 quice git。
uWebSockets 安装
npm install uWebSockets.js#binaries --save
服务器端点是通过一个简单的带有模式匹配和通配符的 URL 路由器定义的:
const uWS = require("uWebSockets.js");
uWS.H3App({
key_file_name: "./key.pem",
cert_file_name: "./cert.pem",
})
.get("/*", (res, req) => {
res.end("遇见H3,一切都变得美好!");
})
.listen(9004, (listenSocket) => {
if (listenSocket) {
console.log("监听端口号: 9004!");
}
});
使用 quiche-client
访问服务器很容易:
quiche-client --no-verify https://[::1]:9004/
性能
首先通过创建运行最小的 Node.js HTTP/1.1
服务器来作为参考点,无需任何路由或加密,在单核上以 100%
的 CPU 情况下进行压力:
const http = require("http");
const requestListener = function (req, res) {
res.end("HTTP1 服务");
};
const server = http.createServer(requestListener);
server.listen(8080);
在这台特定的机器上,在 100%
的 CPU 时间(一个内核)下每秒收到 18k
个请求。现在将其与 uWebSockets.js 中的 H3
进行比较。
在单核上 100%
的 CPU 情况下,每秒可以处理高达 291k
的请求,并且还是在加密和 URL 路由解析的情况下,整整 16 倍的加速!
为什么快这么多?部分原因是 HTTP/3
具有适当的请求并行性 pipelining
。所有主要 Web 浏览器都认为 HTTP/1.1
中的pipelining
不可用和禁用,但为了完整起见,将在此基准测试中启用 HTTP/1.1
流水线并再次运行它!
在所有条件相同的情况下,使用 Node.js 内置 HTTP/1.1
服务器每秒获得 28k
请求。与 uWebSockets.js HTTP/3
支持相比,仍然是 10 倍的差异。
注意:
HTTP/3
必须是TLS 1.3
加密和 URL 路由的!
很明显,与Node.js相比,性能数据是非常高的,如果想要HTTP/3
的特性,将无法使用普通的 Node.js 。
uWebSockets.js
现在构建了高度实验性的 HTTP/3
,将开始持续稳定的支持。一个大概的计划是在 6 个月内发布一个稳定版本,在 1 个月内应该发布一个包含实验支持的版本。同时,可以开始将应用程序移植到 uWebSockets.js 中。
这样做意味着可以在不改变任何业务逻辑的情况下从 uWS.App
切换到 uWS.H3App
, uWebSockets.js
在与 HTTP/1.1
相同的接口下公开 HTTP/3
。
不过目前处于概念验证阶段并且非常实验性,运行条件有点苛刻,在使用上还需谨慎。