KPanel 运行时性能基线

July 28, 2026 · View on GitHub

测试日期:2026-07-28 测试提交:7ea8eaf 测试版本:0.24.0-perf

结论

当前版本适合单管理员日常使用,常规只读请求吞吐和稳定性通过;但在 256 MiB 容器限制下,并发密码校验会触及 cgroup 内存上限,发布前应先调整 登录哈希并发或容器内存策略。

项目结论
常规页面和会话 API通过,10 并发约 4,400 req/s,无错误
Agent 实时采集单用户可用;并发时重复采集导致延迟和内存上升
登录单次约 225 ms;双并发内存余量不足;第三路会被 429 限流
长连接100 个空闲 Keep-Alive 连接未增加可见 RSS,关闭后 FD 正常回收
前端传输资源已拆包并支持 304,但直连模式未启用 gzip/Brotli
镜像和持久化镜像约 7.92 MiB;只读压测未造成异常数据增长

本轮总体判定为有条件通过。阻断项是登录内存边界,不是常规 API 吞吐。

测试边界

测试使用当前源码构建独立 Panel 镜像和同版本 Agent,不复用线上 Panel 数据:

  • 验收机:Debian 13、8 vCPU、约 7.76 GiB RAM、Docker 29.6.2;
  • Panel:仅监听 127.0.0.1:18080,限制 1 CPU / 256 MiB / 128 PIDs
  • Agent:独立 socket、token 和状态目录,只执行 GET 观测;
  • 压测从同一宿主机发起,结果不包含公网延迟;
  • 未执行安装、更新、备份、还原、卸载等会改变宿主机状态的任务;
  • 活跃交互终端依赖真实脚本任务,本轮只验证连接保持和代码中的长轮询边界。

因此,本报告是 Panel/Agent 运行时基线,不替代 LDNMP、应用安装和公网链路的 专项实机验收。

请求基准

共执行 22 组、114,050 次 GET 请求,累计响应约 67.97 MiB, 所有请求均完成,HTTP 错误和客户端错误均为 0。

接口并发请求数吞吐 req/s平均 msP95 msP99 ms
/api/v1/health120,0002,290.270.4290.6411.121
/api/v1/health1020,0004,394.922.2665.2187.370
/api/v1/health5020,0004,309.1311.56728.00839.832
/api/v1/auth/session1010,0004,510.282.2084.9736.952
/2010,0003,715.865.36413.34920.117
/api/v1/sites102,0003,110.913.1916.25815.771
/api/v1/capabilities110010.0199.901117.884128.505
/api/v1/capabilities1010051.29189.674240.498247.327
/api/v1/system/summary11006.14162.927165.618170.002
/api/v1/system/summary1010057.69170.529186.452188.301
/api/v1/docker/summary101,000677.0314.73518.60522.304
/api/v1/docker/containers110011.9183.92696.975102.882
/api/v1/docker/containers1010034.42290.008304.474309.570
/api/v1/apps15010.3296.885110.876124.234
/api/v1/apps105029.20339.428369.935371.257

/api/v1/system/summary 包含固定 150 ms CPU 采样窗口,因此约 163 ms 的单请求耗时符合当前实现。Docker 容器列表会逐容器读取详情,应用列表还会 组合完整应用目录,所以二者在并发下存在明显的重复工作。

CPU、内存、线程与 FD

常规只读负载

  • Panel 稳态 RSS 约 15–17 MiB,线程 8–9,FD 8–10
  • Agent 空闲 RSS 约 20–21 MiB
  • Agent 在并发实时采集期间峰值 RSS 约 91.7 MiB,线程由 13 增至 17,FD 由 7 增至 12
  • 压测结束后 Agent RSS 先降至约 55 MiB,数分钟后约 40.6 MiB, 未观察到 FD 泄漏;
  • 主要 GET 套件中,Panel 消耗约 23.8 CPU 秒,Agent 约 25.3 CPU 秒
  • 8 核宿主机 load 由 0.09 升至 3.19,测试期间无请求失败。

启动

5 次冷启动到健康检查成功:

  • 平均 606.4 ms
  • 最快 524 ms
  • 最慢 661 ms
  • 启动 RSS 约 76.2–79.2 MiB

每次启动都会生成 Argon2 假密码哈希,以避免用户名枚举造成的时序差异。 这会产生约 64 MiB 的安全性相关瞬时内存,不是页面业务泄漏。

