news 2026/9/26 21:14:55

网站打不开?从DNS到数据库的层次化故障排查SOP

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
网站打不开?从DNS到数据库的层次化故障排查SOP

1. 先别急着刷新:把"网站打不开"拆成五类场景

我得先说实话:绝大多数"网站打不开"的求助,最后查出来的根因都不是什么惊天大坑,反而越是简单的故障,越容易被紧张的排障过程搞复杂。凌晨两点收到告警,群里已经炸成一锅粥,这时候最忌讳的就是手忙脚乱地刷新页面、重启服务器、连看三遍日志——顺序全错了,问题当然查不到。

我自己的习惯是,接到报障后的第一件事不是动手,而是先把问题分门别类。判断"网站打不开"具体属于哪一类,决定了后面排查的方向和对故障等级的预估。根据我这些年处理过的线上故障,基本可以归纳成五类:

场景类型典型表现最可能的根因方向
完全打不开浏览器直接提示无法访问、超时DNS、链路、防火墙、服务器宕机
能打开但白屏/卡住页面加载一半不动,或HTTP返回502/504应用进程、数据库、代码异常
部分用户打不开有的地区正常,有的地区异常CDN、DNS调度、多线路机房
突然发生昨天还好好的,今天凌晨全挂变更窗口、夜间任务、证书过期
间歇性故障时好时坏,过一会儿自己恢复负载高、连接数满、限流

1.1 想清楚这三个问题,比跑命令更值钱

面对每一类故障,我建议你强迫自己在纸上(或者脑子里)先回答三件事:

  1. 故障是从什么时候开始的?这个时间点之前有没有做过发布、改配置、调参数?
  2. 影响范围有多大?是所有用户全挂,还是只有某些网络/地域的用户受影响?
  3. 故障是持续性的,还是脉冲式的?持续性问题多半和配置、进程、资源耗尽相关,间歇性问题多半和负载、并发、锁竞争相关。

这三个问题问完,你大概能划掉一半的错误方向。比如,如果是某个省份的电信用户打不开,而你人在联通机房,那大概率是链路互联互通的问题,这时候你在服务器上折腾半天毫无意义。如果是昨天发版之后出现的间歇性502,那重点应该放在新代码的数据库连接池配置上,而不是去重启PHP进程碰运气。

1.2 变更窗口:排查最快的一条捷径

我在团队里经常反复强调一句话:90%的线上故障都来自变化,不是被攻击了,也不是机器老了,而是某个"看起来人畜无害"的小改动。可能是今早运维顺手改了一下Nginx的超时参数,也可能是开发同学发布时漏了一个依赖包。所以,每次排障前,务必先确认变更窗口。

怎么确认?最直接的是看发布系统/工单系统里的记录。小团队没有自动化发布平台的,至少要有git提交记录和服务器操作历史。登录服务器先跑一条ls -lt /usr/local/nginx/conf/,看配置文件有没有在故障时间点被改过;再翻一下应用的部署目录,看Release目录的时间戳。这一步往往能直接把排查时间从两小时压缩到十分钟。

2. 由外到内快速定界:DNS、链路、服务器一台台过

分类分完了,变更也确认了,下面进入真正的排查阶段。我习惯按"由外到内"的顺序走:客户端 → DNS → 链路 → 服务器 → 应用 → 数据库。每一层只做最少的验证,发现正常就迅速下沉,不要在一个层级上恋战。

2.1 DNS解析:先确认域名是否"指路正确"

很多新手一上来就去登录服务器看日志,结果问题根本不在服务器上。域名解析错了、解析没生效,用户压根就到不了你的服务器,服务器上当然一切正常。

排查DNS最快的方式是用系统自带的工具。Linux/Mac下用dig,Windows老版本用nslookup:

dig example.com A +short nslookup example.com

重点看返回的IP对不对,是不是你CDN或源站的真实IP。如果域名明明指向旧机房IP,而你的业务早迁走了,那问题就是DNS记录没更新,或者TTL太高导致客户端的本地缓存还在用旧IP。

还有一种容易忽略的情况:域名被解析到了多个IP,其中一个IP对应的服务器已经下线或者防火墙放行异常。这时候从你本机解析可能一切正常,但某个地区的用户落在了那个坏IP上,表现就是"部分用户打不开"。处理方式是先拿dig查全部的A记录,再看每个IP的健康状态。

