Linux下Nginx故障系统化检查Shell脚本 #!/bin/bash# # 脚本名称: nginx_triage.sh# 功能描述: 对 Nginx 意外中断进行系统化、哲学驱动的快速检查与取证# 遵循 本体论-奥卡姆剃刀-辩证法-整体论 的认知框架# 使用方式: 以 root 或具有适当权限的用户运行# 重要原则: 只取证不恢复。恢复动作应在充分判断后由人工执行。# set-uopipefail# ---------------------------- 配置区 ----------------------------------------NGINX_MASTER_PID_FILE/var/run/nginx.pidNGINX_ERROR_LOG/var/log/nginx/error.logNGINX_ACCESS_LOG/var/log/nginx/access.log# 可能用于判断流量中断时间点JOURNAL_SINCE5 minutes ago# ---------------------------------------------------------------------------# 颜色定义RED\033[0;31mGREEN\033[0;32mYELLOW\033[1;33mBLUE\033[0;34mNC\033[0m# No Colorecho-e${BLUE}${NC}echo-e${BLUE}Nginx 中断现场快速检查 (Triage)${NC}echo-e${BLUE}理念: 本体归类 - 奥卡姆剃刀 - 辩证分期${NC}echo-e${BLUE}${NC}# ---------------------------------------------------------------------------# 第一部分本体论归类 —— 快速识别“中断”属于哪类实体# 哲学依据: 区分症状实体(进程消失/无响应)与根因实体(OOM/磁盘满等)# 通过几条轻量命令迅速将当前现象映射到已知故障模式# ---------------------------------------------------------------------------echo-e\n${YELLOW}[阶段一] 本体论识别中断现象实体${NC}# 1.1 进程存在性echo-e\n${GREEN}[检查1] Nginx 进程状态${NC}if[-f$NGINX_MASTER_PID_FILE];thenmaster_pid$(cat$NGINX_MASTER_PID_FILE2/dev/null)if[-n$master_pid]kill-0$master_pid2/dev/null;thenecho Master 进程存在PID:$master_pid# 检查 worker 进程worker_count$(pgrep-P$master_pid-c2/dev/null||echo0)echo Worker 进程数:$worker_countif[$worker_count-eq0];thenecho-e${RED} 现象归类Master 在但无 Worker可能配置重载失败或 worker 频繁退出${NC}fielseecho-e${RED} 现象归类PID 文件存在但进程不存在Nginx 进程已死亡${NC}fielseifpgrep-xnginx/dev/null21;thenecho 未找到标准 PID 文件但发现 nginx 相关进程运行中可能为其他实例pgrep-anginxelseecho-e${RED} 现象归类Nginx 进程完全不存在${NC}fifi# 1.2 端口监听状态整体论视角也间接检查后端连接堆积echo-e\n${GREEN}[检查2] 端口监听与连接状态${NC}# 检查常见端口可根据需要调整forportin80443;dolisten_info$(ss-tlnpsport :$port2/dev/null)if[-n$listen_info];thenecho 端口$port正在监听:echo$listen_info# 额外检查 Recv-Q/Send-Q 是否有堆积无为思想让内核数据说话recvq$(ss-tansport :$port2/dev/null|awkNR1 {sum$2} END{print sum})sendq$(ss-tansport :$port2/dev/null|awkNR1 {sum$3} END{print sum})echo 当前端口$port总 Recv-Q:$recvq, Send-Q:$sendq(非零可能表示请求堆积)elseecho-e${RED}端口$port未被监听${NC}fidone# 手工检查步骤注释如果无端口监听请手动执行 ss -tlnp 检查是否有其他进程占用了 Nginx 需要的端口# 若有端口监听但无法访问请检查防火墙规则 (iptables -L -n) 及本地策略# ---------------------------------------------------------------------------# 第二部分奥卡姆剃刀 —— 用最少的命令获取最大信息量# 优先检查高概率、高信息密度的日志而非全面铺开# ---------------------------------------------------------------------------echo-e\n${YELLOW}[阶段二] 奥卡姆剃刀高密度信息优先${NC}# 2.1 Nginx 错误日志最近30行重点看 emerg/alert/critecho-e\n${GREEN}[检查3] Nginx 错误日志 (最近30行)${NC}if[-f$NGINX_ERROR_LOG];thentail-30$NGINX_ERROR_LOG|whileIFSread-rline;doifecho$line|grep-qE\[emerg\]|\[alert\]|\[crit\]|\[error\];thenecho-e${RED}$line${NC}elseecho$linefidone# 快速检查是否有磁盘空间不足的典型错误iftail-50$NGINX_ERROR_LOG|grep-qNo space left on device;thenecho-e${RED} 明确发现磁盘空间不足${NC}fiiftail-50$NGINX_ERROR_LOG|grep-qToo many open files;thenecho-e${RED} 明确发现文件描述符耗尽${NC}fielseecho-e${RED}未找到错误日志文件:$NGINX_ERROR_LOG${NC}fi# 手工检查如果日志文件过大请执行 tail -100 /var/log/nginx/error.log | grep -E emerg|alert|crit 并查看时间戳是否与中断吻合# 2.2 系统日志中的关键事件OOM、段错误、systemd 杀死进程echo-e\n${GREEN}[检查4] 系统日志 (OOM/segfault/systemd)${NC}# 优先使用 journalctl若无则回退到 /var/log/messagesifcommand-vjournalctl/dev/null21;thenecho --- journalctl (最近$JOURNAL_SINCE) ---journalctl--since$JOURNAL_SINCE--no-pager2/dev/null|grep-iEnginx|oom|killed process|segfault|memory cgroup||echo (无匹配关键信息)elseif[-f/var/log/messages];thenecho --- /var/log/messages ---grep-iEnginx|oom|killed process|segfault/var/log/messages|tail-20||echo (无匹配关键信息)fifi# 内核环形缓冲区echo --- dmesg (最后15行) ---dmesg|tail-15|grep-iEoom|nginx|segfault|killed||echo (无匹配关键信息)# 手工检查如果怀疑 OOM执行 dmesg | grep -i out of memory 查看完整 kill 列表# 手工检查如果怀疑 systemd 资源限制执行 systemctl status nginx 查看 Main PID 退出状态# ---------------------------------------------------------------------------# 第三部分关键资源快速检查奥卡姆剃刀继续只查最可能且代价最低的# ---------------------------------------------------------------------------echo-e\n${YELLOW}[阶段三] 关键资源剃刀检查 (磁盘/文件描述符/内存)${NC}# 3.1 磁盘空间与 inodeecho-e\n${GREEN}[检查5] 磁盘使用情况${NC}df-h|grep-vE^tmpfs|^devtmpfs|^overlay|awk{if (NR1 || $50 80) print}# 只显示使用率80%的分区echodf-i|grep-vE^tmpfs|^devtmpfs|^overlay|awk{if (NR1 || $50 80) print}echo-e${YELLOW}提示: 重点关注 Nginx 日志目录所在分区、/tmp 和 /var${NC}# 手工检查若发现分区已满执行 du -sh /var/log/nginx/* | sort -rh | head 找出大文件# 手工检查若 inode 耗尽执行 find /tmp -type f | wc -l 检查是否有海量临时文件# 3.2 文件描述符限制与当前使用量echo-e\n${GREEN}[检查6] 文件描述符限制${NC}if[-f/proc/sys/fs/file-max];thenecho 系统全局限制:$(cat/proc/sys/fs/file-max)fi# 如果 Master PID 存在查看其 limitsif[-f$NGINX_MASTER_PID_FILE];thenmaster_pid$(cat$NGINX_MASTER_PID_FILE2/dev/null)if[-n$master_pid][-d/proc/$master_pid];thenecho Master 进程 limits:grepMax open files/proc/$master_pid/limits2/dev/null# 当前打开的文件数快速估算不遍历全进程以减轻负载open_files$(ls/proc/$master_pid/fd/2/dev/null|wc-l)echo Master 进程当前打开文件描述符数:$open_filesfifi# 手工检查执行 lsof -p master_pid | wc -l 获得精确数量可能稍慢# 手工检查若怀疑 ulimit 问题检查 /etc/security/limits.conf 中的 nofile 设置# 3.3 内存与 Swap 快照echo-e\n${GREEN}[检查7] 内存与 Swap 状态${NC}free-hechoif[-f/proc/swaps];thenecho Swap 使用情况:swapon--show2/dev/null||cat/proc/swapsfi# 手工检查如果内存不足运行 ps aux --sort-%mem | head -10 找出内存大户# 手工检查如果怀疑 Nginx 内存泄漏后续可使用 pmap -x worker_pid 分析# ---------------------------------------------------------------------------# 第四部分整体论与配置检查 —— 跳出单点看交互# ---------------------------------------------------------------------------echo-e\n${YELLOW}[阶段四] 整体论跨组件关联与配置状态${NC}# 4.1 检查与后端的连接状态echo-e\n${GREEN}[检查8] 到上游后端服务的连接状态${NC}# 查看与常见后端端口 (如 8080, 9000) 的连接ss-tanstate established|grep-E:80[^0-9]|:443[^0-9]|:8080|:9000|head-15||echo 无相关连接echo-e${YELLOW}提示: 如果连接数极少或状态异常根因可能在后端${NC}# 手工检查执行 ss -tanp | grep nginx 查看所有 Nginx 相关连接# 手工检查结合 APM/分布式追踪查看上游服务是否过载或不可达# 4.2 快速检查 Nginx 配置语法有配置时echo-e\n${GREEN}[检查9] Nginx 配置状态${NC}ifcommand-vnginx/dev/null21;then# 仅做语法检查不输出正常信息有错误才显示config_test$(nginx-t21)ifecho$config_test|grep-qtest is successful;thenecho 配置文件语法: OKelseecho-e${RED}配置文件语法错误:${NC}echo$config_testecho-e${RED} 这可能是 Nginx 无法启动或 reload 失败的直接原因${NC}fielseecho nginx 命令不可用跳过配置检查fi# 手工检查如果配置错误导致 reload 失败不要重启先通过 nginx -t 定位并修正配置再执行 reload# 手工检查查看最后一次配置变更记录使用版本控制系统 diff# 4.3 检查证书有效性如果使用 HTTPSecho-e\n${GREEN}[检查10] SSL 证书状态 (概览)${NC}# 遍历配置中常见的证书路径cert_paths$(grep-rssl_certificate /etc/nginx/2/dev/null|grep-v#|awk{print $NF}|tr-d;|sort-u)forcertin$cert_paths;doif[-f$cert];thenend_date$(openssl x509-enddate-noout-in$cert2/dev/null|cut-d-f2)if[-n$end_date];thenexpiry_epoch$(date-d$end_date%s2/dev/null)now_epoch$(date%s)if[$now_epoch-gt$expiry_epoch];thenecho-e${RED}证书已过期:$cert(过期于$end_date)${NC}elseecho 证书有效:$cert(到期:$end_date)fifielseecho-e${YELLOW}证书文件未找到:$cert${NC}fidone# ---------------------------------------------------------------------------# 第五部分辩证法总结 —— 给出排查方向提示恢复决策# ---------------------------------------------------------------------------echo-e\n${BLUE}${NC}echo-e${BLUE}现场取证完成 - 诊断摘要${NC}echo-e${BLUE}${NC}# 利用已收集的信息给出快速判断简单启发式issues()# 判断进程与端口if!pgrep-xnginx/dev/null21;thenissues(Nginx 进程已不存在)fiif[-f$NGINX_ERROR_LOG];thenifgrep-qNo space left on device$NGINX_ERROR_LOG;thenissues(磁盘空间已满 (由错误日志确认))fiifgrep-qToo many open files$NGINX_ERROR_LOG;thenissues(文件描述符不足 (由错误日志确认))fiifgrep-qcannot bind$NGINX_ERROR_LOG;thenissues(端口绑定失败 (由错误日志确认))fifiifdmesg|grep-qiout of memory.*nginx||journalctl--since$JOURNAL_SINCE2/dev/null|grep-qiout of memory.*nginx;thenissues(系统曾触发 OOM Killer目标包含 Nginx)fiifcommand-vnginx/dev/null21;thenif!nginx-t/dev/null21;thenissues(Nginx 配置文件存在语法错误)fifiif[${#issues[]}-eq0];thenecho-e${GREEN}未发现明确的高概率根因。建议进行深度检查${NC}echo 1. 检查 worker 是否因段错误频繁退出 (dmesg/coredump)echo 2. 分析后端服务响应时间与错误率 (全链路追踪)echo 3. 审查近期变更记录 (配置、代码、依赖库)echo 4. 如果 Nginx 进程存在但无响应使用 strace -p worker_pid 观察elseecho-e${RED}发现以下关键问题:${NC}forissuein${issues[]};doecho-e${RED}*$issue${NC}donefiecho-e\n${YELLOW}【辩证法决策提示】${NC}echo-e - 如果服务当前仍中断优先根据上述线索执行${RED}可逆的恢复动作${NC}(如清理磁盘、回滚配置)echo-e - 恢复前请确保已保存上述输出或屏幕截图作为事后分析依据echo-e - 服务恢复后再基于保留的证据进行${GREEN}彻底的根因分析${NC}# ---------------------------------------------------------------------------# 手工补充检验的参考命令集合不自动执行仅供参考# ---------------------------------------------------------------------------echo-e\n${BLUE}--------------------------------------------${NC}echo-e${BLUE}手工深度检验命令参考 (奥卡姆剃刀之下的后续步骤)${NC}echo-e${BLUE}--------------------------------------------${NC}catEOF # 1. 若怀疑 OOM 但日志不明确查看完整 OOM 计分板 dmesg | grep -i oom -A 10 # 2. 若 Master 进程在但无 Worker开启 debug 日志重载 nginx -s stop # 仅在确认无法 reload 时使用 nginx -c /etc/nginx/nginx.conf # 观察控制台输出 # 3. 检查打开文件详情 lsof -p master_pid | awk {print $5,$9} | sort | uniq -c | sort -rn | head # 4. 分析 worker 段错误 coredumpctl list nginx coredumpctl gdb pid # 在 gdb 中执行 bt 命令查看调用栈 # 5. 检查 systemd 资源限制是否生效 systemctl show nginx | grep -iE mem|limit|nofile # 6. 全链路视角使用 curl 测试本地回环和上游后端 curl -v http://localhost/status # 本地探针 curl -v http://upstream_ip:port/health # 后端健康检查 # 7. 检查 DNS 解析问题 tcpdump -i any port 53 -c 20 # 查看 Nginx 配置中的 resolver 设置确认 DNS 可达 # 8. SELinux/AppArmor 审计 ausearch -m avc -ts recent # 查看最近的权限拒绝事件 aa-status # 查看 AppArmor 状态 # 9. 定时任务与人为脚本 crontab -l -u root ls -la /etc/cron.d/ # 排查是否有定期 stop/restart nginx 的脚本 # 10. 性能分析仅当服务恢复后可安全执行 perf top -p worker_pid strace -p worker_pid -c -f EOFecho-e\n${GREEN}脚本执行完成。请根据上述输出和手工检查提示完成故障定位。${NC}