登录内存边界

默认 Argon2 参数为 64 MiB / 3 iterations / 4 threads,登录哈希并发上限为 2:

场景结果
单并发,5 次全部 200,平均约 224.74 ms
双并发,6 次全部 200,平均约 542.98 ms
三并发,6 次2 次 200、4 次 429,限流生效

风险事实:

  • 混合顺序和并发登录后,cgroup memory.peak 到达 256 MiB 上限;
  • memory.events.max 增长,说明内核已经进行限额回收;
  • 本轮 oom=0oom_kill=0,容器没有退出;
  • 高 RSS 在 20 秒空闲和短时并发健康请求后仍未立即回落;
  • 两轮各 20,000 次单连接健康请求触发 Go GC/回收后,RSS 最终回到约 17.1 MiB

这不是已发生 OOM,但在当前 256 MiB 限制下缺少可靠安全余量。

空闲连接

同时保持 100 个 HTTP Keep-Alive 连接 20 秒:

  • Panel FD 从 8 增至 108
  • RSS 保持约 17.3 MiB
  • 线程保持 8
  • 连接关闭后 FD 回到 8

当前交互终端采用最长 1 秒的有界长轮询,不是永久 WebSocket。真实脚本输出和 输入延迟仍应随安装、建站、体检任务做专项验收。

前端和网络传输

生产镜像大小为 8,306,670 bytes,Web 静态目录为 2,105,348 bytes / 219 files

资源原始大小gzip 后参考值
主 JS144,073 B53,894 B
主 CSS55,755 B10,598 B
Overview 路由478,802 B90,893 B
交互终端路由343,900 B87,410 B

直连 Panel 验证结果:

  • JS、CSS 和 /api/v1/apps 在客户端声明 Accept-Encoding: gzip 后仍返回 原始内容,没有 Content-Encoding
  • /api/v1/apps 单次响应约 196,868 B
  • 哈希静态资源缓存时间为 1 小时;
  • 静态资源带 Last-Modified,条件请求正确返回 304

如果前置反向代理开启压缩,可补偿直连模式的传输开销;IP + 端口直连不会获得 该收益。

优化优先级

P0:收紧登录内存边界

在以下方案中选择并实测一种,不能只修改配置后推测:

  1. 256 MiB 限额下将密码哈希并发降为 1;
  2. 保留双并发,但提高 Panel 内存限额并设置合理的 GOMEMLIMIT
  3. Argon2 参数调整只能在完成安全评估后考虑,不能单纯为省内存降低强度。

验收应断言双登录、连续登录及登录后普通 API 负载均不产生 memory.events.max,并保留 oom_kill=0

P1:合并 Agent 重复采集

  • capabilities、Docker 列表和应用清单增加 1–3 秒短缓存;
  • 对并发相同 GET 使用 singleflight,避免同一时刻重复扫描;
  • 消除容器列表中的逐容器 inspect,或使用有界并发与短缓存;
  • system/summary 可共享后台 CPU 采样结果,避免每个请求固定等待 150 ms。

缓存只能减少重复观测,写操作完成后必须失效,不能成为第二套业务状态。

P1:压缩与静态缓存

  • 为文本静态资源和较大的 JSON 响应启用 gzip/Brotli;
  • 对带内容哈希的静态文件使用长缓存和 immutable
  • 保留 index.htmlno-cache
  • 同时验证域名反代和 IP + 端口两种访问方式。

P2:前端载荷

  • 优先分析 Overview 478,802 B 路由包;
  • 交互终端已经按路由懒加载,保持该边界;
  • 应用清单内容较大,先压缩,再评估是否需要摘要/详情拆分,避免过早引入第二套 状态接口。

复跑

仓库提供无第三方依赖的只读基准工具:

python3 scripts/runtime-benchmark.py \
  --base-url http://127.0.0.1:8080 \
  --path /api/v1/health \
  --requests 20000 \
  --concurrency 10

认证接口使用 curl Netscape cookie jar:

python3 scripts/runtime-benchmark.py \
  --base-url http://127.0.0.1:8080 \
  --path /api/v1/auth/session \
  --cookie-file ./cookies.txt \
  --requests 10000 \
  --concurrency 10

正式发布验收应在干净的 Debian、Ubuntu 和 Rocky/AlmaLinux 主机上复跑,并增加 实际安装、终端长轮询、备份/还原、断网和低内存场景。