服务器突然连不上了,或者CPU风扇狂转,这是运维人员最不想面对的场景。别慌,绝大多数故障都有迹可循。直接切入正题,当一台Ubuntu服务器表现异常时,最先做的不是重启,而是先诊断。重启虽然能暂时掩盖问题,但会销毁宝贵的现场证据。正确的做法是,先稳住自己,然后从资源、网络、磁盘、进程、日志这五个维度逐一排查。
瞬间定位资源瓶颈:CPU与内存服务器变慢,第一反应是看谁在消耗资源。别用图形化工具,直接上命令行。htop比top更直观,但很多最小化安装的系统没有,所以掌握top足够。执行top后,注意看三个指标:load average、us(用户态CPU)和wa(I/O等待)。如果load average数值持续大于CPU核心数的1.5倍,说明系统过载了。如果wa值很高,比如超过30%,说明CPU不是在忙着计算,而是在苦等磁盘读写,这时候去优化CPU是没用的,得立刻排查磁盘I/O。
内存方面,别被free命令的available列迷惑,直接看实际使用量和swap使用情况。如果swap用量持续增长,物理内存肯定吃紧了。快速揪出内存大户的命令是:
ps aux --sort=-%mem | head -n 10
这个命令按内存使用率降序排列进程,一眼就能看到罪魁祸首。有时候,内存泄漏的进程会悄悄耗尽资源,用这个命令定期巡检,比任何监控仪表盘都直接。如果发现是某个Java应用或数据库占用过高,不要急着杀进程,先用jmap或数据库自带工具分析堆内存,保留现场。
磁盘满了的隐秘角落:不只是大文件磁盘空间耗尽是最常见的故障之一,但很多人只会用df -h看挂载点,发现满了就去找大文件。这没错,但更隐蔽的情况是:文件被删除了,但空间没释放。原因是某个进程还在持有已删除文件的句柄。用这个命令检查:
lsof | grep deleted
你会看到一堆标记为deleted的文件,它们占用的空间在df里不会消失。解决办法通常是重启那个持有句柄的服务,比如Apache或Tomcat。另外,inode耗尽也会导致“磁盘满”的假象,明明df还有空间,却无法创建新文件。检查inode使用率:
df -i
如果某个分区的IUse%达到100%,说明小文件太多了。常见于邮件队列目录或临时会话目录。用以下命令找出哪个目录下有海量小文件:
for i in /*; do echo $i; find $i -type f | wc -l; done
这个脚本会遍历根目录下的每个一级目录,统计文件数量,很快就能定位到问题目录,然后进去清理无用的会话文件或日志缓存。
网络故障的快速隔离:从内到外网络不通,先别急着ping外部地址。故障点可能在本地网卡、DNS解析、路由或防火墙。按链路层到应用层的顺序排查。第一步,确认网卡是否启动,IP是否正常:
ip addr show
如果网卡没有UP,用ip link set eth0 up启动。第二步,检查路由表,尤其是默认网关:
ip route show
确保默认路由指向正确的网关。第三步,测试本地协议栈是否正常,ping本地回环地址127.0.0.1。如果这都不通,内核网络模块可能出了问题,这种情况极少见但存在。第四步,ping网关,如果不通,检查网线、交换机端口或ARP表。用arp -a看是否能解析网关MAC地址。第五步,如果网关通但外网不通,检查DNS。很多“断网”其实是DNS解析失败。用nslookup或dig测试,如果DNS不通,临时修改/etc/resolv.conf为公共DNS进行对比测试。
还有一种特殊情况:端口监听正常,但外部连不上。这多半是防火墙或云服务商安全组的问题。Ubuntu上默认使用ufw,快速检查:
ufw status verbose
如果显示allow的端口不包含你的服务端口,那就是这里拦截了。但更隐蔽的是,有些云平台有独立的安全组策略,即使系统内ufw关闭,流量也会被拦截,所以务必同时检查云控制台的防火墙规则。
服务假死的终极诊断:进程与端口服务明明启动了,但客户端连不上,或者连接超时。这种“假死”状态很棘手。首先确认进程是否真的在运行:
systemctl status 服务名
如果显示active (exited),说明服务启动后立即退出了,这通常是配置文件错误导致。用journalctl -u 服务名 -n 50查看最近的日志,错误信息一般都很明确。如果状态是active (running),但端口没监听,可能是服务绑定了错误的IP地址。用ss命令检查:
ss -tlnp | grep 端口号
注意看监听地址是0.0.0.0还是127.0.0.1。如果是后者,服务只能本机访问,外部请求全都会被拒绝。这是配置文件中bind-address设置错误造成的。还有一种情况是端口被占用,新服务无法启动,用同一个ss命令也能看到是谁在占用。如果发现是TIME_WAIT状态的连接过多,导致新连接无法建立,需要调整内核参数net.ipv4.tcp_tw_reuse,但这是临时缓解,根本原因是短连接请求过于频繁,需要从应用架构上优化。
系统日志的挖掘技巧:不要大海捞针故障发生时,日志是最诚实的记录者,但也是最容易被海量信息淹没的。不要盲目用tail -f追着看,要带着问题去搜索。系统级日志集中在/var/log/syslog,应用日志通常在/var/log/应用名/下。排查硬件故障,比如内存条损坏或磁盘读写错误,直接搜kernel:
grep -i error /var/log/syslog
如果出现大量I/O error或Buffer I/O error,磁盘很可能有物理坏道,赶紧用smartctl -a /dev/sda查看SMART信息,确认后立即备份数据并更换磁盘。对于应用层故障,比如数据库连接失败,日志里会有反复的connection refused记录。用grep结合-A和-B参数可以显示匹配行的上下文,例如:
grep -A 5 -B 5 "Connection refused" /var/log/应用日志
这样能完整看到错误发生前后的情况,便于推断原因。如果日志文件太大,grep会很慢,可以先用logrotate强制轮转一次,或者用split分割后再查。另外,/var/log/auth.log记录了所有认证相关操作,如果有人暴力破解SSH,这里会留下大量Failed password记录,用lastb命令也能快速查看。
软件包管理中的依赖陷阱执行apt upgrade后服务挂了,这是运维的噩梦。问题往往出在依赖冲突或库版本变更。如果升级后系统异常,第一时间查看apt的历史日志:
less /var/log/apt/history.log
这个文件记录了每次apt操作的详细时间、命令和变更的包列表。找到最近一次操作,看看哪些包被更新了。如果确认是某个包的更新导致,可以直接降级:
apt install 包名=版本号
版本号可以从/var/cache/apt/archives/里找,或者用apt-cache policy 包名查看可用版本。更常见的情况是,添加了第三方PPA源后,系统更新时引入了不兼容的库。排查方法是检查/etc/apt/sources.list和/etc/apt/sources.list.d/下的文件,用apt-cache policy确认某个包的来源。如果发现来自非官方源,先注释掉那个源,再重装该包。预防这类问题的最佳实践是:生产环境不要随意添加PPA,升级前在测试环境验证,并且始终保留上一个内核版本,以便从内核不兼容中恢复。
定时任务的神秘操作有些故障只在特定时间点出现,比如每天凌晨三点服务器负载飙升,或者每周日磁盘空间突然下降。这几乎可以肯定是cron定时任务在搞鬼。排查思路是列出所有用户的定时任务:
for user in $(cut -f1 -d: /etc/passwd); do crontab -u $user -l; done
这个命令会遍历所有系统用户,打印出他们的crontab。同时还要检查系统级的/etc/crontab和/etc/cron.*目录。找到可疑任务后,分析其执行时间和脚本内容。很多运维会忽略的一个点是,cron任务执行时的环境变量和登录Shell完全不同,PATH变量非常有限。如果脚本里用了某些命令却找不到,cron会静默失败。排查方法是查看/var/log/syslog中cron的日志,或者在脚本开头强制设置PATH变量,并将输出重定向到日志文件,以便捕获错误信息。
SSH连接卡顿的深层原因SSH登录很慢,输入密码后要等十几秒才出现命令行。这个问题几乎100%是DNS反向解析超时导致的。当客户端尝试连接时,SSH服务端默认会对客户端IP进行反向DNS查询,如果DNS服务器响应慢或不可达,就会一直等待超时。快速验证:在服务端临时注释掉/etc/ssh/sshd_config中的UseDNS yes,改为UseDNS no,然后重启sshd。如果连接变快,问题就确诊了。但直接关闭UseDNS会丢失日志中的主机名信息,更好的做法是确保服务端的/etc/resolv.conf配置了可达的DNS服务器,或者在/etc/hosts中为常用客户端IP添加解析记录。
内核参数调优的紧急救火面对突发的高并发流量,服务开始拒绝连接,日志报出“Too many open files”。这是因为系统对单个进程可打开的文件句柄数有限制。临时提高限制:
ulimit -n 65535
但这只对当前会话有效。永久生效需要修改/etc/security/limits.conf,添加类似“root soft nofile 65535”和“root hard nofile 65535”的行,然后重新登录。对于网络层面的syn flood攻击或突发连接,内核参数net.core.somaxconn控制了监听队列的最大长度,默认值通常较小。如果发现大量SYN_RECV状态的连接,可以临时调整:
sysctl -w net.core.somaxconn=2048
这些内核参数调整是救急手段,稳定后应该根据实际负载进行科学计算并写入/etc/sysctl.conf持久化。
