有一次我在外面用手机打开自己的博客,等了大概四秒才看到首屏。回到电脑前再打开,半秒不到。同一篇文章、同一个站点,差别大得让我有点不服气。
我一开始归因于“手机性能差”。但换了几台设备、几个网络之后,规律变得清楚:问题不在设备,而在这段路本身。从输入域名到文字出现,中间经过的每一段,都可能让等待变长。
那段路到底有多长
我试着把一次访问拆开:
1 | 输入域名 |
每一段都有耗时,而且互相依赖。DNS 慢,后面全慢;TLS 握手多一次往返,首字节就晚一点;HTML 到了但 CSS 阻塞,页面还是白屏;图片太大,首屏一直在等。
在自己电脑上,很多段被缓存和高速网络掩盖了。到了移动网络,缓存是冷的、延迟更高、带宽更窄,问题就全部暴露出来。
第一次测量
我没有凭感觉优化,先做了两件事。
第一,用 curl 看服务端这段时间花在哪:
1 | curl -o /dev/null -s -w \ |
第二,用浏览器的性能面板和 Lighthouse 看前端这段时间花在哪。两边一对,问题就很具体了:DNS 和 TLS 不算慢,TTFB 也还可以,真正的大头是图片和字体,以及一个阻塞渲染的脚本。
这个结果和我原先的猜测不一样。我以为“服务器不够快”,实际上是“页面太重”。
链路思维带来的变化
以前我判断一个站点快不快,只看“打开得顺不顺”。现在我更愿意把它看成一整条链路,每一段单独问三个问题:
- 这一段做了什么?
- 这一段的耗时是多少?
- 如果它变慢或失败,用户会看到什么?
这三个问题让优化变得有方向。比如:
- DNS:解析记录是否合理,TTL 是否太短,有没有多余的 AAAA 记录;
- 连接:是否复用了连接,TLS 版本和证书链是否正常;
- CDN:缓存命中率多少,回源是否频繁,缓存键是否合理;
- 源站:TTFB 由什么构成,有没有慢查询或阻塞;
- 浏览器:哪些资源阻塞渲染,图片和字体是否过大;
- 渲染:首屏需要哪些资源,哪些可以延后。
这六段里,任何一段出问题,用户看到的都是“慢”或“打不开”。如果不分段,就只能靠猜。
不是所有等待都值得消除
研究链路之后,我也放弃了一些“把每一毫秒都抠出来”的执念。
有些等待是值得的:等一张真正需要的图片,等一个让阅读更舒服的字体。有些优化则会带来新的问题:过度内联让 HTML 变大,激进缓存让更新不可见,预加载太多反而抢了关键资源的带宽。
链路优化的目标不是“每一项指标都满分”,而是“用户想读的内容尽快出现,并且不因为优化而变得不可靠”。
接下来的方向
这次对比之后,我开始按链路而不是按功能来组织自己的工作:先确认 DNS 和连接正常,再看 CDN 和缓存,最后才动前端资源。后面的文章会分别记录 CDN 调优、加载优化、日志分析和多端检查的过程。
站点建好只是开始。真正决定阅读体验的,是内容离开服务器之后经过的每一段链路。把这段路看清楚,才知道光为什么没有传得更远。