先别急着重启,先定位问题
网站变慢是个人站长最常遇到的「玄学」问题:明明什么都没改,怎么就慢了呢?很多人的第一反应是重启服务器、加带宽、上 CDN,结果钱花了问题还在。其实网站变慢从来不是玄学,它一定是某个环节出了状况——网络、DNS、服务器资源、数据库、缓存、代码,总有一环。本文给你一套可以照着做的排查流程:先判断慢的类型,再逐层量化定位,最后针对性解决。
一、先判断「慢」是哪一种
排查前先回答三个问题:
- 全站都慢,还是只有个别页面慢?全站慢多半是服务器资源或网络问题;个别页面慢则要怀疑页面本身,比如图片太大、插件冲突、SQL 查询太重。
- 首次访问慢,还是刷新也慢?首次慢通常是缓存未命中或后端处理慢;刷新也慢说明缓存根本没生效,要先查缓存。
- 你自己慢,还是所有人都慢?换手机流量试试,再让不同地区的朋友访问一下。只有你慢,问题很可能出在你本地网络或 DNS。
这三个问题能帮你把排查范围缩小一大半,避免在错误的方向上浪费几个小时。
二、用 curl 量化 TTFB
不要凭感觉判断「慢」,用数据说话。在本地和服务器上分别执行:
curl -o /dev/null -s -w "DNS:%{time_namelookup}s 连接:%{time_connect}s TLS:%{time_appconnect}s 首字节:%{time_starttransfer}s 总计:%{time_total}s\n" https://你的域名看几个关键指标:DNS 解析时间异常(超过 0.5 秒)说明 DNS 服务商或本地解析有问题;连接时间异常说明网络链路不通畅;首字节时间(TTFB)异常说明服务器处理慢,这是最需要关注的一项;总时间减首字节时间很长,说明页面体积大或带宽不足。
一个重要的对比技巧:在服务器本机 curl 自己(用内网地址或 127.0.0.1)。如果本机 TTFB 很快、外部访问却很慢,问题在网络层;如果本机也慢,问题在服务器内部——PHP、数据库、磁盘 IO,逐层往下查。
三、浏览器 Network 面板看前端
打开开发者工具切到 Network 面板,正常加载一次页面。重点看几类问题:
- 有没有单个资源特别大:一张几 MB 的图片没压缩,或上传了原图直接引用,一个页面光图片就拖半天;
- 静态资源有没有走缓存:第二次加载时图片、JS、CSS 应该返回 304 或直接命中本地缓存,如果全是 200 说明缓存头没配好;
- 有没有启用压缩:响应头里没有 Content-Encoding: gzip 或 br,说明压缩没开,文本类资源白白多传好几倍体积;
- 第三方资源拖后腿:统计代码、字体、外链 JS 挂掉或超时,会阻塞页面渲染,这种问题在浏览器里最容易发现。
另外注意首屏渲染:如果页面大量依赖 JS 才能显示内容,或者阻塞渲染的脚本太多,即使服务器响应很快,用户感知依然是慢。把统计代码、广告脚本改成异步加载,首屏速度会有肉眼可见的提升。
四、服务器负载与资源排查
登录服务器,用几条命令快速体检:
uptime # 负载,持续超过 CPU 核数就是过载
top -b -n1 | head -20 # 看 CPU 和内存占用最高的进程
free -h # 内存和 swap 使用情况
iostat -x 1 3 # 磁盘 IO,%util 长期 90% 以上说明磁盘是瓶颈
df -h # 磁盘空间,满了会导致各种诡异故障常见情况一:负载打满但业务并不忙——很可能被恶意爬虫或采集器刷爆了,去 access log 里按 IP 统计请求数,找出异常来源,配合 Nginx 限流和封禁解决。常见情况二:CPU 长期 100% 且进程名可疑——检查是不是被挖矿程序入侵,用 top 和 ps 结合排查,发现异常进程立刻取证并处理。
五、数据库慢查询排查
很多「页面变慢」的根源在数据库。先打开慢查询日志(以 MySQL 为例):
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 2; # 超过 2 秒的 SQL 记录然后分析慢查询日志里出现频率高的 SQL,常见原因就三类:
- 缺索引:WHERE 条件里的字段没有索引,导致全表扫描,数据量一大就慢;
- 深分页:LIMIT 100000, 20 这种写法,MySQL 要先扫描前 10 万行再丢弃,越翻越慢;
- 数据膨胀:随着文章和评论增多,以前能跑的数据量现在跑不动了。
对可疑 SQL 执行 EXPLAIN 看执行计划:type 列是 ALL 就说明全表扫描,rows 估算值过大也说明索引没生效。加上合适的索引后,慢查询通常立竿见影。
除了慢查询日志,还可以直接看数据库当前正在做什么:执行 SHOW FULL PROCESSLIST,能看到正在运行的 SQL 和已经执行了多久。如果某条 SQL 反复出现且耗时长,基本就是它在拖慢整个站点;确认无误后用 KILL 终止危险查询,再针对它做索引优化。
六、缓存命中率检查
缓存是网站性能的放大器,但缓存「没命中」等于没有缓存。分层检查:
- PHP OPcache:在 phpinfo 页面或状态页看命中率,长期低于 90% 说明 opcache 配置需要调整;
- Redis/Memcached:执行 INFO stats,看 keyspace_hits 和 keyspace_misses,命中率低于 80% 要检查 key 的设计和过期策略;
- 页面级缓存:Nginx fastcgi_cache 或缓存插件,响应头里一般有 X-Cache: HIT 或 MISS,MISS 比例高说明缓存没生效或一直在过期重建。
一个经典问题:明明开了页面缓存,命中率还是低。常见原因是缓存 key 里带了不稳定的参数,比如时间戳、随机数,或者缓存时间设得太短,页面刚生成就被淘汰,等于每访问一次都回源重建一次。
以 Redis 为例,redis-cli INFO stats 输出的 keyspace_hits 和 keyspace_misses 两个计数器就能算出命中率;PHP 侧如果启用了对象缓存,还可以通过 phpinfo 或调试面板确认缓存是否真的在读,而不只是「配置了」。
七、网络链路与外部因素
如果服务器本机一切正常,但访客就是慢,检查链路:
mtr -rw 目标IP # 看每一跳的丢包和延迟
dig 你的域名 # 看 DNS 解析结果和耗时mtr 里某个节点持续丢包或延迟飙升,说明链路绕路或运营商问题,可以考虑换线路或上 CDN 解决;解析耗时异常,考虑换 DNS 服务商,国内可以用阿里云 DNS、腾讯 DNSPod。另外别忘了访客地域:服务器在海外、访客在国内,物理距离摆在那里,加 CDN 是更现实的解法,靠优化服务器本身很难消除跨洋延迟。
八、一套推荐的排查顺序
把上面的方法串成固定流程,下次再遇到就不用慌:
- 先量化:curl 记录 TTFB 和总耗时,作为排查基线;
- 分内外:服务器本机测一次,区分网络问题和服务器问题;
- 查资源:负载、内存、磁盘 IO,排除资源瓶颈和被攻击;
- 查数据库:开慢查询日志加 EXPLAIN,处理慢 SQL;
- 查缓存:命中率逐层检查,确认缓存真正生效;
- 查前端:大资源、压缩、缓存头、第三方脚本;
- 改一个变量测一次,不要同时改多个配置,否则出了问题不知道是谁引起的。
这套流程的核心是「用数据代替猜测」。大部分网站变慢问题,都能在这几步里找到答案,真正需要重装系统、换服务器的极少。
常见问题(FAQ)
Q:TTFB 很慢但服务器负载很低,可能是什么原因? A:优先怀疑 PHP-FPM 进程阻塞或慢 SQL,其次检查磁盘 IO——云服务器的突发 IO 可能被打满而 CPU 却闲着。负载低不代表没有瓶颈。
Q:用了 CDN 还是慢怎么办? A:先确认访问是否真的走了 CDN 节点(ping 域名看解析到的 IP),再检查源站是否健康——CDN 回源慢,边缘节点再快也没用。还要看缓存命中率,动态内容没被缓存的话,每次请求都要回源。
Q:这些排查工具需要装很多软件吗? A:curl、top、free、df 是系统自带的;iostat 装 sysstat 包,mtr 装 mtr 包,都是几十 KB 的小工具,装上不亏,排查时能省大量时间。
Q:排查了好几天都没找到原因怎么办? A:回到基线对比:把变化前后的代码提交、配置改动、流量波动列出来,逐项回滚测试。多数「找不到原因」的慢问题,最后都发现是某个不起眼的小变更引起的。