2330 字
约 7 分钟
21
S27-A14 · 实测记录的写法:结论、环境与可复现

一份实测笔记写着"Redis 比 MySQL 快 20 倍",三个月后有人照此结论选型,落地后发现两者差距不到两倍。翻开原笔记,没有任何环境信息:多大的数据量、什么查询、用什么机器、串行还是并发——它记录的其实是一个无法验证的印象。

实测记录的价值不在于结论,而在于别人能不能在你的条件下复现,以及能不能判断你的条件与他的差距。缺了环境与步骤,结论就只是一句话,无法被使用。


1. 一条可用的实测记录要有五段

段落 回答什么
问题 为什么做这次实测
环境 软硬件版本、数据量、配置
方法 怎么测的、多少轮、取什么统计量
结果 原始数据与结论
失效条件 什么情况下这个结论不成立

五段之外还有一个隐含要求:记录要有时间与作者。技术结论有保质期,两年前的实测在版本更迭后可能已不成立;而没有作者,就没人能问"当时为什么这么测"。

第五段最少被写,却决定了这份记录能不能被别人安全引用。"Redis 快 20 倍"在"数据能放进内存"的条件下成立,在"数据量超过内存"的条件下可能完全不成立。

2. 环境要写到什么程度

要素 必写 说明
版本号 是 具体到 minor(如 8.0.34)
硬件规格 是 CPU 核数、内存、磁盘类型
数据量 是 行数或字节数,不是"中等规模"
关键配置 是 影响结论的那几项
网络位置 视情况 同机、同机房、跨地域

配置项要挑"影响结论的那几项"写,不必全量。判断方法是问:改掉这一项,结论会不会变。会变的就是关键配置。

第一项最容易漏:同一个数据库的不同小版本,执行计划可能不同。写"MySQL 8"不够,要写 8.0.34。

// 环境块:复制粘贴即可,比叙述可靠
env:
  os: "Ubuntu 24.04, kernel 6.8"
  cpu: "8 vCPU (Xeon Platinum 8259CL)"
  mem: "32 GB"
  disk: "NVMe SSD, 3000 IOPS"
  db: "MySQL 8.0.34, buffer_pool=8G, innodb_flush_log_at_trx_commit=2"
  cache: "Redis 7.2.4, maxmemory=8G, maxmemory-policy=allkeys-lru"
  data: "orders 2000 万行, 平均行 480B, 索引 3 个"

3. 方法要说清的三件事

事项 差的做法 好的做法
轮次 跑一次 至少 5 轮,报中位数与 P95
预热 不提 明确"前 N 次丢弃"
并发 不提 说明线程/连接数与分布

并发这一项还应当说明"并发怎么来的":是固定线程数循环发请求,还是按泊松到达。两者的排队行为不同,得到的延迟分布也不可比。

// 方法块里加一行"负载模型",避免两种测法互相比较
load_model: closed-loop(固定 16 线程循环发请求)
// 另一种是 open-loop(按固定速率发,不等待响应)——延迟含义完全不同

第二项在缓存类实测里影响巨大:首次访问必然回源,不预热就等于在测冷启动。这类细节不写,结论就无法被解释。

// 方法块:把"怎么测的"写成可执行的东西
warmup=50; rounds=10; concurrency=16
// 前 50 次丢弃(预热),后 10 轮各取一次耗时,报中位数与 P95
for i in $(seq $((warmup+rounds))); do
  t=$( { /usr/bin/time -f %e ./bench.sh $concurrency; } 2>&1 | tail -1 )
  [ $i -gt $warmup ] && echo "$t"
done | sort -n | awk '{a[NR]=$1} END {print "median:",a[int(NR/2)],"p95:",a[int(NR*0.95)]}'

4. 结果要留原始数据

做法 后果
只写结论 无法复核
写汇总统计 可复核但看不到分布
留原始样本 最好,可重新分析
留可重跑脚本 更持久,环境变化后可再测

