数力科技Digital Force
← 全部文章

为什么你的网站有时秒开,有时要等两秒

这是个很常见的困惑:你刚做完网站,反复刷新都是秒开,很满意。过两天再打开,转了一下才出来。你怀疑是服务器不行,或者是网络问题,但测又测不出所以然。

下面用我们自己的站做例子,把这件事拆开。所有数字都是实测的。

先看两个数字

同一个页面,从奥克兰访问:

缓存命中时:45 毫秒。你几乎感觉不到等待,点击和显示是连着的。

缓存没命中时:210 到 520 毫秒。这个区间里你会明确感觉到”顿了一下”。

十倍的差距,同一个页面,同一台服务器,同一个网络。区别只在于这一次请求有没有命中缓存。

缓存在哪里,为什么会没有

中间这层通常是 CDN,比如 Cloudflare。它在全球有很多节点,离新西兰最近的在奥克兰。第一个访客来的时候,节点没有这个页面,它去源服务器取一份,存下来,然后发给访客。之后的访客直接从奥克兰这个节点拿,不用再跑一趟。

问题出在”存下来”这件事上。

很多人以为缓存时间设长一点就行——设成一年,那就存一年。这个理解是错的,而且错得很关键。

缓存时间是上限,不是保证。CDN 节点的存储空间要给成千上万个网站共用,它按访问热度淘汰内容。一个流量不大的网站,即使你把缓存时间设成一年,几个小时没人访问,那份副本也会被挤掉给更热门的内容让位。

于是就出现了那个现象:你连续刷新的时候快,因为副本还在;隔一天再来,副本已经被淘汰了,这次请求要一路回到源服务器。

而且这个规律很残酷——越是流量小的网站,越容易碰到慢的那一次。而流量小的网站,往往每一个访客都更重要。

那 210 到 520 毫秒花在哪了

拆开看:从奥克兰到我们的源服务器(在悉尼),建立连接、TLS 握手、发请求、等响应、传回来,这一整趟大约 110 毫秒。这是物理距离决定的,改不了。

但实测的 CDN 回源比这个还慢,而且波动很大。原因是它每次都要重新建立到源服务器的加密连接,而不是复用一条已经开着的。

另外那个源服务器如果还要跑数据库查询、拼页面,再加几十到一百多毫秒。很多网站慢在这里,但要注意:即使你把服务器优化到极致,只要还需要回源,那一趟物理往返就省不掉。

常见的三种应对,以及各自的问题

把缓存时间调得更长。没用,上面说过了,那是上限不是保证。这是最常见的误区,很多人调完之后觉得好了,其实只是刚好在缓存还热的时候测的。

定时去访问自己的网站,让缓存保持热。方向对,但很难做对。CDN 是按节点分别缓存的,你从服务器上发起的请求只会暖到离服务器最近的那个节点,奥克兰的访客照样命中不到。

换更好的服务器。能改善回源那一段的处理时间,但改不了物理往返,也改不了缓存被淘汰这件事。花钱最多,效果最有限。

真正的解法是让源服务器退出这条路径

如果一个页面的内容在两次发布之间是不变的——绝大多数企业网站的页面都是这样——那它根本不需要每次去源服务器取。

做法是把页面提前生成成静态文件,随程序一起部署到 CDN 的网络里。这时它的身份变了:它不是缓存,是部署产物。缓存会被淘汰,部署产物不会——它就在那里,直到你发布下一个版本。

我们这个站改成这样之后的实测:所有页面稳定在 40 到 60 毫秒,连续测几十次没有一次超过 100 毫秒。之前是命中时 45 毫秒、没命中时 520 毫秒,现在没有”没命中”这个状态。

动态的部分——后台、表单提交、AI 客服接口——照常回源。它们本来就不该被缓存,而且量很小。

有一个代价,值得说清楚

这套做法有个新问题:每次发布新版本,各个节点上的文件要重新分发一次,第一个访问的人还是会慢一下(实测约 340 毫秒)。等于把”缓存被淘汰时慢”变成了”刚发布完慢”。

处理办法是发布流程的最后自己把这一次代价吃掉:发布完立刻从本地把所有页面请求几轮,让节点先填满,再交给访客。

这里有个细节容易漏:一个 CDN 节点内部有很多台服务器,请求会被分到不同机器上,每台都要各自填一次。我们实测跑两轮还剩四个页面是慢的,跑六轮才降到零。

你可以自己测

不需要任何工具,命令行一条命令就能看到自己网站的真实情况:

用 curl 请求你的首页,看 time_starttransfer 这个值,它是从发起请求到收到第一个字节的时间。连续测五次,再隔一天测五次。如果两次的结果差好几倍,那就是缓存淘汰在起作用,不是你的服务器有问题。

顺便看一眼响应头里的 cf-cache-statusHIT 是命中,MISS 是这次回源了。你会发现慢的那几次基本都是 MISS。

知道原因之后再决定要不要处理。我们交付的站点默认就是上面那套结构,不是作为加价项。

Get started

开始一个项目先聊三十分钟

先聊聊你的想法,我们给你一份免费的方案建议。

AI 客服右下角气泡
所在地Auckland, NZ