同一份实验报告里我写下过两个差距:21% 和 3%。21% 那条拿去做了决定,3% 那条只写了「没测出差异」。两条的差别不在数字大小。测之前我先量过这台机器自己抖多少:3% 落在抖动范围里,21% 刚出头。我的判断是,一个性能数字能不能用来做决定,取决于三件事:机器本身抖多少、这组跑了几次、这个数在什么条件下成立。三样缺一样,它就只能当参考。
先量机器自己抖多少
实验集群是 1 台 8 核 15 GiB 的工作机,上面同时跑着四五组实验。etcd 写盘常停顿 5 到 12 秒,最长一次卡了 18.9 秒。我要测的东西在几十秒量级——60 个沙箱同时建,就绪中位数 21 秒上下。
噪声能占到被测时间的 10% 到 20%。
判据是测之前写死的:经引擎建比直接建 pod 慢不到 10%,就不动架构。60 个那组实测经引擎 21.7 秒、直接建 21.1 秒,差 3%。
3% 落在噪声里,而且这组每边只跑了 1 次。只跑一次,噪声又和差值同量级,这个对照做不出判定:它可能真慢 3%,也可能真快 3%,一次 etcd 停顿就够把两边换个位置。能写的只有「没测出差异」。
这么写有代价:这组对照的机器时间照样花了,最后进报告的只有一句话,没留下一个能被引用的数字。
按预先定的判据,没测出差异同样是不动架构,结论没变。但措辞得跟着证据走。「差不到 10%,不动」和「慢 3%,在容忍范围内」是两句话,后一句给了读者一个我手里没有的数——下次有人拿这篇报告去算 3% 的累积影响,他算的是噪声。
报告里另一组对照:预拉镜像并发开到 2 时中位数 44.3 秒,交给 kubelet 现场拉(并发 5)56.0 秒,差 21%。噪声 10% 到 20%,21% 刚够出头,方向和机制也对得上。这条我当结论用了。
同一份报告里,哪些数能当结论用,得一条一条判。
噪声一致时,比值还能用
只跑一次的数还能用,只是得降一档。
控制器访问 Kubernetes 的客户端限速默认每秒 100 次。减半到 50,1000 个建 pod 的总时间从 69.17 秒变成 141.55 秒,几乎严格翻倍。这个判断站得住,不是因为 141.55 这个数准,是因为翻倍比噪声大得多,而且两边跑在同一台机器上,etcd 抖动对两边影响方向一致。
反向那次更干净:控制器 CPU 从 0.5 核加到 2 核、限速不动,时间完全没变。它大部分时间在限速器里等令牌,CPU 本来就不是瓶颈。这种「改了配置没反应」的结果不依赖测量精度——时间有没有动一眼能看出来,不用管那几个秒数准到哪一位。
比值和机制能带走,绝对数带不走。调完限速实测每秒建 263 个 pod,这个数不能拿去给生产环境承诺容量:它产自一台抖着的 8 核机器和 50 台假节点。
假节点那条线画在 kubelet 上
1000 并发那组用了 50 台 KWOK 模拟节点。这些节点只在 Kubernetes 里登记,不下载镜像,不运行容器。
KWOK 伪造的是 kubelet 向 apiserver 汇报节点和 pod 状态这一段。线以上全是真的:调度器怎么选节点、watch 事件的量、控制器回写状态的次数、客户端限速、控制器 CPU 被限流。线以下全是假的:镜像下载、容器启动、CPU 争抢。
实验的适用边界就是这条线。控制面上的机制结论可以直接带走:新版控制器每建一个沙箱要改写自己那个对象约 6.6 次,撞上每秒 100 次的上限,折合每秒最多建 15 个。1000 ÷ 15 ≈ 66 秒,实测 69.17 秒,重跑 64.99 秒。这串算术跟节点真不真跑容器没关系。时间数字只能看量级。
同一套方法我在 GPU 调度上用过一次。50 台 8 卡机器全是伪造的,400 张卡一张真的都没有。默认限速下 90 秒只分出 29 个整卡请求,一共 40 个;限速调到每秒 100 次后,95% 的请求在 1.52 秒内分到卡。要测的四件事全在控制面:卡分给谁、额度怎么记、抢占时按什么拓扑挑、排队按什么顺序,没有一件要等卡真的算起来。
瓶颈会随规模换位置。60 个沙箱那个规模,卡住它的是节点侧 init 容器的资源记账;到 1000 个才换成控制面每秒 100 次的 API 限速。「调好配置就差不到 5%」这个结论也带规模边界,它只在 60 这个量级上验过。
没测成和测出不行是两回事
报告里还有一批数字根本不存在。
从快照分叉出沙箱,试了 8 次全失败。借来的实验程序能分给沙箱的内存被别的实验占得只剩约 350 MiB,一个任务环境要几个 GB,放不下。这是环境装不下,不是快照分叉这条路不可行。
防火墙要做到「只放 kubelet 的探测通过」需要 nftables 0.9.5 以上,集群上是 0.9.3,记「没测成」。
工作机只有 1 台,「在 A 机器预拉镜像、在 B 机器建沙箱」这条路一次都没跑过。
还有一次沙箱误删——建好 120.7 秒之后被删掉——复跑一轮加 4 个冷建都没再出现,报告写「未复现」。根因定位到原型里一段特有逻辑,但同样的问题在多副本部署下也会有。防护保留,依据写的是那次事故本身,不是复现结果。
未复现、没测成、测出不行,对应三个不同的后续动作:未复现要留根因和适用边界,没测成要留复测条件,只有测出不行才能把一个方向关掉。都写成「不行」,当下省几行字,代价是以后重测的人拿不到复测条件,一个只是装不下的方案被当成走不通。