原始数据的留存也有成本,折中做法是保留聚合后的分桶数据(每秒的 P50/P95/P99),既能重算分位数,又不占太多空间。

第四项是最有价值的形态:把实测做成一个可重跑的小脚本,半年后环境变了,重跑一次就有新结论,而不是"凭记忆更新数字"。

结果段还应当包含"没有测到的部分"。一次实测没覆盖的场景,是最容易被误当成"也没问题"的部分——比如只测了等值查询,却有人拿这个结论去判断范围扫描的性能。

5. 结论的写法:带条件

写法 可用性
"A 比 B 快 20 倍" 低
"在 2000 万行、等值查询下,A 的 P95 是 B 的 1/20" 中
"在内存可容纳工作集时 A 快 20 倍;超出后差距迅速缩小" 高
后两条 + "不适用于范围扫描与聚合" 最高

第三与第四行的差别在于是否给出了适用边界。有边界的结论可以直接支撑决策;没有边界的结论,引用者只能靠猜。

// 结论段落的三句结构
在 <条件> 下,<指标> 为 <数值>(对比 <基线> 为 <数值>)。
该结论的前提是 <关键前提>。
若 <前提不成立的情形>,结论不适用,需另行实测。

记录还要能被"部分引用":别人往往只需要你的环境块或方法块,而不是全部结论。所以三段应当用小标题分开,不要写成一大段叙述——这样引用成本低,误引用的概率也低。

// 记录的三段式结构,便于单独引用
## 环境(可单独复制)
## 方法(可单独复用)
## 结果与结论(引用时须带上前面两段)

6. 排错:五种"实测结论不能用"

现象 成因 处理方向
换环境结论全反 环境记录缺失 补环境块
无法复核 无脚本、无原始数据 留可重跑脚本
数字漂亮但线上不符 测试数据与真实分布不同 用真实分布造数
每次测都不一样 无预热、轮次太少 固定方法块
结论被滥用 没写失效条件 补适用边界

排错时有个很好用的做法:找一份结论,然后试着用它的数据反推条件。如果反推不出来,这份记录就缺了关键信息——这个过程本身就是对自己记录质量的检验。

第五项是记录者的责任:一条没有边界的结论,一定会被用到它不成立的场景里。这不是引用者的问题,因为记录里没有告诉他边界在哪。

7. 边界:什么情况不必写完整记录

场景 为什么 做法
一次性的选择(用完即弃) 无复用价值 记一行结论即可
官方基准(可信来源) 无需自测 引用并注明来源
结论只影响自己 无协作成本 简记
与既有记录重复 已验证过 引用旧记录

最后一条与共享有关:实测记录应当放在别人能搜到的地方,而不是个人笔记里。放在个人笔记里的实测,等于没做——因为需要它的人找不到,于是会重做一次,浪费的是同一份时间。

还有一些实测天然不该被复用到决策上:压力测试得到的吞吐上限。它只说明"在这个数据与这个模式下能跑多快",一旦数据分布改变,上限就不可移植——引用时至少要说清这一条。

判断口径一句话:这条结论会不会被别人拿去支撑一个决定。会,五段都要写;不会,一行就够。

复现性还有一个成本项容易被漏写:跑一遍要多久。跑一天的实测与跑十分钟的实测,别人愿不愿意复用的差别很大。


8. 自测

  1. 五段记录中,哪一段最少被写却最影响可用性?为什么?
  2. 为什么版本号必须写到 minor?"MySQL 8"为什么不够?
  3. 缓存实测里"预热"为什么必须写明?不写会导致什么误读?
  4. 为什么"留可重跑脚本"比"留原始数据"更持久?
  5. 结论段落的三句结构分别是什么?为什么"没写失效条件"是记录者的责任?
  6. 判断"是否需要完整记录"的那个问题是什么?
S27-A14 · 实测记录的写法:结论、环境与可复现
https://www.clxhxhhr.top/posts/6438/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。