ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

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

网站打不开?从DNS到数据库的层次化故障排查SOP 1. 先别急着刷新把网站打不开拆成五类场景我得先说实话绝大多数网站打不开的求助最后查出来的根因都不是什么惊天大坑反而越是简单的故障越容易被紧张的排障过程搞复杂。凌晨两点收到告警群里已经炸成一锅粥这时候最忌讳的就是手忙脚乱地刷新页面、重启服务器、连看三遍日志——顺序全错了问题当然查不到。我自己的习惯是接到报障后的第一件事不是动手而是先把问题分门别类。判断网站打不开具体属于哪一类决定了后面排查的方向和对故障等级的预估。根据我这些年处理过的线上故障基本可以归纳成五类场景类型典型表现最可能的根因方向完全打不开浏览器直接提示无法访问、超时DNS、链路、防火墙、服务器宕机能打开但白屏/卡住页面加载一半不动或HTTP返回502/504应用进程、数据库、代码异常部分用户打不开有的地区正常有的地区异常CDN、DNS调度、多线路机房突然发生昨天还好好的今天凌晨全挂变更窗口、夜间任务、证书过期间歇性故障时好时坏过一会儿自己恢复负载高、连接数满、限流1.1 想清楚这三个问题比跑命令更值钱面对每一类故障我建议你强迫自己在纸上或者脑子里先回答三件事故障是从什么时候开始的这个时间点之前有没有做过发布、改配置、调参数影响范围有多大是所有用户全挂还是只有某些网络/地域的用户受影响故障是持续性的还是脉冲式的持续性问题多半和配置、进程、资源耗尽相关间歇性问题多半和负载、并发、锁竞争相关。这三个问题问完你大概能划掉一半的错误方向。比如如果是某个省份的电信用户打不开而你人在联通机房那大概率是链路互联互通的问题这时候你在服务器上折腾半天毫无意义。如果是昨天发版之后出现的间歇性502那重点应该放在新代码的数据库连接池配置上而不是去重启PHP进程碰运气。1.2 变更窗口排查最快的一条捷径我在团队里经常反复强调一句话90%的线上故障都来自变化不是被攻击了也不是机器老了而是某个看起来人畜无害的小改动。可能是今早运维顺手改了一下Nginx的超时参数也可能是开发同学发布时漏了一个依赖包。所以每次排障前务必先确认变更窗口。怎么确认最直接的是看发布系统/工单系统里的记录。小团队没有自动化发布平台的至少要有git提交记录和服务器操作历史。登录服务器先跑一条ls -lt /usr/local/nginx/conf/看配置文件有没有在故障时间点被改过再翻一下应用的部署目录看Release目录的时间戳。这一步往往能直接把排查时间从两小时压缩到十分钟。2. 由外到内快速定界DNS、链路、服务器一台台过分类分完了变更也确认了下面进入真正的排查阶段。我习惯按由外到内的顺序走客户端 → DNS → 链路 → 服务器 → 应用 → 数据库。每一层只做最少的验证发现正常就迅速下沉不要在一个层级上恋战。2.1 DNS解析先确认域名是否指路正确很多新手一上来就去登录服务器看日志结果问题根本不在服务器上。域名解析错了、解析没生效用户压根就到不了你的服务器服务器上当然一切正常。排查DNS最快的方式是用系统自带的工具。Linux/Mac下用digWindows老版本用nslookupdig 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 -30uptime看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 内存与SwapOOM杀进程的现场还原内存耗尽的表现通常是服务进程突然消失、页面请求全部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就从一份死文档变成了真正有生命力的流程。这套排查思路核心就一句话分清层次、按序深入、经验沉淀、工具固化。真把这一套跑顺了你会发现网站没有那么容易挂就算挂了你也不再害怕——你手里已经有了一套清晰的路线图知道每一步该看什么、怎么判断、往哪走。别小看这个按部就班在凌晨两点的告警声里它就是你最可靠的伙伴。
返回列表