2.2 链路探测与本地排除

DNS没问题,接着验证从你当前网络到目标服务器的链路是否通。三条命令足够:

ping -c 5 你的服务器IP telnet 你的服务器IP 80 curl -I https://你的域名

ping看网络层的通断和丢包率,telnet验证TCP端口是否开放,curl则直接模拟一次真实的HTTP请求。如果ping通但telnet不通,多半是防火墙或服务没起来;如果ping超时但其他机器访问正常,说明你的出口线路到这台机器有故障,或者服务器的安全组/防火墙把你这个IP段给拦了。

我遇到的比较经典的坑是:服务器在阿里云,安全组规则里放行了80和443,但客户是从某个内部办公网络访问,出口做了端口限制,所有8443以上的端口都被封。这种情况是换一台测试机、或者让用户用手机4G/5G流量访问一下,基本就能立刻定位。

2.3 用第三方视角判断影响范围

单靠你本地的一台电脑,永远只能代表一种网络环境。判断"是全局故障还是局部故障",最快的方式是找第三方监测站点,或者直接问几个不同网络环境的同事。我比较常用的思路:

  • 用线上拨测工具(比如听云、博瑞、公开的Ping检测站点)从多个城市发起探测,看是否有大面积超时。
  • 如果手上有多地运维能力的同学,在群里喊一声,让北京、上海、广州的同事各ping一次。
  • 手机切到4G/5G网络访问,对比WiFi下的表现。

如果拨测结果全国都超时,那基本可以确认是源站或CDN域名调度层面出了问题;如果只有某个点异常,那就是局部链路运营商之间的问题,这时不用慌,按链路故障走工单找运营商排查,同时可以考虑临时切换DNS线路。这一步把故障定界定清楚之后,再往服务器里钻就踏实多了。

3. 服务器内部体检:负载、内存、磁盘、inode一个都不能少

定界到了服务器这一层,接下来做的就是在机器上"望闻问切"了。我有一套固定的开机五分钟命令序列,基本覆盖了服务器层面的绝大多数资源型故障。

3.1 开机五分钟的六道命令

登录服务器后,我习惯按以下顺序敲:

uptime free -h df -h df -i top -bn1 | head -20 dmesg -T | tail -30

uptime看1分钟、5分钟、15分钟的负载均值。如果1分钟负载远高于15分钟,说明系统正在经历突发压力;如果三个值都很高,说明高负载已经持续很久了。对于Linux服务器,负载均值需要结合CPU核数来判断,比如8核的机器,负载超8就要警惕,16核的机器跑到12也未必有问题——这个判断逻辑很多人经常搞错。

free -h主要看内存余量和Swap使用情况。df -h检查磁盘空间,df -i检查inode。很多运维只查磁盘不查inode,这会在第3.2节重点说。top看一眼当前CPU和内存占用最高的进程,确认是不是某个进程异常吃满资源。dmesg则看内核日志,OOM记录、磁盘I/O错误、TCP丢包警告都在这里,是排查底层异常的黄金渠道。

3.2 磁盘满之外还有inode这个隐形坑

我得重点讲讲inode,这坑我踩过不止一次。有次客户反馈"网站无法上传图片,程序报磁盘写入失败",我上去一看df -h,磁盘还剩20G,怎么看都够用。后来查了一圈才发现,磁盘满了?不,是inode满了。

inode是Linux文件系统里用来记录文件元数据的数据结构,简单理解就是"档案编号"。每个文件(包括目录)都要消耗一个inode。如果磁盘里堆积了大量的小文件,比如PHP的session文件、各种缓存碎片、邮件队列,那么会出现磁盘空间还有空闲、但inode被消耗殆尽的情况。此时系统无法创建任何新文件,服务自然表现异常。

判断方法很简单:

df -i

如果/dev/vda1的IUse%接近100%,那就是inode耗尽了。排查哪里堆积了大量小文件,可以用:

