[DOTNET] KESTREL 框架中, HTTP1 与 HTTP2 的性能对比

张开发
2026/5/1 5:13:09 15 分钟阅读

分享文章

[DOTNET] KESTREL 框架中, HTTP1 与 HTTP2 的性能对比
如果仅从协议的角度对比http2 会比 http1 更快吗如果更快能快多少基于以上疑问我基于 C# 的 Kestrel 框架做了一个协议性能的对比。结论节约大家的时间先说结论:在同样的运行环境同样的业务逻辑情况下。最好情况http2 比 http1快 4.03 倍从处理字节数上看http1 平均每个请求 230 字节http2 平均每个请求 112 字节。就单个请求而言http2 的包体积只有 http1 的包的 48.7%.http2 是二进制协议理论上一定比 http1 这样的文本协议更快。发挥 http2 的性能优势的关键参数是MaxStreamsPerConnection(我测试时设置为 200)也就是说一定要在一个 tcp 上并发多个 stream才能发挥 http2 的性能优势。从应用上说api 服务、rpc 服务使用 http2 更好文件下载(图片、资源文件等)、html 页面输出、文件上传、大数据量的 post 等等使用 http1 更好使用 http1 在代理服务器上也能获得性能优势。请看前一篇 为什么在代理服务器上测试 http2 的转发性能比 http 1 更低是否简单的使用 http2 的客户端就能轻松实现 http2 比 http1 提升了 4 倍答案是否定的http2 的客户端并不简单。我一共使用了四种 http2 的客户端来测试使用 nghttp2 客户端C 语言实现专门用于压测的工具测试得到 http2 比 http1 快 4.03 倍使用 golang 客户端每个 HttpClient 对象对应一个协程每个协程内一发一收http2 的吞吐量是 http1 的 80%如果以 http1 的模式来使用 http2http2 会比 http1 慢使用 golang 客户端每个 HttpClient 对象上限制只有一个 tcp 连接每个 HttpClient 对应 40 个协程一发一收http2 的吞吐量是 http1 的 1.86 倍通过限制 tcp 连接来让每个 tcp 连接上并行多个 stream这才是 http2 client 的正确用法压测客户端启动两个进程http2 的吞吐量是 http1 的 2.28 倍由此说明 golang 的 http2 的 client 内部有很多锁单个进程不如多个进程性能好。使用 golang 客户端完全基于 tcp 协议来实现每个 tcp 连接上一个协程专门用于 send一个协程专门用于 recv: http2 的吞吐量是 http1 的 2.68 倍nghttp2 客户端可能做了一些 socket option 的优化导致做到了最好的压测性能如果希望做到 http2 上的极致性能基于 tcp 来实现是个好主意压测环境说明基于 KESTREL 的C# 服务端源码位置: https://github.com/ahfuzhang/QiWa/tree/v0.1-http-compare/code-snippets/Http2EchoServer使用 dotnet 10 编译make -f Makefile_linux build$(DOTNET) publish $(PRJ).csproj \ -r linux-x64 \ -p:DefineConstantsUNIX -p:AllowUnsafeBlockstrue \ -p:PublishAottrue \ -p:StripSymbolsfalse \ --self-contained true \ -c Release -o $(BUILD_DIR)http1 和 http2 采用同样的 callback 函数服务器运行环境运行于 linux amd64 环境在 docker 容器中运行限定一个 cpuCPU 型号Intel(R) Core(TM) Ultra 7 265KF, 小核 4.5GHz内存 256 MB限制线程池的线程数为 1:ThreadPool.SetMaxThreads(1, 1)为何限制请看前一篇C#的 ThreadPool.SetMaxThreads() 配置最大线程数到底对性能有多大影响客户端在同一个机器上请求服务器尽量达到单核 100% 的 CPU 占用率然后在客户端统计 QPSdocker run -it --rm \ --platformlinux/amd64 \ --cpuset-cpus19 \ -m 256m \ -v $(BUILD_DIR):/app \ --networkhost \ mcr.microsoft.com/dotnet/runtime:10.0 \ /app/Http2EchoServer \ -http2.port9081 \ -http1.port9082 \ -threadpool.max1NGHTTP2 压测压测 http1 端口的命令如下:docker run --rm -it --network host goodideal/nghttp2:latest \ h2load -p http/1.1 -c 120 -t 8 -n 2000000 \ http://127.0.0.1:9082/echo?seq9999120 个 tcp 连接时测试得到最优性能表现压测 http2 的命令如下:docker run --rm -it --network host goodideal/nghttp2:latest \ h2load -p h2c -c 8 -t 8 --max-concurrent-streams 60 -n 1000000 \ http://127.0.0.1:9081/echo?seq8888最优性能组合为连接数 8max-concurrent-streams 60, 每个 tcp 连接上并发 60 个 stream

更多文章