凌晨两点,网站排查手机弹出一条告警:站点首页响应时间从 230ms 飙到 4.8s。网站排查我爬起来打开笔记本,网站排查第一件事不是网站排查重启服务,而是网站排查先看监控曲线——CPU 没炸,内存没满,网站排查磁盘 IO 也正常。网站排查那问题大概率不在服务器本身。网站排查
先查 DNS。网站排查`dig` 一下,网站排查解析正常,网站排查TTL 也没问题。网站排查ping 网关延迟 12ms,网站排查丢包为零。网站排查排除网络层。网站排查接着用 curl 拉首页,-w 参数打出各阶段耗时:DNS 0.01s,TCP 0.02s,TLS 0.08s,TTFB 4.6s。瓶颈在服务端处理,不在传输。
SSH 上去,`top` 一看,php-fpm 进程占满 CPU,但每个进程的负载并不高。这说明请求排队了。看 nginx 的 access log,同一秒内有 300 多个请求来自同一个 IP 段,UA 全是空的。典型的爬虫扫接口,而且没走 CDN,直接打到了源站。
临时封掉那个段,响应时间掉到 800ms。还是慢。继续查。打开 MySQL 的 slow log,发现一条 select 语句执行了 3.2 秒。表不大,八万行,但 where 条件里用了 `like '%keyword%'`,索引失效。更糟的是,这个查询在首页被调用了四次,每次都在循环里。
改 SQL 来不及,先上缓存。Redis 里加一层,key 按参数哈希,过期时间 60 秒。首页 TTFB 降到 180ms。但缓存命中率只有 40%,因为参数组合太多。于是把查询拆成两步:先查 id 列表,再批量取详情。两次查询,一次缓存,命中率拉到 92%。
第二天白天,用户反馈后台登录偶尔 502。查 nginx error log,`upstream timed out`。php-fpm 的 `max_children` 设的是 10,但并发上来时不够用。调到 50,同时把 `request_terminate_timeout` 从 60s 改成 30s。502 消失。
还有个隐蔽问题:静态资源没开 gzip,CSS 和 JS 加起来 1.2MB。nginx 配置里加 `gzip on`,`gzip_types` 补上 `application/javascript` 和 `text/css`。首屏加载从 3.4s 降到 1.1s。顺手把图片转成 WebP,又省了 400KB。
排查过程中最耗时的不是技术操作,而是确认“哪个环节慢”。很多人一上来就重启,或者盲目加机器。其实先看监控,再分层定位——DNS、TCP、TLS、TTFB、内容下载——每一步都有对应的工具和指标。顺序对了,十分钟能解决的问题,不会拖到两小时。
最后做了一件事:把这次所有变更写成 checklist,放进运维手册。下次告警响的时候,照着跑一遍,不用再靠记忆。网站排查不是玄学,是流程加经验。流程保证不漏,经验决定快慢。