一位开发者发现,通过 Playwright 或 Puppeteer 连接 Chrome DevTools 调试器会使基于 fetch 的上传速度降低 20 倍以上,从而使日常性能基准测试变成了误导性的数据。
引发调查的谜团
Coffer 是一款基于浏览器的文件存储系统,在将数据发送到服务器之前会对其进行加密,它通常在本地网络上进行千兆级上传。当团队测量上传速度时,发现了一个差距:下载速度达到了链路饱和,但上传速度仅为可用带宽的八分之一左右。这种差异促使团队进行了三轮代码修改,但都未能取得显著进展,直到第四次“修复”似乎带来了巨大的提升——然而,一旦移除调试器,这种提升便消失了。
团队最初的尝试
工程师们排查了常见的嫌疑对象:
- 分块大小 (Chunk size) – 将数据块从 16 MiB 翻倍至 32 MiB,吞吐量仍未改变。
- 流水线 (Pipelining) – 将下一个数据块的加密与当前上传重叠,仅获得了 13% 的微小提升,与测量误差无异。
- 并发性 (Concurrency) – 并行运行多个上传任务,总速度仍被限制在同一水平,表明存在全局上限。
这些变化都无法解释 8 倍的减速。
出人意料的对比测试
为了隔离问题,团队更换了客户端实现。使用 .NET HttpClient 在同一网络下记录到了 700 Mbps 的速度;而使用 Chromium 的 fetch() API 发出的相同请求却停滞在 140 Mbps。这种鲜明的对比指向了浏览器的网络栈是罪魁祸首——直到下一个实验证明事实并非如此。
调试器的隐藏代价
Playwright 和 Puppeteer 通过 Chrome DevTools Protocol (CDP) 驱动 Chrome。该协议会将调试器附加到浏览器进程,从而暴露网络事件、DOM 快照和控制台日志。团队进行了一项针对性测试:使用 fetch() 调用发送 Uint8Array 负载,分别在附加 CDP 调试器和不附加调试器的情况下进行测试。
- 附加调试器: 113 Mbps
调试器的存在使上传速度降低了 20 倍 以上。在普通的 Edge 窗口中进行手动测试(未附加调试器)时,速度达到了 600+ Mbps,这证实了在不受干扰的情况下,浏览器本身可以处理这些流量。
一个微小但真实的改进
虽然调试器是导致速度大幅下降的主要原因,但团队还是发现了一个真正的优化点:将请求体从 Uint8Array 切换为 Blob,使 Chromium 的速度提升了约 30%。这是一个有用的调整,但远未达到最初期望的“奇迹般”提升。
为什么这对工程师很重要
- 测量工具可能会撒谎。 自动化浏览器的性能工具本身也是测量链的一部分。
- 看起来不可能的基准测试值得进行合理性检查。 如果数值与网络容量严重背离,测量环境应该是首要怀疑对象。
- 无效的结果也很有价值。 确认某项更改没有效果可以防止在追逐“幻影 Bug”上浪费精力。
- 手动控制是廉价的保险。 在普通的浏览器窗口中运行相同的操作,可以揭示隐藏的工具开销。
反方观点:调试器不可或缺的时候
调试器提供了对页面行为、错误追踪和网络时间线的可见性,而这些在其他情况下是无法获取的。对于回归测试、安全审计或复杂的 UI 交互,附加 CDP 调试器通常是必不可少的。关键在于将功能测试与原始性能测量分开,并在以后者为目标时禁用调试器。
总结: 使自动化测试成为可能的工具,也可能成为性能失真的最大来源。在指责浏览器、网络或代码之前,请先验证是否由于调试器在悄无声息地限制数据流。