for i in /var/spool /tmp /var/log /home/* 目录; do find $i -type f | wc -l; done

或者更精准地查找某个目录下文件数量排行。处理上一般就是清理过期的session、清空垃圾邮件队列、或者把缓存目录下超过30天的临时文件删除,并把定时清理脚本挂到crontab里。

3.3 内存与Swap:OOM杀进程的现场还原

内存耗尽的表现通常是:服务进程突然消失、页面请求全部502、free -h显示内存所剩无几,而Swap也基本没有。这时候不要光看Java/PHP进程本身,还要看是不是有其他进程把内存吃光了。

有一次我排查一个网站间歇性宕机,dmesg -T里看到了一行很关键的信息:

Out of memory: Kill process 2344 (php-fpm) score 832 or sacrifice child

这就很明确了,PHP-FPM进程因为内存压力过大被内核的OOM Killer给"枪毙"了。处理办法是给php-fpm的pm.max_children调低,同时排查为什么单个PHP进程占用内存那么高——后来发现是个别接口存在死循环读取大文件的问题。不定位代码,光靠重启进程永远解决不了根本。

4. 应用层的排查重点:Web服务、日志、进程、配置

如果服务器硬件资源都正常,问题大概率就出在应用层。这里的"应用层"包括Web服务器(Nginx/Apache)、后端语言运行时(PHP-FPM/Java/Python/Golang)、以及业务代码本身。每一层都有它自己典型的故障模式。

4.1 服务在不在、端口通不通

到了服务器上,第一反应当然是确认服务进程和端口状态:

ps -ef | grep nginx ps -ef | grep php-fpm ss -tlnp | grep ':80\|:443\|:9000'

如果进程不在了,看服务状态或直接重启。但这里有个经验:进程在,不代表服务是健康的。Nginx可能进程还挂着,但worker进程已经卡死;PHP-FPM可能master进程活着,但所有worker都在等待某个慢请求。我遇到过Nginx出现"所有worker都处于sleep状态,但CPU占用接近0"的情况,表现就是网站打开奇慢无比但没完全挂。

这时候需要看一眼错误日志和连接状态:

tail -f /var/log/nginx/error.log ss -t state established '( dport = :80 or sport = :80 )' | wc -l

如果established连接数异常高,同时nginx日志频繁出现upstream timed out或connect() failed (111: Connection refused),那问题多半出在后端服务,比如PHP-FPM或Java服务已经没法正常工作了。

4.2 日志是事故现场的监控录像

排障到应用层,日志就是你唯一可信的信息来源。我总结过几个最常用的日志查看技巧:

# 看最近100行错误日志 tail -100 /var/log/nginx/error.log # 带时间戳持续跟踪 tail -f /var/log/nginx/access.log # 统计最近5分钟的访问量 awk -v date="$(date -d '-5 minutes' '+%d/%b/%Y:%H:%M')" '$4 > date' /var/log/nginx/access.log | wc -l # 找出耗时超过10秒的请求 awk 'int($NF) > 10000 {print $0}' /var/log/nginx/access.log | tail -20

其中"找耗时超过10秒的请求"这条命令非常实用。Nginx的$request_time字段位于日志行的最后一个位置,单位是毫秒。如果发现某些请求的耗时特别离谱,哪怕数量很少,也可能是一个慢SQL拖垮了连接池,进而导致所有请求排队。

前端页面出现白屏时,如果访问日志里压根没有对应的请求记录,说明流量没到达后端,问题在更外层;如果日志有记录但返回5xx,说明到达了后端但处理失败;如果记录显示200但用户端仍然白屏,那可能是CDN缓存了错误页面,清一下缓存往往就好了。

4.3 配置文件:最后一个被怀疑的凶手

有一类故障很诡异:服务进程活着、日志也看不出明显错误、资源完全够用,但网站就是间歇性打不开。这种时候我一般会去对比配置文件,因为配置的坑往往藏得很深,要到最后才怀疑它。

有一次我们的Nginx配置在做灰度发布时,不小心把一个server块里的proxy_read_timeout从60改成了5。结果流量稍大或者后端处理稍慢,Nginx就主动断开连接,前端表现为"网站经常打开一半就报504"。从日志上看没有error,从资源上看没有瓶颈,最后是一行一行地diff配置才找到的元凶。

所以我的建议是:每次改配置前,先备份原文件并保留一个diff记录;遇到间歇性故障时,不要急着翻业务代码,先对比一下最近一次变更前后的配置差异。命令很简单:

diff /usr/local/nginx/conf/nginx.conf.bak /usr/local/nginx/conf/nginx.conf

改完之后记得用nginx -t做语法校验,并nginx -s reload平滑加载。如果配置改挂了你没发现,那可能连服务都起不来,别问我是怎么知道的。

5. 数据库故障往往最隐蔽:连接数、锁等待、慢查询逐个看

数据库几乎是"网站打不开"故障里最热门的元凶了,尤其是用了MySQL的场景。很多应用层的异常,追根溯源都会回到数据库这一层。而且数据库故障的表现往往不那么直观——页面返回502、接口超时、系统间歇性卡顿,你可能查了半天代码,最后才发现是数据库连接池被拖垮了。

5.1 连接数被打满的典型表现

MySQL连接数满了的经典报错是:

Too many connections

但很多时候应用的报错不一定直接显示这句话,而是显示Connection refused、SQLSTATE[HY000] [2002]之类的信息,因为连接池在尝试建立新连接时就已经失败了。此时你需要确认MySQL当前的连接情况:

SHOW STATUS LIKE 'Threads_connected'; SHOW VARIABLES LIKE 'max_connections'; SHOW PROCESSLIST;

如果Threads_connected长期贴着max_connections上限,那就是连接数被打满了。常见原因有两个:

  • 某个接口的代码忘记释放连接(连接泄漏),导致连接只增不减。
  • 某段时间流量突增,连接池的最大连接数不够用。

处理方法是先临时调大max_connections(注意不要一下子调到远超实际内存承载能力),最稳妥的是重启有问题的应用服务,释放挂起的连接。然后立刻去查连接数异常增长的来源,通常SHOW PROCESSLIST里能看到大量来自同一台应用服务器的连接,集中在同一个库。再配合慢查询日志,基本就能定位到是哪个SQL拖慢连接池了。

5.2 慢查询与锁等待

即使连接数没满,数据库也可能因为某一条慢SQL把整个库拖垮。最典型的场景是:一张大表没有走索引,一个全表扫描查询就要几秒,业务请求一多,所有请求都在等这条SQL执行完,数据库的CPU飙升,查询全部变慢。

排查慢查询,先看慢查询日志有没有开:

SHOW VARIABLES LIKE 'slow_query_log'; SHOW VARIABLES LIKE 'long_query_time';

没开的话,建议立刻打开:

SET GLOBAL slow_query_log = ON; SET GLOBAL long_query_time = 2;

另外,锁等待问题也非常常见。我处理过一个线下故障:某业务表被一个长事务锁住,其他所有操作这条表的请求全部堵在Waiting for table metadata lock或Lock wait timeout exceeded。这种情况在SHOW PROCESSLIST里能直接看到大量状态为Waiting for ...的会话。

遇到锁等待,先找出持有锁的源头事务ID,然后让业务方评估是否需要杀掉该事务。大多数时候Apache/Nginx层怎么调都没用,只有把锁释放掉,流量才会恢复。

5.3 主从同步延迟

如果网站架构里走了读写分离,还有一个容易被忽略的坑:主从同步延迟。比如用户提交订单后,立即去查订单列表,如果查询走的是从库,而从库还没同步到最新数据,就会看到"数据消失"或"页面数据不全"的假象。更严重时,如果从库同步中断太久、binlog积压严重,从库上的查询会越来越慢,最终拖垮业务。

排查同步延迟,在从库上执行:

SHOW SLAVE STATUS\G

重点看Seconds_Behind_Master,数值越大说明延迟越严重。如果是持续性的高延迟,优先检查从库服务器的磁盘I/O、网络带宽,以及有没有大事务在主库上执行。解决办法通常是给大事务拆批,或者把部分分析型查询直接指向主库,临时缓解透读压力。

6. 让SOP从灭火器变成防护网:监控指标与故障演练

排查SOP最大的价值不只是让你在故障发生时能按图索骥,而是把"救火"变成"防火"。如果你总是等到报警了才开始排查,那即使SOP写得再完美,网站的稳定性也是脆弱的。更好的做法是,把这篇SOP里的关键判断点都变成监控指标,让系统在你还没接到用户投诉之前就发出告警。

6.1 核心指标的监控清单

我建议至少给下面这些指标配上监控、告警和可视化:

监控对象指标体系建议告警阈值
服务器CPU使用率、负载均值、内存/磁盘/inode负载持续5分钟超核数、磁盘使用率超85%
Nginx活跃连接数、5xx状态码比例、request_time5xx比例超过5%、平均耗时超3秒
应用PHP-FPM/Java进程状态、队列堆积数进程挂掉、队列积压超过阈值
数据库Threads_connected、慢查询数、主从延迟连接数超80%、慢查询突增、延迟超10秒

监控工具方面,中小团队可以用开源方案,比如Prometheus + Alertmanager + Grafana这套组合。如果不想自己搭,云厂商自带的云监控也够用,关键是把告警渠道配上——电话、短信、钉钉/企业微信机器人,任选两三个,避免单点渠道失效。

6.2 故障演练与复盘:让SOP活起来

写好的SOP如果只在故障时打开看,它永远不会变成团队的能力。我建议每季度至少做一次故障演练,挑一个非业务高峰期的时段,人为制造一两个故障场景:关掉一台应用服务器、把数据库连接池调小、或者模拟DNS解析异常,然后让值班的同学按SOP走一遍,记录耗时和卡壳的地方。

演练之后最重要的一件事是复盘。每次真实故障处理完,一定要回答三个问题:

  • 当前SOP里哪些步骤是有效的?哪些步骤根本用不上?
  • 本次故障有没有在监控层面提前发现?如果没有,缺什么指标?
  • 有没有什么工具或自动化手段能减少下次定位的时间?

我自己就经常干这种事:复盘完之后,把每次故障的根因和处置方法写进知识库,并同步更新SOP。这样跑过一两次完整循环之后,SOP就从一份死文档变成了真正有生命力的流程。

这套排查思路,核心就一句话:分清层次、按序深入、经验沉淀、工具固化。真把这一套跑顺了,你会发现网站没有那么容易挂,就算挂了你也不再害怕——你手里已经有了一套清晰的路线图,知道每一步该看什么、怎么判断、往哪走。别小看这个"按部就班",在凌晨两点的告警声里,它就是你最可靠的伙伴。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 21:13:43

SpringBoot+SSM美容院管理系统毕设:从业务拆解到论文答辩全攻略

如果你正打算做一个美容院管理系统的毕业设计,或者你只是好奇“SpringBoot SSM”这套组合在真实管理系统里到底是怎么落地的,这篇内容应该能帮你省不少弯路。我会从最开始的业务拆解讲起,一直讲到数据库表设计、核心功能代码怎么写、开发过程…

作者头像 李华
网站建设 2026/9/26 21:13:38

英语-语法-倒装句

分词结构全部倒装部分倒装,主语,谓语不变,但是要把助动词放在主语的前面。否定词在句首的时候需要把助动词提到主语的前面第二种情况 Only状语在句首

作者头像 李华
网站建设 2026/9/26 21:11:31

交流AI的未来:从调用到对话,构建稳定可复用的AI交流通道

1. 从“交流AI的未来”说起:这个项目到底在聊什么“Chat GPT | 交流AI的未来”这个标题,乍一看像是一句口号,但如果你真的动手做过AI对话类项目,就会明白它其实指向一个非常具体的东西:如何让普通人和大模型之间形成一…

作者头像 李华
网站建设 2026/9/26 21:10:17

从碎片化到可追溯:DeskcommCRM落地实践与避坑指南

在客户量涨到三百多家之后,我明显感觉到原来的那套“微信Excel个人邮箱”组合已经撑不住了。客户A在微信里问过的问题,三天后客户B又来问一遍;上午电话里答应的方案,下午找不到记录到底改没改;销售和售后各记各的账&am…

作者头像 李华
网站建设 2026/9/26 21:08:42

Qt QPalette实战:从调色板机制到全局亮暗主题切换

做Qt开发这些年,我一直觉得QPalette是被很多人低估的一个类。一提到界面美化,大家第一反应就是上QSS(Qt样式表),写一堆border-radius、background-color、color,看着挺爽,等到了全局换肤、动态主…

作者头像 李华