跳至正文

Linux运维里一个让我少加了两天班的通用调试技巧

事情是这样的,上周五快下班的时候,测试环境的一台服务器突然抽风了。Nginx返回502,数据库连不上,但其他几台同配置的机器跑得稳稳当当。我第一反应是检查服务状态,systemctl status nginx,绿的,running。再看MySQL,也是绿的。telnet端口,通的。curl本地,正常。但就是从外面访问,502。

当时我脑子里的第一想法是防火墙,因为以前被iptables坑过,改完规则忘了保存,重启就恢复。我赶紧检查iptables -L -n,空的。firewalld也没开。这就诡异了,同一个网段的其他机器能正常请求这台机器的端口,但外网进来的流量就是不行。

折腾了半个小时,从网络层看到应用层,什么tcpdump抓包、ss -tlnp看监听、nginx error log翻了个底朝天,都没发现异常。error log里干干净净,access log里甚至连请求记录都没有,说明请求根本没到nginx手里。那问题出在哪?

我正打算重启机器看看,突然想起之前一个老前辈跟我说过的一句话:”Linux里很多诡异问题,先看系统日志,别自己瞎猜。”这话听着像废话,但那天我真就栽在以为自己懂系统日志这件事上。

我打开/var/log/messages,翻到最后,发现一条不太起眼的信息:nginx: segfault at 0 ip 00007f8c9a3b2c99 sp 00007ffd8e4f3b70 error 4 in libc-2.17.so。再往前翻,每隔几分钟就有一条nginx的segfault。但诡异的是,systemctl一直显示nginx是running状态,因为主进程没挂,但worker进程在反复崩溃重启。这种情况下,nginx的master进程还在,但实际处理请求的worker已经挂了,所以端口监听还在,但请求进来就没人处理,直接丢包。

那为什么只有这台机器出问题?我把nginx版本拉出来一看,1.20.1。其他几台是1.18.0。查了一下更新日志,1.20.1确实修复了一些安全漏洞,但也引入了一个和glibc 2.17不兼容的bug,在高并发场景下会导致worker进程segfault。测试环境这台机器glibc版本正好是2.17,其他几台是2.28以上,所以只有它中招。

解决方案其实很简单:降级nginx版本到1.18.0,或者升级glibc到2.28以上。我选了降级,因为升级glibc风险太大,一不小心整个系统就炸了。操作步骤:

yum remove nginx -y
yum install nginx-1.18.0 -y
systemctl start nginx

然后验证,curl localhost,200。外网访问,正常。前后不到五分钟。

但这里有个更坑的细节。我一开始没想到看系统日志,是因为我习惯了看应用日志。很多运维教程都在教你怎么配置日志轮转、怎么用ELK分析日志,但很少强调一个点:系统日志和应用日志是两个完全不同的排查入口。应用日志告诉你”发生了什么”,系统日志告诉你”为什么发生”。比如这次,nginx error log里什么都没有,因为segfault是操作系统层面的信号,nginx自己都来不及写日志就炸了,只有内核会记录到/var/log/messages里。

后来我复盘了一下,这个”先看系统日志”的技能其实可以通用到很多场景。比如MySQL突然挂了,但mysqld.log里只有一句”Aborted connection”,这时候去/var/log/messages里查,可能能看到OOM killer的记录,说明是内存不足被系统杀了。再比如某个进程突然变慢,top里看不出问题,但messages里可能有大量的”soft lockup”或者”hung_task_timeout_secs”提示。

还有一个我自己总结的骚操作:用journalctl –since “5 minutes ago” -p err,可以只看最近五分钟的错误级别日志,省得翻半天。有些发行版默认用systemd-journald,messages文件可能被压缩或者清空,这时候journalctl比直接读文件靠谱。版本号方面,CentOS 7开始默认用systemd 219,journalctl的命令格式基本通用。

最后说一个踩坑经验。那天我差点就执行了reboot,想着重启大法好。但仔细一想,如果真的是内存越界或者glibc兼容性问题,重启之后问题依然存在,而且重启会清空系统日志里的segfault记录,到时候连排查线索都没了。所以遇到诡异问题,第一件事不是重启,是备份日志。cp /var/log/messages /var/log/messages.bak,然后再动手。

总结一句话:系统日志是你和内核之间的唯一对话渠道,别等到出问题才想起来看它。平时没事的时候可以养成习惯,每天扫一眼/var/log/messages或者journalctl -p err –since “24 hours ago”,很多隐患在变成故障之前就有预兆。比如我后来发现这台机器其实早就有segfault记录了,只是之前量少没引起注意,直到某次流量波动触发频繁崩溃我才发现。这种细节,光靠监控告警是抓不到的。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注