一、问题背景
线上出问题,最怕的不是问题本身,是“不知道从哪儿下手”。同样拿到一份“系统卡顿”的工单,老鸟 10 分钟出根因,新人可能要花半天,原因往往就是一套排查命令不够熟。
Linux 命令本身不少(GNU coreutils + util-linux + procps + iproute + … 加起来几百个),但真正高频、能在生产环境直接复用的就那么几十个。这几十个都不熟:
- 高峰期 CPU 100% 报警,不知道是哪个进程占的。
- 业务反馈“慢”,但
top 看 CPU 不高、内存也不高,无从下手。
- 磁盘突然写满,
du 半天查不到大文件在哪。
- 进程启动失败,
systemctl status 一行红字,愣是没看懂到底卡在哪。
- 网络不通,
ping 能通但 curl 不通,netstat 看不懂。
- 日志滚得飞快,眼睛跟不上。
- 诡异问题,重启就消失,没法复现。
这背后其实是“Linux 排障的基本盘”不扎实。“基本盘”是什么?是对 CPU / Memory / Disk IO / Network / Process / File / Log / 启动流程 / 系统调用 / 资源控制 这一套内核概念有一个清楚直觉,再把对应的“信息源”(/proc、/sys、strace、lsof、ss、perf)和“命令入口”(top、ps、pidstat、iostat、vmstat、sar、mpstat)掌握到位。
本文围绕 “CPU / 内存 / 磁盘 IO / 网络 / 进程与文件 / 搜索与日志 / 启动与服务” 八个维度,把一线真正有用、并且教科书里也会点到的命令整理成“目的-命令-预期-判断-下一步”五段式清单。读完后,应该能做到:
- 拿到一个工单,能在 5 分钟内把信息从内核层面摘出来。
- 能根据现象推测“该看哪个命令”,而不是乱枪试。
- 知道破坏性命令的边界,能避免在生产误删。
需要说明的是,本文以 RHEL/CentOS 7+ / Ubuntu 18.04+ / Debian 10+ 为主流目标系统。perf、turbostat 等工具在某些发行版默认没装,会标注。iproute2 系列(ss、ip)已经取代大部分 net-tools 系列(netstat、ifconfig),本文以 iproute2 为主。
二、适用场景
下列场景,都是本文会深入讨论的:
- CPU 满载,需要定位是哪个进程或哪段代码。
- CPU 看似不高,但业务反映“慢”。
- 内存使用率高,想知道是不是 leak。
- 大量 swap 命中,性能塌方。
- 磁盘 IO 突增,写延迟飙升。
- 磁盘写满,找不到大文件。
- 网络不通,能 ping 通但连不上服务。
- 服务连接数打满。
- 进程启动失败,看不懂报错。
- 日志被刷屏。
- 进程僵死 / 僵尸进程。
- 端口冲突,listen 不上。
- 文件被谁占用,无法删除。
- 服务 Down 后想秒级定位是开机没起来还是运行中挂了。
- 系统启动卡住 / 启动失败。
- 内核日志告警(
dmesg 里都是红色)。
不在本文范围:
- 不展开 KVM 虚拟化层、容器化层(
cgroup、namespace 等)的深入;只在相关命令处顺势提一下。
- 不写 shell 编程技巧、不写网络协议栈源码解析。
三、核心知识点
下面这些是后面命令的“地基”。理解之后再读命令表会很顺。
1. CPU 三大块
- user:用户态进程(非内核代码)。
- sys:内核态 CPU。
- iowait:CPU 在等 IO 完成。
- nice / irq / softirq / steal:优先级、硬中断、软中断、被 hypervisor 偷走的时间。
关键观察:
- user 高 + load 高 → 应用占 CPU(计算密集)。
- sys 高 → 内核态吃 CPU(系统调用多、IO 调度、锁竞争)。
- iowait 高 + load 高 + sys 不高 → IO 设备跟不上。
2. 内存与缓存
free 命令看到的 buffers / cached 都是 Page Cache,本质是“已用但可回收”。系统内存吃紧时,这部分会先释放。
available 是真正可用:约等于 free + buffers + cached - 不可回收部分。
swap 命中 不一定是有压力:可以被动换出。/proc/vmstat 中 pswpin / pswpout 是更严格的 swap 流量指标。
- OOM:被 OOM Killer 杀掉的进程在
dmesg | grep -i 'killed process'。
3. 磁盘 IO 指标
iostat -xz 1 输出里:
r/s、w/s:每秒读写次数。
rkB/s、wkB/s:每秒读写字节。
await:单次 IO 平均等待(毫秒)。
%util:设备利用率(注意不直接等于负载,IO 队列深度也会影响)。
- NVMe 与 SSD:
%util 经常 100%,但 await 仍很小,是因为并发度高;要看 aqu-sz(平均队列)和 await。
- 写延迟 / 读延迟:
await 是平均值;如果业务对延迟敏感,应看 P99,需要 sar 或更专业的工具。
4. 网络
ss -ntp 看 TCP 连接,-p 列出进程(需要 root)。
ip -s link 看网卡统计(丢包、错误、队列)。
- TCP TIME_WAIT:客户端主动关闭后留 30~60s 的“时间等待”,正常,但量太大会占端口。
- Listen backlog:内核
somaxconn 与 backlog 联合决定。listen() 不带 backlog 默认 5。
- DNS 慢:
getent hosts / getent ahosts / dig 排查。
net.ipv4.tcp_tw_reuse=1:开启后可重用 TIME_WAIT;生产慎用 --reuseport,留量需要的场景才开。
5. 进程 / 文件 / 文件描述符
6. 启动与服务
- systemd 取代 SysVinit + Upstart:
systemctl status nginx:看到 active (running) / failed / inactive。
systemctl list-units --type=service:所有 unit。
journalctl -u nginx -n 100:服务日志。
journalctl -u nginx -f:实时跟踪。
systemctl daemon-reload:改了 unit 文件后。
7. 日志
/var/log/messages(RHEL)/ /var/log/syslog(Debian/Ubuntu):系统日志。
journalctl:systemd journal,二进制索引过,查询快。
dmesg:内核环形缓冲,关机前所有“硬件相关”都会留这里。
/var/log/audit/audit.log:SELinux、pam_faillock 等。
8. 加载和加载平均
uptime / top 头上的 load average 是 1/5/15 分钟的可运行 + 不可中断进程数的滑动平均。
- 单 CPU 机器 上
load=1 是满载;多 CPU 上要除以核数。
四、整体排查或实施思路
按“现象 → 看哪一块 → 用什么命令”的顺序给一张主路径。
- 接收现象:“慢 / 卡 / 报错 / 服务挂”。明确是某个服务还是整台机;是稳定复现还是突发。
- 入口检查:
uptime、top -b -n 1、free -h、df -h、ss -s、dmesg | tail -20。粗略判断 CPU / 内存 / 磁盘 / 网络 / 内核消息。
- 资源定位:CPU 满 →
pidstat / ps;内存高 → pmap 或 /proc/<pid>/status;IO 高 → iostat + iotop;网络连接满 → ss。
- 进程定位:拿到 PID 后
/proc/<pid>/ 取细节。
- 链路定位:网络问题走七层模型:物理层
ethtool → MAC ip link → IP ip addr、ip route → TCP ss、tcpdump → 应用 curl/http。
- 日志定位:业务日志、内核日志、服务日志、journal。
- 处置:调参数 / 杀进程 / 重启服务 / 修改配置 → 验证。
- 复盘:记录现象、命令、参数、结论,沉淀到 wiki。
注意:以上每一步都先观察再下手。先看后杀 是基本准则。
五、实战步骤
下面这十几个步骤能覆盖 80% 的常见线上故障。
步骤 1:系统入口快照
目的:拿到当前机器的全局状态快照。
命令:
uptime
top -b -n 1 | head -20
free -h
df -h
ss -s
dmesg | tail -20
预期输出(示意):
uptime:14:32:11 up 30 days, 12:03, 1 user, load average: 0.40, 0.35, 0.30
top:Cpu(s): 12.0%us, 3.0%sy, 0.0%ni, 80.5%id, 3.0%wa, ...
free:16G total, 12G used, 1G free, 3G buff/cache
df:/ 50G 40G 8G 84% /
ss:TCP: 200 (estab 150, closed 30, orphaned 0, timewait 20)
dmesg:最后几条无报错
异常表现:
load 高(> CPU 核数)、us+sy 高 → CPU 饱和。
load 高但 CPU idle 高、wa 高 → IO 等死。
free 几乎为 0 但 available 还有 → 多数是 Page Cache,正常。
dmesg 出现 Out of memory: Killed process → 历史 OOM。
判断逻辑:
- 锁定是哪一块吃资源(CPU / 内存 / IO / 网络)。
- 锁定是“持续发生”还是“刚发生”。
下一步动作:进入对应分支。
步骤 2:CPU 高定位
命令(看哪个进程最忙):
ps -eo pid,ppid,user,pcpu,pmem,comm --sort=-pcpu | head -20
命令(看每个进程的 CPU 时间片):
pidstat -p <pid> 1 5
命令(采样看 CPU 上跑哪些符号/函数):
perf top
perf 在 RHEL 用 yum install perf;Debian 用 apt install linux-tools-common linux-tools-generic;容器环境看不到 perf。
预期输出:CPU 高的进程名、PID、占的 CPU 占比。
异常表现:
pcpu 高 + 进程名是 kworker / ksoftirqd → 内核态饱和,可能是 IO 中断或锁竞争。
pcpu 高 + 进程名是某业务进程 → 取 CPU 使用详情。
下一步动作:用 top -c / pidstat -p <pid> -w 看哪个线程占 CPU;用 perf top 看热点符号(MySQL、Java 这类也能看到热点函数)。
步骤 3:内存高定位
命令:
ps -eo pid,ppid,user,pcpu,pmem,rss,comm --sort=-rss | head -20
free -h
cat /proc/meminfo
命令(应用内存细看):看到 PID 后:
cat /proc/<pid>/status | grep -E 'VmRSS|VmSize|VmPeak'
cat /proc/<pid>/smaps_rollup
pmap -x <pid> | sort -nr | head
预期输出:
VmRSS:常驻内存。
VmPeak:进程历史最高占用。
VmSwap:被换出的内存。
异常表现:
VmRSS 持续上涨 → 内存泄漏嫌疑。
- 大进程在
java -Xmx 已经设置,但 RSS 远超 -Xmx → 共享库/线程栈。
- RSS 不高但机器内存吃紧 → 内核 slab / page cache 太多,
slabtop。
下一步动作:进入性能采样,看 vmstat 1 10。
步骤 4:swap 与 slab
命令:
vmstat 1 10
slabtop
vmstat 输出解读:
si / so 列:每秒换入 / 换出。
bi / bo:每秒块设备读 / 写。
cs:上下文切换次数。
异常表现:
si/so 持续非零 → 内存吃紧,已经在用 swap。
cs 高(> 100k/s)→ 进程创建/退出频繁或线程调度抖动。
步骤 5:磁盘 IO 突增
命令:
iostat -xz 1 5
iotop
解读:
r/s、w/s 上升。
await 上升(> 5ms 关注,> 30ms 严重)。
aqu-sz(平均队列)上升。
%util 高但 await 低:并发度高。
异常表现:
await 高 + %util 高 → 单设备 IO 饱和。
- 某个磁盘高 → 该盘的
iostat -xz 1,看是不是有进程在疯狂 IO。
下一步动作:
- 用
iotop 找到 IO 高的进程 ID。
- 用
pidstat -d 1 5 看该进程 IO 详情。
步骤 6:磁盘占用 100% / 找不到大文件
命令:
df -h
df -i # inode
du -sh /* 2>/dev/null | sort -hr | head -10
异常表现:
Use% 100% → 进入“找大文件”分支。
Use% 不高但 IUse% 100% → inode 用完(典型场景:大量小文件)。
下一步动作:
find / -type f -size +1G -exec ls -lh {} \;(按需)。
- 注意
find 的耗时;可以 du 看每个一级目录占比,再递归。
命令:
du -sh /var/* 2>/dev/null | sort -hr
du -sh /var/log/* 2>/dev/null | sort -hr
find /var/log -type f -size +100M -ls | head
风险提醒:
find / -delete 是不建议使用的格式。删除前先 -ls 看清单。
du -sh /* 在 root 下耗时,可以用 du -hd 1 限定。
- 清理日志一定要让 Nginx / rsyslog 重新打开文件(
kill -USR1 或重启服务)。
步骤 7:网络连通性排查
命令:
ping -c 4 <host>
traceroute -n <host> # 或 tracepath
mtr -n <host> # 持续追踪丢包
预期输出:每个 hop 的 RTT / Loss%。
异常表现:
Loss% 高 → 节点丢包。
Loss% 主要在最后一跳 → 服务端不稳。
下一步动作:用 curl -v 拿完整请求/响应;用 tcpdump 抓包。
步骤 8:端口监听与连接
命令:
ss -tunlp
ss -s
ss -tan | awk 'NR>1 {c[$4]++} END {for (k in c) print c[k], k}' | sort -nr
解读:
LISTEN:监听中。
ESTAB:已建立。
TIME-WAIT、CLOSE-WAIT 大量 → 关闭策略/代码 bug。
异常表现:
- 服务正常但
ss 看不到 LISTEN → 启动失败,进 service 日志。
CLOSE-WAIT 多 → 代码没 close socket,应用 bug。
下一步动作:抓 tcpdump 抓一段时间,按需 tcpdump -ni eth0 host 1.2.3.4 and port 80 保存 pcap。
步骤 9:服务启动失败
命令:
systemctl status <service> -l --no-pager
journalctl -u <service> -n 100 --no-pager
journalctl -u <service> --since "5 min ago"
预期输出:
- 报错行
Failed with result ...、status=1/FAILURE。
- 末尾
Active: failed (Result: ...)。
异常表现:
Address already in use → 端口被占;ss -tunlp | grep 80。
Permission denied / bind: ... → SELinux、防火墙、用户、文件权限。
No such file or directory → 配置或路径错误。
下一步动作:拿具体报错去搜;对端口冲突解 PID 或改端口;对 SELinux 用 ausearch -m AVC。
步骤 10:进程僵死 / 僵尸
命令:
ps -eo pid,ppid,stat,comm | awk '$3~/Z/' # 找 Z 状态
top -b -n 1 | awk 'NR>7 && $8~/Z/'
异常表现:
Z(僵尸):进程退出但父进程没收尸;列父进程,重启父进程或 kill -CHLD <ppid> 让父进程收尸。
D(不可中断睡眠):通常是 IO 锁着,杀不死,只能解根因(拔盘、解除 mount)。
下一步动作:拿进程详情 cat /proc/<pid>/status、cat /proc/<pid>/wchan 看在哪阻塞。
步骤 11:文件被谁占用,无法删除
命令:
lsof /path/to/file
fuser -vm /path/to/file
fuser -km /path/to/file # 杀掉占用进程,慎用
lsof +D /path/to/dir | head
异常表现:
fuser -k 会直接发 SIGKILL;生产慎用,先看 -v 输出。
下一步动作:通知占用进程方,或者等业务侧关闭。
步骤 12:端口 / 进程关联
命令:
ss -tunlp | grep ':80' # 拿到 PID
ls -l /proc/<pid>/exe # 哪个二进制
cat /proc/<pid>/cmdline | tr '\0' ' '
异常表现:
ss 不显示 PID:可能是 ss -p 没 root;或者 socket 在别的 network namespace(容器场景常见)。
步骤 13:抓包
命令:
tcpdump -ni eth0 -w /tmp/cap.pcap tcp port 80
tcpdump -ni any host 1.2.3.4
tcpdump -ni any -s 0 -w /tmp/full.pcap
预期输出:pcap 文件。
下一步动作:拿到本地用 Wireshark / tshark 分析;也可以 tcpdump -A 直接打印数据,但注意敏感信息。
风险:tcpdump -w /tmp/cap.pcap 不要把 pcap 留在原机器太久;带敏感数据。
步骤 14:内核消息
命令:
dmesg -T | tail -50
journalctl -k --since "15 min ago"
异常表现:
Out of memory: Killed process → 历史 OOM,定位被杀的进程。
I/O error, dev sda, sector ... → 磁盘坏道,备份优先。
TCP: out of memory -- consider tuning tcp_mem → TCP 缓冲不足。
下一步动作:定位具体硬件问题,请相应团队上硬盘 / 检查存储。
六、常用命令
把上面的命令整合成速查表。每个命令都明确给出目的、关键参数、典型用法,便于回头查阅。
1. CPU 相关
| 命令 |
目的 |
关键参数 |
top |
实时资源总览 |
-b -n 1:批模式单次;-p <pid>:只看一个 |
htop |
top 增强版(默认不一定安装) |
鼠标可交互 |
ps |
进程快照 |
-eo 自定义列;-L 看线程;--sort=-pcpu 倒序 |
pidstat |
进程的 CPU/IO 详细统计 |
-p <pid>、-u、-d、-w、-r、-t |
mpstat |
多核 CPU 视角 |
mpstat -P ALL 1 |
sar |
系统活动历史 |
sar -u 1 5、sar -P ALL 1 5 |
perf top |
实时热点函数 |
需要 root + 内核符号 |
turbostat |
CPU 频率/温度/C-state |
服务器 CPU 视角,x86 专用 |
uptime |
负载与运行时间 |
简单 |
2. 内存相关
| 命令 |
目的 |
关键参数 |
free |
内存概况 |
-h 人类可读;-s 1 持续输出 |
vmstat |
综合状态 |
vmstat 1 10,看 si/so/cs/in/interrupts |
pmap |
进程内存映射 |
pmap -x <pid>、按地址排序 |
smem |
按比例算内存(含 shared) |
smem -u -k -r |
slabtop |
内核 slab 使用 |
实时刷 |
/proc/meminfo |
全量内存指标 |
cat 即可 |
cat /proc/<pid>/status |
单进程内存明细 |
VmRSS / VmSwap / VmPeak |
sar -r |
内存历史 |
需要收集器(sysstat) |
3. 磁盘相关
| 命令 |
目的 |
关键参数 |
df |
文件系统占用 |
-h、-i(inode) |
du |
目录大小 |
-sh 汇总;--max-depth |
iostat |
设备 IO |
-xz 1,看 r/s、w/s、await、%util |
iotop |
实时 IO 热点 |
类似 top |
pidstat -d |
进程 IO |
-p <pid> -d 1 |
lsblk |
块设备树状 |
看整盘 / 分区 / LVM |
blkid |
块设备文件系统 / UUID |
配 fstab |
mount |
当前挂载点 |
mount \| column -t |
findmnt |
挂载点 |
findmnt /xxx |
smartctl |
S.M.A.R.T 健康 |
健康巡检 |
fsck |
文件系统一致性检查 |
卸载后跑 |
4. 网络相关
| 命令 |
目的 |
关键参数 |
ip |
地址 / 路由 / 链路 |
ip addr、ip route、ip -s link |
ifconfig |
兼容老语法 |
新机器可能没装 |
ss |
socket 统计 |
-t TCP、-u UDP、-n 数值、-p 进程、-l LISTEN |
netstat |
同 ss(旧工具) |
netstat -tunlp |
tcpdump |
抓包 |
-ni eth0 -w file.pcap |
mtr |
路由追踪丢包 |
mtr -n <host> |
traceroute |
路由追踪 |
traceroute -n |
curl |
HTTP 客户端 |
-v 详细、-I head、-k 不验证书、--resolve |
wget |
文件下载 |
-O - 直打印 |
dig / nslookup |
DNS |
dig +trace example.com |
ethtool |
网卡状态 |
ethtool eth0、-S 统计 |
sar -n DEV |
网卡历史 |
与 sysstat 配合 |
conntrack |
NAT 连接跟踪 |
conntrack -L |
tc |
流量控制 |
tc qdisc show dev eth0 |
5. 进程 / 文件 / 文件描述符
| 命令 |
目的 |
关键参数 |
lsof |
谁打开了什么 |
-p <pid>、-i :80、+D /path/ |
fuser |
谁占了这个文件 |
-v -m /path/、-k 杀进程慎 |
pidof |
进程名查 PID |
简洁 |
pgrep |
按正则查 PID |
配 pkill |
pstree |
进程树 |
-aps <pid> |
ps |
进程快照 |
-ef BSD 风格;-eo 自定义 |
kill |
发信号 |
-9 SIGKILL;优先 -TERM |
pkill |
按模式发信号 |
-HUP <pattern> |
strace |
系统调用追踪 |
-p <pid> -o strace.log |
ltrace |
库调用 |
类似 strace |
gdb |
调试器 |
慎用 |
ulimit |
资源限制 |
ulimit -n |
/proc/<pid>/fd/ |
该进程 fd |
ls -la 看链接对象 |
6. 搜索 / 文本
| 命令 |
目的 |
关键参数 |
find |
搜文件 |
-name、-mtime、-size、-user |
grep |
搜文本 |
-r 递归、-E 扩展正则、-i 忽略大小写 |
egrep |
同 grep -E |
简写 |
xargs |
给管道接命令 |
-n 1 一行一个、-I{} 替换 |
awk |
文本处理 |
awk '条件{动作}' |
sed |
文本替换 |
-i 原地;常配合 s/old/new/g |
cut |
切列 |
-d ':'、-f1 |
tr |
字符转换 |
大小写、压缩 |
sort / uniq |
排序 / 去重 |
sort -nr、uniq -c |
wc |
行/字/字节 |
-l、-c |
head / tail |
首 / 尾 |
tail -F 持续 |
7. 启动 / 服务 / 日志
| 命令 |
目的 |
关键参数 |
systemctl |
服务控制 |
status、start、stop、restart、reload、enable、disable、mask |
journalctl |
日志 |
-u <srv>、-n、-f、--since |
service |
兼容老语法 |
service nginx status |
chkconfig |
兼容老语法 |
老系统 |
dmesg |
内核日志 |
-T 人类时间 |
tail -F |
滚日志 |
tail -F /var/log/... |
less /F |
检索 |
直接搜 /keyword |
lnav |
高级日志查看 |
第三方,按需 |
loginctl |
用户会话 |
查看登录会话 |
hostnamectl |
主机名控制 |
RHEL 7+ / Debian 11+ |
timedatectl |
时间同步 |
timedatectl status |
localectl |
本地化 |
locale |
老命令(netstat/ifconfig/service/chkconfig)在新发行版可能未装。建议直接用新命令。
8. 进程与资源(cgroup / namespace)
| 命令 |
目的 |
关键参数 |
systemd-cgtop |
cgroup 视角的 top |
默认按 cpu 排序 |
systemd-cgls |
cgroup 树状视图 |
看进程归属 |
cat /proc/self/cgroup |
当前进程 cgroup |
容器里查归属 |
ls /proc/<pid>/ns |
namespace |
容器/vhost 调试 |
cat /sys/fs/cgroup/.../<path>/cpu.stat |
cgroup v2 cpu 统计 |
配合 systemd 使用 |
prlimit |
进程级 rlimit |
prlimit --pid <pid> |
cat /proc/<pid>/limits |
进程 rlimit |
软硬限均显示 |
9. 时间 / 硬件 / 系统信息
| 命令 |
目的 |
关键参数 |
date |
当前时间 |
date "+%F %T" |
chronyc |
chronyd 客户端 |
chronyc sources、chronyc tracking |
ntpq |
ntpd 老客户端 |
老机器 |
timedatectl |
时间同步状态 |
排查时钟漂移 |
lscpu |
CPU 信息 |
NUMA 节点、缓存 |
dmidecode |
硬件信息 |
DMI/BIOS |
lspci |
PCI 设备 |
排查 NVMe/网卡 |
lsusb |
USB 设备 |
服务器基本不用 |
ethtool -i eth0 |
网卡驱动信息 |
排查驱动不匹配 |
numastat |
NUMA 内存分配 |
内存性能问题 |
biosdecode / dmidecode -t bios |
BIOS 信息 |
服务器厂商信息 |
cat /proc/version |
内核版本 |
编译时间、gcc 版本 |
uname -a |
内核/主机名 |
简单 |
uptime |
启动时长 |
简单 |
10. 容器 / 虚拟化(按需)
| 命令 |
目的 |
关键参数 |
docker ps / logs / exec |
容器管理 |
见 docker 文档 |
crictl ps / logs |
k8s 容器运行时 |
kubelet 的工具 |
ctr -n k8s.io containers ls |
containerd 直接操作 |
高级排查 |
podman |
无 daemon 容器 |
RHEL 用得较多 |
virsh |
KVM 管理 |
virsh list |
ip netns |
网络命名空间 |
ip netns exec <ns> ss -tunlp |
lsns |
命名空间 |
全系统视角 |
七、配置示例
下面这些配置示例并不直接出现在排障命令里,但理解它们能避免“排障时把生产改崩”。
1. 内核参数 /etc/sysctl.conf
生产环境常用的几条,关注 net.core.somaxconn、net.ipv4.tcp_*、vm.swappiness:
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 262144
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_slow_start_after_idle = 0
vm.swappiness = 10
vm.dirty_ratio = 20
vm.dirty_background_ratio = 10
fs.file-max = 2097152
fs.nr_open = 1048576
风险:tcp_tw_reuse=1 与 tcp_tw_recycle=1 不一样,后者早已被废弃,开启会出怪问题,本文不写 tcp_tw_recycle。vm.swappiness 设为 10 是常见做法,倾向减少 swap;但实际要按业务调。
生效:
sysctl -p /etc/sysctl.conf
sysctl -w net.core.somaxconn=65535
2. 资源限制 /etc/security/limits.conf
* soft nofile 1048576
* hard nofile 1048576
* soft nproc 65535
* hard nproc 65535
* soft core unlimited
* hard core unlimited
root soft nofile 1048576
root hard nofile 1048576
注:systemd 启动的服务要看 /etc/systemd/system/<srv>.service.d/override.conf 中的 LimitNOFILE。
3. nproc / cgroup
如果是 cgroup 限制(容器、systemd unit),配置在对应位置:
systemctl set-property nginx.service LimitNOFILE=1048576
4. logrotate 通用模板 /etc/logrotate.d/generic
/var/log/myapp/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 root adm
sharedscripts
postrotate
/usr/bin/systemctl reload myapp >/dev/null 2>&1 || true
endscript
}
注:自定义应用要按服务类型决定 postrotate 是发信号还是 reload。
5. sshd 基础加固 /etc/ssh/sshd_config
列出只为口径,和排障时用 ssh -vvv 抓错能看懂。
Port 2222
Protocol 2
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
MaxSessions 10
ClientAliveInterval 300
ClientAliveCountMax 0
AllowUsers ops
生效:
sshd -t
systemctl reload sshd
6. sysstat 采集 /etc/cron.d/sysstat
*/10 * * * * root /usr/lib64/sa/sa1 1 1
53 23 * * * root /usr/lib64/sa/sa2 -A
改完 crontab 后 systemctl restart crond。
7. 自定义 alias
/root/.bashrc 中加:
alias ll='ls -lh --color=auto'
alias la='ls -alh --color=auto'
alias du1='du -hd 1 | sort -hr'
alias psmem='ps -eo pid,user,pcpu,pmem,rss,comm --sort=-rss | head'
alias pscpu='ps -eo pid,user,pcpu,pmem,comm --sort=-pcpu | head'
alias ports='ss -tunlp'
alias ip4='ip -4 addr | grep inet'
八、日志或指标观察方法
下面这套观察方法需要“指标体系”的支撑。
1. 主机级指标
- CPU:用户态/内核态/IOwait/软硬中断。
- 内存:可用、已用、cached、swap in/out。
- 磁盘:read/write TPS、带宽、await、util、inode。
- 网络:收/发 PPS、丢包、错包、TCP 重传。
- 进程:CPU、内存、IO、文件描述符、线程数。
采集工具:node_exporter(Prometheus) / Telegraf / 阿里云 / 腾讯云的云监控。
2. 关键指标观察点
- CPU sys 高 + 软中断高:网络栈瓶颈或锁竞争,配合
mpstat -P ALL 1 看分布。
- iowait 高 + await 高 + %util 高:磁盘瓶颈。
- available 持续下行 + 主动换出:
vmstat 1 持续看 si/so。
- TCP 重传:
netstat -s 或 ss -s。
- TIME_WAIT 持续上万:客户端每请求都新连接,复用率低;改 keep-alive / 升 HTTP/2。
3. sar 历史回放
yum install sysstat
systemctl enable sysstat
systemctl start sysstat
sar -u 1 5
sar -r 1 5
sar -n DEV 1 5
sar -P ALL 1 5
sa1 1 5 # 手动采
sadf -d /var/log/sa/sa$(date +%d) -- -n DEV # 取当天数据输出 CSV
4. Prometheus 视角
核心指标(拿 node_exporter 即可):
node_cpu_seconds_total{mode} rate
node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes
node_disk_io_now
node_network_receive_bytes_total rate / node_network_transmit_bytes_total rate
node_filefd_allocated / node_filefd_maximum
告警阈值按业务基线调整。常见做法:
- CPU 用户态 > 80% 持续 5 分钟。
- available 内存 < 10% 持续 5 分钟。
- disk space 使用率 > 90%。
- await > 30ms。
5. 日志巡检
- 检查
/var/log/messages、/var/log/syslog 中 OOM、IO error、kernel panic 字样。
- 检查
journalctl -p err 中 err 及以上级别。
- 业务日志各服务抽取“异常关键字”(
exception、failed、timeout、killed)做计数。
九、排查路径
下面给出十几个常见异常的“决策树”。
路径 1:CPU 100%
uptime load 高 → top 看 us / sy / wa
├── us 高 → ps -eo pcpu | head → 找到进程 → strace -p <pid>
│ → 看系统调用;perf top 看热点
├── sy 高 → mpstat -P ALL 1 → 某个核上 iowait / softirq 高
│ → 中断分布 / 软中断优化
└── wa 高 → iostat -xz 1 → 找磁盘瓶颈 → iotop 找进程
路径 2:进程不存在但端口被占
ss -tunlp | grep :80
└── 没看到 PID → 进程可能已经死了,内核里有 lingering socket
└── fuser -k 80/tcp 杀掉,然后 wait 30s 内核回收
路径 3:服务起不来 Address already in use
journalctl -u <srv> --since "5 min ago"
└── ss -tunlp | grep :80
├── 没有进程占用 → 内核 SO_REUSEADDR 与 TIME_WAIT 残留,重启几秒可恢复
└── 有进程占用 → 拿到 PID → ps -fp <pid> 看是谁
路径 4:磁盘突然 100%
df -h
├── Use 100% → du -sh /var/* 找大目录
│ → 找到具体目录,find -size +1G -ls
├── Use 不高但 IUse 100% → inode 满
│ → find / -type d -size +1M -exec sh -c 'echo $(ls "$1" | wc -l) $1' _ {} \; | sort -nr | head
└── df 看 mount 选项 → mount 上 ro?
路径 5:慢查询 / 服务响应慢
curl -w "%{time_total}\n" -s -o /dev/null http://localhost/api
├── time_total < 50ms → 大概率是客户端问题
├── time_total 50ms~1s → 看应用日志 / 监控慢 SQL / GC
├── time_total > 1s → 链路问题
│ ├── 客户端到 Nginx → mtr / ping / DNS
│ ├── Nginx → 上游 → log_format 加 $request_time / $upstream_response_time
│ └── 上游 → 数据库 → slow log / EXPLAIN
路径 6:OOM Killer 出场
dmesg | grep -i 'killed process'
└── 找被杀的进程 PID、名字、时间
├── 内存泄漏 → 看 commit_history,常见于 Java/Node 长寿命对象
└── 总内存不够 → 升配 / 限流 / 调代码
路径 7:内网 DNS 解析失败
dig example.com @10.0.0.1
├── timeout → 53 端口 / iptables / nscd / systemd-resolved
└── 成功但解析到错误 IP → /etc/hosts / 视图问题
路径 8:TCP 连接数爆满
ss -s
├── ESTAB 很高且稳定 → 业务并发量真的上来了
├── TIME-WAIT 很高 → 复用率低或短连接过多
└── CLOSE-WAIT 很高 → 业务没 close,应用 bug
路径 9:磁盘 IO 抖动大
iostat -xz 1 10
├── await 抖动大 → 排查是不是有 GC / swap / 备份任务
├── 突发 write → 找进程;iotop
└── 不可解释 → 看 /sys/block/<dev>/stat 健康度、smartctl -a
路径 10:某个服务一直重启
systemctl list-units --type=service | grep failed
journalctl -u <srv> -n 200 --no-pager
└── 启动脚本问题 → 把 ExecStart 改成手工跑
├── 手工跑通 → unit 文件改成 nohup 路径不对
└── 手工跑挂 → 进 strace
路径 11:CPU 高但 iostat 显示空载
mpstat -P ALL 1 5
└── 单核 100% 但其他空闲 → 单线程程序 → 应用层优化
└── 单核 100% 但 us+sy 平均低 → 短时尖刺 → 看具体线程
└── ps -L -p <pid> -o pcpu,comm | sort -nr | head
路径 12:业务请求耗时长,但服务端 TPS 不低
curl -w "time_namelookup:%{time_namelookup}\ntime_connect:%{time_connect}\ntime_appconnect:%{time_appconnect}\ntime_pretransfer:%{time_pretransfer}\ntime_redirect:%{time_redirect}\ntime_starttransfer:%{time_starttransfer}\ntime_total:%{time_total}\n" -s -o /dev/null http://example/api
├── time_namelookup 长 → DNS 慢 → 配 DNS 缓存 / 调 host
├── time_connect 长 → TCP RTT 大 → mtr 看哪一跳
├── time_appconnect 长 → TLS 握手慢 → 是否启用了 OCSP stapling
└── time_starttransfer 长 → 服务端响应慢 → 看后端
路径 13:内核日志刷屏 net_ratelimit 被截断
dmesg
└── 'net_ratelimit: N callbacks suppressed'
├── 流量过大 / 内核在频发刷日志
└── 调 net.core.message_burst / net.core.message_cost
或者升级内核 + 调整驱动
路径 14:磁盘日志无权限写
tail: cannot open '/var/log/app.log' for reading: Permission denied
└── ls -la /var/log/app.log
├── 归属用户/组不对 → chown appuser:appgroup
└── 父目录权限不够 → chmod o+x /var/log
└── 同时仍是 root-only 写 → 想办法不被 sudo 改覆盖
路径 15:误改 sshd 配置导致无法登录
sshd -t
journalctl -u sshd -n 50
└── 立即再开一个 ssh 会话;不要断开当前
└── 当前会话保命的做法:echo '...' > /etc/ssh/sshd_config.d/...d ; sshd -t ; kill -HUP
└── 如果改了 system-auth / PAM → 严重情况下可能要 VNC/IPMI 进 console 修复
路径 16:磁盘掉线 / 多路径
lsblk
ls /sys/class/scsi_device/
dmesg | grep -i 'scsi\|sd '
└── 某盘消失 → 多路径软件 multipath / device-mapper 是否接管
└── multipath -ll
└── 软链路故障 → 检查线缆 / HBA 卡 / 光纤交换机
路径 17:内核软死锁 / hard lockup
dmesg | grep -E 'soft lockup|hard lockup|NMI'
└── 关闭 NMI 看门狗:echo 0 > /proc/sys/kernel/nmi_watchdog
└── 看是单核还是所有核:mpstat -P ALL 1
└── 锁在哪 → kernel debugger (crash) 或 perf
路径 18:systemd 启动卡住某个服务
systemctl list-jobs
systemctl status
└── 看到 'start' 持续 → 该 unit 卡住
└── systemctl mask 掉试试(实际不推荐);先看 status 输出卡在哪一步
└── ExecStartPre 阶段 → 解析脚本
└── ExecStart 阶段 → 应用启动慢 → strace
└── ExecStartPost → 启动后健康检查卡住(如 curl 阻塞)
路径 19:网络带宽看起来很低
sar -n DEV 1 5
ip -s link
ethtool eth0
├── 协商速率 100M 而不是 1G → 网线 / 交换机口
├── rx_dropped / tx_dropped 高 → 缓冲区打满,调 net.core.rmem_max
└── 链路没问题但应用慢 → 看应用层是不是限流了
路径 20:内存足够但 OOM 杀进程
dmesg | grep -i 'killed process'
└── 启动参数中 cgroup memory.limit 较小 → 实际机器内存看不到
└── 容器视角下 cgroup 内存限额太小 → 调整 spec.resources.limits.memory
└── 调整后验证 cgroupfs / sys/fs/cgroup/...
路径 21:TCP 重传率突增
ss -ti dst 1.2.3.4
netstat -s | grep -i retransmit
sar -n EDEV 1
└── 链路不稳 / 拥塞
└── 网络抖动 → mtr 找丢包
└── 客户端调整拥塞窗口:sysctl net.ipv4.tcp_congestion_control
路径 22:日积月累崩溃 / 进程自杀
journalctl -p err --since "30 days ago"
crash / var/crash/ 系统是否启用 kdump
└── 启用 kdump:systemctl enable kdump → 拍下下次崩溃 core
└── crash 工具分析 vmlinux + vmcore
路径 23:用户态 CPU 高但 top 不显示
top 按 H 显示线程
ps -eo pid,tid,pcpu,comm --sort=-pcpu | head
└── 线程耗 CPU 主线程不显眼 → perf top / pstree -p
路径 24:磁盘顺序写慢但随机 IO 正常
iostat -xz 1
└── 顺序写实质上对 SSD 是好的,机械盘要注意 noatime、I/O 调度器
└── cfq / deadline / noop → 对比测试
└── echo cfq > /sys/block/sda/queue/scheduler(重启失效)
smem -p -k
└── RSS 减 shared ≈ PSS(proportional set size)
└── 容器视角下 cgroup RSS 计 PSS,会看到远小于 RSS 的大进程
十、风险提醒
下面这些操作只要出现踩过一次就够记一辈子。
1. rm
- 风险:不进回收站,删了就删了。
- 替代:先
ls -la 确认;mv 到 /tmp 或独立回收目录;脚本里至少一遍 -print + cat。
2. find -delete
- 风险:漏路径或正则错,可能删错。
- 替代:先
find ... -ls | head 看路径,再 find ... -print | head,最后 -delete。
3. truncate
- 风险:清空当前 inode 大文件,进程 fd 仍指向原 inode,可能导致文件空洞或写错位置。
- 替代:用 logrotate + 信号让服务重开文件。
4. KILL
- 风险:
kill -9 不给进程清理机会,会丢事务、不刷盘、文件描述符泄露。数据库、上游业务千万不要 kill -9。
- 替代:先
kill -TERM,给 30s 缓冲;再不响应才 -9。
5. 批量脚本
- 风险:写
for i in $(cat list) 错把 \n 拼接错,导致一行跑成 N 段。
- 替代:明确
while read line,或者 xargs -n1 一行一命令。
6. 修改内核参数 / 防火墙 / 数据库参数
- 风险:错误参数可能让机器拒绝所有网络或磁盘 IO。
- 替代:先在测试机试;用
sysctl -w 临时改,验证后再写进 sysctl.conf。
7. 重启服务
- 风险:很多服务有缓存,重启会引发缓存击穿打挂下游。需要走灰度或预热。
- 替代:优先
reload;确实需要重启先确认是否有探活、是否有备用节点摘流。
8. 修改生产配置
- 风险:配置文件改错直接报错启动失败。
- 替代:始终
nginx -t、apachectl -t、httpd -t、mvn validate 类。
9. 主从切换(数据库)
- 风险:错方向切换、数据丢失、从库脱节。
- 替代:先
show slave status\G 看 Seconds_Behind_Master、Relay_Log_File、Exec_Master_Log_Pos,确认无延迟再切。
10. 磁盘 / 文件 / 系统盘清理
- 风险:清理日志时不重开文件不会释放磁盘;清理 socket 路径可能破坏进程。
- 替代:日志清理走 logrotate 流程;socket 清理让进程自己删。
十一、验证方式
每次处理完都要验证,否则可能“看起来好其实没好”。
1. CPU 恢复
top -b -n 1 | head -5
ps -eo pid,pcpu --sort=-pcpu | head
预期:CPU 占用降回基线。
2. 内存回收
free -h
cat /proc/<pid>/status | grep VmRSS
预期:available 回升;进程 RSS 不再持续上涨。
3. 磁盘释放
df -h
du -sh /path/
预期:Use% 回到安全水位。
4. 网络恢复
ss -s
mtr -n <host>
curl -I http://...
预期:网络包建立正常,curl 返回 200/301/302 而不是 timeout。
5. 服务恢复
systemctl status <srv>
journalctl -u <srv> -n 50 --no-pager
ss -tunlp | grep <port>
预期:active (running)、监听端口恢复。
6. 配置生效
nginx -T | grep ...
httpd -t
mysqld --verbose --help | grep -i <option>
redis-cli config get <key>
预期:拿到预期配置。
7. 内核参数生效
sysctl net.core.somaxconn
sysctl -p
预期:值与配置文件匹配。
8. 限速 / 配额
ulimit -n
cat /proc/<pid>/limits
预期:与配置一致。
十二、回滚方案
下面对“高风险操作”给出最小可行的回滚思路。
1. 内核参数变更
- 修改前:
sysctl -w net.core.somaxconn=65535 记录当前值,或者读 /etc/sysctl.conf 备份。
- 回滚:
sysctl -w net.core.somaxconn=ORIG、或 cp sysctl.conf.bak sysctl.conf && sysctl -p。
2. 防火墙规则
- 修改前:
iptables-save > /etc/iptables.backup 或对应 firewall 导出。
- 回滚:
iptables-restore < /etc/iptables.backup。
3. 服务配置
- 修改前:
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak。
- 回滚:
cp 回来 + nginx -t && nginx -s reload。
4. 数据库参数
- 修改前:
SELECT @@xxx、SHOW VARIABLES LIKE 'xxx' 记录。
- 回滚:
SET GLOBAL xxx = 'old'。
5. 资源限制
- 修改前:
ulimit -n 当前值记录。
- 回滚:登录新 session 重设;或重启服务;或在
/etc/security/limits.conf 改回。
6. 日志清理
- 删除前:分类、按业务决定保留天数。
- 回滚:从 OSS/S3 备份拉回来。
7. 文件误删
- 如果是 lvm + snapshot:回挂 snapshot 取回。
- 如果有备份:恢复。
- 如果都没有:磁盘数据恢复工具 extundelete / testdisk(成功率看文件系统活动)。
- 教训:上文件恢复只能取证式恢复,不保证完整。
8. 错误创建的 crontab
- 修改前:
crontab -l > /root/cron.bak。
- 回滚:
crontab /root/cron.bak。
9. 错误执行的 systemctl 命令
- 误禁用/启用:
systemctl disable/enable 撤销。
- 误 mask:
systemctl unmask。
十三、生产环境注意事项
下面这些是“为什么专业运维和业余运维看起来在做相同事情,但稳定性差很多”的本质原因。
1. 所有变更都要走变更窗口
- 加白名单 / 修改防火墙 / 数据库参数 / 资源限制:都需要灰度、值班、检查单、确认步骤。
- reload / restart:要让观察者随时在场,关注错误率上升、关注告警。
2. 配置变更走“先 t 后 reload”
nginx -t && nginx -s reload
加 && 是为了让前者失败时不执行后者。这是工程纪律问题。
3. 编辑器选择
vi / vim 是默认选择。
- 改完文件
nginx -t、apachectl -t、mysqld --verbose --help 类似的校验不能省。
4. 拆解操作步骤
- 不在生产机器上跑没审过的 shell 片段;先在测试机 / 容器跑通。
- 复杂操作逐步执行,每步验证。
5. 执行窗口
- 高峰、变更窗口慎重;批处理、定时任务选低峰跑。
- 大批量任务(清理日志、
find -delete)要分批执行,并监控负载。
6. 权限 / 凭据
- 不让脚本明文保存密码,用
~/.netrc、/etc/<svc>/<config>.cnf(权限 600)、环境变量、密钥管理系统。
- 用
ssh -i 而不是把私钥写到配置里。
7. 时间一致
- 多机时间偏差大,日志/告警/调度无法对齐。
- 安装并启用
chronyd、或云厂商 NTP 服务。
8. 资源规划
/var/log、/tmp、/var/cache 各自独立分区或挂载,避免日志写满根盘。
inode 也要监控,电商促销等场景会生成大量小文件。
9. 内核升级 / 系统升级
- 升级内核要走灰度,尤其 ext4 / xfs / 网络栈 / cgroup 的行为在不同内核版本上不一样。
- 升级
glibc 同理。
10. 与团队沟通
- 任何“看起来正常但我不确定”的操作,先和团队负责人对齐。
- 留书面记录(PR、工单、变更单)。
11. 调试痕迹不要长期驻留
strace 输出文件、perf 数据、tcpdump pcap 都有敏感数据,跑完即删。
12. 备份与回滚
- 关键目录(
/etc、/var/spool/cron、/var/lib/mysql、nginx vhost)都要有定期备份。
- 重要配置修改前后做 diff:
diff -u before.conf after.conf | less。
13. 进程退出码
- 脚本
set -euo pipefail。
- 关键命令做
|| exit 1 显式失败。
- 日志统一格式,便于 ELK 分析。
14. 备机与降级
- 关键服务要有备机 / 多副本,保证单台挂了不影响整体 SLA。
- 故障期间适当降级(关不重要的非核心功能),先把核心稳住。
15. 知识沉淀
- 把每次线上问题的现象、命令、根因、修复、回滚写到团队 wiki。
- 沉淀为内部 runbook,下次同样的问题直接走 runbook 第一段。
十四、总结
Linux 运维基本盘,是把 资源维度(CPU / 内存 / 磁盘 / 网络)× 信息源(/proc、/sys、strace、日志、journal)× 命令入口(top/ps/pidstat/iostat/vmstat/ss/lsof/strace/journalctl) 这套三维网络打通。
一口气掌握的命令不需要几十个,需要的是 “有现象时,能在 60 秒内决定去看哪个文件、跑哪个命令”,并能 90% 覆盖常见问题。
一定要避免的几个反模式:
- 在生产直接
rm、find -delete。
- 高峰期重启服务。
- 改内核参数但没看清原来是什么。
- 看到
load 高就重启机器。
- 看到
iowait 高就上 SSD(要先确认确实是磁盘 IO 瓶颈)。
- 给服务器装
iperf3 这类压测工具但忘了禁公网。
熟练度是练出来的。每天复盘一次当天的告警,对照命令与现象记录到 runbook;下次再遇到,三步之内命中。
把这套命令练熟,“Linux 排障”就真的能从“凭感觉”变成“凭证据”。