Appearance
实验 2.4:4核机器全量对照 — 核数如何改写结论?
所属 Day:Day 2 — epoll/多进程/短连接压测 前置依赖:长跑稳态(20 核结论) 更新时间:2026-08-20(重构:从原 Day 2 单篇 128KB 文档拆分,对应原 §7.6,含 12 项子实验) 定位:本实验是 Day 2 的方法论高潮——用一台 4 核机器全量重跑 20 核机器的结论,剥离"核数相关"与"核数无关"的结论
一、本实验要回答的问题
20 核机器上测出"LT≈ET(均值 <2%)"、"MP 非银弹"。这些结论换个核数还成立吗?
Q1:同样的测试搬到 4 核机器,LT vs ET 的胜负会反转吗?Q2:哪些结论是"核数无关"的(跨机器稳定)?哪些是"核数相关"的(只在 20 核成立)?
二、实验设计
- 机器:4 核 / CentOS 7 (3.10.0-1160),3.6 GB 内存
- 脚本:
run_all_comprehensive.sh一键全量 12 项(短跑/长跑/并发/并发扫描/strace 完整 syscall/pidstat/LT-PURE 对比/瞬态失败复现/MP worker 分布) - 新增服务端:LT-PURE(LT 去掉 accept 循环,每次只取 1 个连接,验证 §8.6.2 方向 2)
- 结果:
results_comprehensive_20260729_215414/
三、实验数据
3.1 短跑(100 req 串行,×3)
| 运行 | LT QPS | ET QPS | MP QPS | LT-PURE QPS |
|---|---|---|---|---|
| Run 1 | 14856.6 | 14170.3 | 14349.3 | 1339.3 ⚠️ |
| Run 2 | 15496.7 | 14954.4 | 14436.3 | 14316.4 |
| Run 3 | 12903.2 | 14923.1 | 15060.2 | 14259.2 |
| 均值 | 14418.8 | 14682.6 | 14615.3 | 14287.8(排 Run 1) |
延迟(3 跑均值):P50 四者全 56-57μs 打平;P99 MP 163μs 最优(LT 424μs 含异常 / LT-PURE 144μs 排异常);LT-PURE Run 1 P999=68ms 为偶发调度抖动。
3.2 长跑(10000 req 串行,×3)
| 运行 | LT QPS | ET QPS | LT-PURE QPS | LT P50/P99 | ET P50/P99 | LT-PURE P50/P99 |
|---|---|---|---|---|---|---|
| Run 1 | 13431.2 | 11104.0 | 12804.3 | 61/175 | 62/667 | 60/140 |
| Run 2 | 13695.0 | 11383.5 | 12109.5 | 61/158 | 62/271 | 77/136 |
| Run 3 | 13716.7 | 13459.6 | 16061.1 | 60/163 | 62/161 | 54/99 |
| 均值 | 13614.3 | 11982.4 | 13658.3 | 61/165 | 62/366 | 64/125 |
3.3 并发扫描(bench.sh 10→100)
| 并发 | LT | ET | MP |
|---|---|---|---|
| 10 | ~75 | ~77 | ~78 |
| 50 | ~76 | ~82 | ~82 |
| 100 | ~77 | ~83 | ~82 |
QPS 几乎不随并发增长(10→100 并发仅 +6%)。
3.4 完整 syscall 统计(10000 req 长跑)
| syscall | LT (us/call) | ET (us/call) | LT-PURE (us/call) |
|---|---|---|---|
| close | 35 | 58 | 39 |
| accept | 14 | 18 | 14 |
| epoll_wait | 13 | 15 | 13 |
| read | 13 | 13 | 13 |
| epoll_ctl | 12 | 13 | 13 |
| fcntl | 12 | 13 | 12 |
| 总耗时 | 1.703s | 2.082s | 1.721s |
| 总调用 | 110,135 | 110,644 | 110,260 |
| 总错误 | 10,001 | 10,090 | 43 |
3.5 LT-PURE vs LT 直接对比(同一长跑内 strace)
| syscall | LT calls | LT us/call | LT-PURE calls | LT-PURE us/call |
|---|---|---|---|---|
| close | 10,000 | 44 | 10,000 | 34 |
| accept | 20,000 (50% err) | 16 | 10,000 (0 err) | 14 |
| write | 160 | 53 | 14 | 36 |
| 总耗时 | 1.851s | — | 1.682s | — |
| 总错误 | 10,031 | — | 14 | — |
3.6 瞬态失败复现(drop_caches 对照)
| 维度 | 冷启动 A(drop_caches,5 跑) | 热启动 B(正常,4 跑) |
|---|---|---|
| QPS 均值 | 15809.3 | 15870.2 |
| P50 | 57 μs | 55 μs |
| P99 | 91 μs | 95 μs |
| P999 | 134 μs | 153 μs |
差异全部 < 5%,drop_caches 对 localhost echo 无实质影响——修正了原 §7.4 的"page cache 冷启动"假说,确认为偶发调度抖动。
3.7 MP worker 连接分布
| Worker | accept 调用 | 实际连接 | 占比 |
|---|---|---|---|
| 24530 | 94 | 48 | 26.5% |
| 24531 | 98 | 50 | 27.6% |
| 24532 | 79 | 42 | 23.2% |
| 24533 | 91 | 47 | 26.0% |
均值 45.3、标准差 3.0、Gini < 0.05——SO_REUSEPORT 哈希分发高度均匀。
四、实验分析
4.1 最重磅发现:4 核上 LT 反超 ET +13.6%
| 指标 | 20 核 | 4 核 |
|---|---|---|
| LT 长跑 QPS | 17.6K | 13.6K |
| ET 长跑 QPS | 17.4K | 12.0K |
| LT vs ET | 打平(<2%) | LT +13.6% |
为什么反转:ET 的"一次唤醒循环深度随机"在低核数下被放大——4 核机器每次调度切换惩罚更重,ET 唤醒次数少但每次处理深度大,一旦被时钟中断抢占,尾延迟和吞吐都受影响;LT"持续通知"看似冗余,在资源紧张时反而成了鲁棒性缓冲。
4.2 ET 单次 syscall 在 4 核异常放大
| syscall | 20 核 ET | 4 核 ET |
|---|---|---|
| close | 28-32 μs | 58 μs(LT 的 1.7×) |
| accept | 8-9 μs | 18 μs(LT 的 1.3×) |
4 核 ET 总耗时 2.082s vs LT 1.703s(+22%)。与内核 3.10.0 的 epoll 实现、CPU 频率限制相关。
4.3 LT-PURE 的三个反直觉结论
- accept 减半对 QPS 无影响:13.7K vs 13.6K(<1%)——accept 循环省下的全是 EAGAIN 错误路径,省错误 ≠ 省时间(EAGAIN 路径内核不分配 fd,成本极低)
- 但 strace 总耗时省 9%(1.851s→1.682s):主要来自 close 44→34μs(-23%)——LT-PURE 进程内 fd 更少,close 时内核清理 epoll 就绪链表更短
- 错误 -99.9%(10031→14):accept EAGAIN 从 10000 次归零
结论:去掉 accept 循环是"代码卫生"改进(减少无意义调用),不是"性能优化"(瓶颈在 TCP 固定税,不在 accept)。
4.4 短跑 QPS 与核数无关(甚至 4 核更高)
| 机器 | 短跑 QPS | 长跑 QPS |
|---|---|---|
| 20 核 | 8.1K | 17.6K |
| 4 核 | 14.4K | 13.6K |
短跑 4 核反而高 77%——QPS 瓶颈在内核路径延迟 + CPU 频率 + 内核版本(3.10 vs 新版),与核数无关。长跑 4 核低 23%,因为稳态吞吐受单核 IPC 上限约束。
4.5 P999 尾延迟 4 核暴增 10×+
| 机器 | LT P999 | ET P999 |
|---|---|---|
| 20 核 | 137 μs | 123-178 μs |
| 4 核 | 1212-1435 μs | 1394-2771 μs |
20 核有 20 条硬件线程吸收调度抖动,4 核每次调度切换惩罚严重得多。
五、实验结论
| # | 结论 | 类型 |
|---|---|---|
| 1 | 4 核上 LT 反超 ET +13.6%(20 核打平) | 核数相关 |
| 2 | 4 核 ET close=58μs(LT 的 1.7×),总耗时 +22% | 核数相关 |
| 3 | 短跑 QPS 与核数无关(4 核反而高 77%) | 核数无关 |
| 4 | 长跑 QPS 4 核低 23%,受单核 IPC 上限约束 | 核数相关 |
| 5 | P999 尾延迟 4 核暴增 10×+ | 核数相关 |
| 6 | LT-PURE:accept 减半 ≠ 性能提升(省错误 ≠ 省时间) | 核数无关 |
| 7 | 瞬态失败 ≠ page cache 冷启动(drop_caches 对照差异 <5%),是偶发调度抖动 | 修正旧结论 |
| 8 | SO_REUSEPORT 哈希分发高度均匀(Gini < 0.05) | 核数无关 |
| 9 | close() 始终是最贵 syscall(21-28%),双机一致 | 核数无关(Day 3 动因) |
六、回答开头的问题
Q1:同样的测试搬到 4 核机器,LT vs ET 的胜负会反转吗?
答:会反转。20 核上 LT≈ET(<2%),4 核上 LT 反超 ET 13.6%——ET 的"一次唤醒循环深度随机"在低核数下被放大(close 58μs vs 35μs,总耗时 +22%)。选型结论必须标注核数:高核数 ET 略优,低核数 LT 更稳。
Q2:哪些结论"核数无关"、哪些"核数相关"?
答:核数无关(双机稳定):短跑三架构打平、close() 最贵(21-28%)、accept 循环浪费(LT-PURE 证伪"省错误=省时间")、SO_REUSEPORT 哈希均匀、瞬态失败是调度抖动非 page cache。核数相关:LT vs ET 胜负(4 核反转)、长跑 QPS 绝对值(4 核低 23%)、P999 尾延迟(4 核差 10×+)、ET close 单次耗时(4 核放大 1.7×)。
方法论收益:单机数据永远无法剥离"核数相关"与"核数无关"的结论——双机对照是把"核数"从变量中独立出来的唯一途径。
一句话总结:4 核机器把 20 核结论撕开了一半——LT 反超 ET(核数相关)、close() 最贵(核数无关);双机对照的价值不是重复实验,而是剥离"核数"变量,让每个结论都标注保质期。