Skip to content
bitzorcas
中EN

Guide

性能基线与回归判断

为构建门禁、API、数据库、消息和后台作业建立可重复的性能证据,正确区分现有耗时报告与待建设的运行时基准。

Last updated

性能基线是“在可重现条件下比较同一场景”的协议,不是一张脱离硬件、数据量和版本的速度榜。BitzOrcas 当前已经能从验收脚本记录工程门禁耗时,但这不等于仓库已有完整 API/数据库性能门禁;运行时场景仍需团队建立稳定负载、预算、存档和回归判定。

测量闭环

否是

定义场景与预算

固定环境与数据

预热并验证正确性

重复测量

与同基线比较

Trace / Profile 定位

是否可接受?

优化并复测

记录证据/例外

先验证结果正确,再测速度。缺少租户过滤、跳过消息投递或吞掉错误会让数字更好,却是功能回归而不是性能优化。

两类不同基线

基线当前仓库状态主要用途
工程门禁耗时report-acceptance.sh 已记录每步 duration发现 restore/build/test/template/trim 退化
运行时业务性能授权容量基线已内置;其余场景按环境建立判断 API、SQL、broker、JobHost 是否满足 SLO

不要把前者的“Application.Tests 用时”解释成后者的“应用吞吐”。门禁耗时受 SDK 缓存、NuGet、生成器和测试数量影响;运行时基线受数据、并发、网络和依赖容量影响。

工程门禁耗时

Terminal window
# 生成 13 步验收报告;每步包含状态、耗时、命令和摘要。
scripts/build/report-acceptance.sh
# 保存环境信息,后续比较必须使用同一 SDK/RID 与近似机器。
dotnet --info > .verify-output/dotnet-info.txt
git rev-parse HEAD > .verify-output/commit.txt

重点观察 Restore、Build、Unit、Application、Architecture、CodeGeneration、Template、Integration without Docker 和 Trim Publish。若某步明显变慢,先单独重复至少三轮,再判断是否是缓存冷启动或共享 CI 噪声。

Terminal window
# 对异常步骤重复测量;不要用 --no-build 改变原始测量边界。
time dotnet test tests/BitzOrcas.Application.Tests --configuration Release
time dotnet test tests/BitzOrcas.Application.Tests --configuration Release
time dotnet test tests/BitzOrcas.Application.Tests --configuration Release

首次 restore、首次模板实例化和 Docker 拉镜像应单独标注为冷启动,不能与热缓存中位数混合。

已内置的第一个运行时基线

仓库已有可复用样板:PortRepositoryParityTests.Authorization_Uncached_Rbac_Should_Emit_Repeatable_Capacity_Baseline(独立分片 authorization-capacity)以 10 租户 × 1000 次未缓存 RBAC 为负载,输出 P50/P95/P99、吞吐(ops/s)、CPU 时长、GC 分配字节与工作集增量。为下一个场景建基线时,直接复用它的测量结构与报告字段,而不是另起格式。

运行时场景清单

一个商业框架至少应覆盖这些端到端场景:

场景负载变量必看信号
授权读取权限数、角色数、缓存冷热p95/p99、cache hit、错误率
租户化列表行数、过滤器、排序/分页DB duration、扫描行、分配
事务写 + CAP并发、消息大小、broker 延迟API latency、outbox backlog、消费延迟
文件预签名对象存储延迟、并发会话外部依赖、超时、失败率
Workflow 完成任务流程深度、并行分支、变量大小DB 锁、timer backlog、吞吐
搜索/报表索引规模、投影宽度、时间窗口p99、内存、依赖 CPU
JobHost批大小、重试、积压量lag、吞吐、失败/死信

每个场景都需要固定输入和正确性断言。例如列表压测不仅记录 200,还要验证 tenant、总数、排序和分页没有因优化而变化。

基线记录格式

# 示例记录结构;实际结果应存入团队约定的可追溯制品库。
scenario: workflow-complete-task
commit: 0123456789abcdef
runtime: .NET 10.0.x
environment: perf-sqlserver-2026-07
dataset: 100-tenants-1m-instances
load:
concurrency: 32
duration: 10m
result:
# 延迟、吞吐和错误率必须来自同一轮负载,不能跨运行拼接。
throughput_per_second: 0 # 用实测值替换;0 不是框架承诺。
p95_ms: 0
p99_ms: 0
error_rate: 0
notes: warm-cache, no deployment overlap

记录必须包含 Commit、Runtime、Release/Debug、CPU/内存/OS、容器资源、数据库版本、数据规模、租户数、索引状态、缓存冷热、并发、请求分布、持续时间、错误率、吞吐、p50/p95/p99、CPU、分配和依赖延迟。

可比较性规则

  1. 同一基线只比较同硬件等级、依赖版本、数据规模和负载模型。
  2. 固定客户端与服务端时钟源,记录压测机是否成为瓶颈。
  3. 预热 JIT、连接池和常用缓存,但另保留冷启动场景。
  4. 使用多轮样本,报告中位数和方差,不只挑最快一轮。
  5. 部署、备份、索引维护等干扰事件必须记录。
  6. 测量方法改变时建立新 baseline ID,不拼接旧曲线。

跨机器的绝对毫秒通常不可直接比较。优先比较同环境相对变化,并以明确 SLO/资源预算作为最终边界。

判断回归

平均值会掩盖尾延迟,单看 p99 又可能被少量基础设施故障支配。判定应同时看:吞吐、p50/p95/p99、错误率、超时率、CPU、内存/GC 分配、数据库与 broker 延迟、队列积压。

候选判定示例:
- 正确性断言必须 100% 通过;否则直接失败。
- p95/p99 与错误率不得超过场景预算。
- 相对回归必须连续多轮出现,且超过历史噪声带。
- 资源成本增长即使延迟未变,也要解释原因。

这些阈值是团队为具体环境制定的策略,不是 BitzOrcas 当前源码内置的统一数值。不要在说明书中虚构全平台固定 TPS 或 p95 承诺。

定位回归

先把变化最小化到一个场景,再按链路分段:客户端排队、ASP.NET Core、授权/租户 pipeline、序列化、ORM/SQL、Redis、RabbitMQ、对象存储或 JobHost。使用 trace 找最长 span,使用 profile 区分 CPU 与 allocation,使用数据库计划判断扫描、索引和锁。

如果新增安全校验导致合理成本增长,记录风险收益、预算影响、Owner 与优化计划;不能静默放宽阈值。例外必须有到期日和运行态告警。

常见陷阱

  • 用 Debug 或附加调试器的结果建立发布基线;
  • 把首轮 JIT、首次镜像拉取混进稳定样本;
  • 多租户查询只验证速度,不验证隔离;
  • 只测成功路径,遗漏超时、取消、并发冲突和依赖降级;
  • 只看 API latency,把积压转移给 Outbox/JobHost;
  • 在共享 CI 抖动中用单次耗时阻塞合并;
  • 改变数据量、索引或负载后仍沿用旧 baseline ID。

交付清单

  • 场景、数据、正确性断言和 SLO 均可复现;
  • 原始结果和汇总绑定 Commit 与环境;
  • 冷/热状态、重复轮次和方差已记录;
  • API、数据库、broker、缓存与 JobHost 信号可以关联;
  • 回归有最小复现、根因、修复前后对比;
  • 例外有 Owner、到期日、监控与退出条件;
  • 文档明确区分“现有自动门禁”和“建议建设的基准”。

另见

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%