查看: 94|回覆: 0

[DotNet] Kestrel 框架中, http1 与 http2 的性能对比

[複製鏈接]

1

主題

0

回帖

0

積分

热心网友

金币
0
閲讀權限
220
精華
0
威望
0
贡献
0
在線時間
0 小時
註冊時間
2012-8-2
發表於 2026-2-26 15:56:00 | 顯示全部樓層 |閲讀模式

作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢!

  • cnblogs博客
  • zhihu
  • Github
  • 公众号:一本正经的瞎扯

(文中的 http2 是指明文的 http2 协议,也叫 h2c, 并未测试 TLS 加密的情况)
如果仅从协议的角度对比,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 的模式来使用 http2,http2 会比 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:DefineConstants=UNIX -p:AllowUnsafeBlocks=true \
	  -p:PublishAot=true \
	  -p:StripSymbols=false \
	  --self-contained true \
	  -c Release -o $(BUILD_DIR)
  • http1 和 http2 采用同样的 callback 函数

服务器运行环境

  • 运行于 linux amd64 环境,在 docker 容器中运行
  • 限定一个 cpu
    • CPU 型号:Intel(R) Core(TM) Ultra 7 265KF, 小核, 4.5GHz
  • 内存 256 MB
  • 限制线程池的线程数为 1: ThreadPool.SetMaxThreads(1, 1)
    • 为何限制,请看前一篇:C#的 ThreadPool.SetMaxThreads() 配置最大线程数到底对性能有多大影响
  • 客户端在同一个机器上请求服务器,尽量达到单核 100% 的 CPU 占用率,然后在客户端统计 QPS
docker run -it --rm \
	  --platform=linux/amd64 \
	  --cpuset-cpus="19" \
		-m 256m \
	  -v $(BUILD_DIR):/app \
	  --network=host \
	  mcr.microsoft.com/dotnet/runtime:10.0 \
	  /app/Http2EchoServer \
	    -http2.port=9081 \
		-http1.port=9082 \
		-threadpool.max=1

nghttp2 压测

  • 压测 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?seq=9999
  • 120 个 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?seq=8888
  • 最优性能组合为:
    • 连接数 8
    • max-concurrent-streams = 60, 每个 tcp 连接上并发 60 个 stream

golang 客户端+http1的模式压测

  • 源码请看: https://github.com/ahfuzhang/QiWa/tree/v0.1-http-compare/code-snippets/GolangHttp2Client
  • 编译: make build
  • 运行: make run

golang 客户端 + 每个 tcp 连接上多个并发的模式

  • 源码: https://github.com/ahfuzhang/QiWa/tree/v0.1-http-compare/code-snippets/GolangHttp2ClientV2
  • 编译: make build
  • 运行: make run
  • 最佳配置:
    • tcp 连接数 8
    • 每个 tcp 连接上 40 个并发

golang 客户端 + 基于 tcp 协议来实现 http2 客户端

  • 源码: https://github.com/ahfuzhang/QiWa/tree/v0.1-http-compare/code-snippets/GolangHttp2ClientV3
  • 编译: make build
  • 运行: make run
  • 最佳配置:
    • tcp 连接数 16
    • 每个 tcp 连接上 80 个并发stream (不是 80 个协程)

总结

  • http2 虽然比 http1 快了 4 倍,但是 rpc 的场景,自定义协议肯定更快
  • c 实现的 nghttp2 的性能很强悍,我用 golang 实现的版本与之还有一大段距离
  • Kestrel 框架的性能相当强悍 (虽然多核情况下可能会变慢)

希望对你有用。😃



来源:https://www.cnblogs.com/ahfuzhang/p/19641964
回覆

使用道具 舉報

您需要登錄後才可以回帖 登錄 | 立即注册

本版積分規則

相关侵权、举报、投诉及建议等,请发 E-mail:qiongdian@foxmail.com

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部