Linux运维场景
Linux 运维或系统开发岗位通常不仅仅考察基础命令,更看重你对系统底层原理、线上故障排查以及架构设计的理解。
1. 系统基础与内核原理
1.2 进程与调度
⭐ 如果一个进程退出了,但它的父进程没有调用 wait(),会发生什么?如何查找并且清理僵尸进程?
- 如果父进程由于太忙、程序 Bug 或设计不当,没有调用
wait()或waitpid()系统调用来读取子进程的退出状态并收尸,那么这个子进程的记录会一直留在内核的进程表中。 - 它不占用内存或 CPU,但会占用一个 PID(进程号)。如果僵尸进程过多,会导致系统无法创建新进程。
- 查找命令:
ps axo stat,ppid,pid,comm | grep -w Z - 僵尸进程已死,无法被杀死,通过找到并且杀掉父进程的方式进行:
# 直接获取所有僵尸进程的父进程 PID
ps -A -ostat,ppid,pid,cmd | grep -e '^[Zz]'
kill -9 <父进程PPID>
⭐ 如果系统 CPU Load 很高,但 CPU 使用率(User/Sys)却很低,可能是什么原因?如何解决
- 当 CPU 使用率低但 Load 高时,最常见的原因是:大量进程正卡在不可中断等待中,通常与磁盘 I/O 或网络 I/O 有关。
- 磁盘 I/O 瓶颈(最常见):
- 大量进程在等待磁盘读写完成(例如数据库繁忙、文件系统损坏、磁盘故障)。
- 虽然进程不消耗 CPU 指令,但它们在队列中等待,被算入 Load。
- 网络 I/O 等待:
- 在使用 NFS(网络文件系统)或 Samba 时,如果网络延迟极高或服务端挂死,客户端进程会进入 D 状态等待响应。
- 僵尸进程或 D 状态进程堆积:
- 某些内核驱动程序 Bug 导致进程陷入不可中断状态,无法被唤醒也无法被杀掉。
- 内存交换(Paging/Swapping):
- 当物理内存不足,系统频繁进行 Swap 换页操作时,由于磁盘速度远慢于内存,会导致大量 I/O 等待,拉高 Load。
排查思路
- 确认等待类型
- 观察
top命令中的%wa(I/O Wait) 字段:- 如果
%wa很高:确认是 I/O 导致的问题。 - 使用
vmstat 1:观察b列(Blocked),如果该数值较大,说明有很多进程正处于不可中断等待。
- 如果
- 观察
- 定位具体的磁盘/分区
- 使用
iostat -x 1查看各个磁盘的指标:util%:如果接近 100%,说明磁盘负载已达极限。await:如果响应时间过长(如超过 10ms),说明磁盘性能存在严重瓶颈。
- 使用
- 找出罪魁祸首进程
iotop:像top一样实时显示哪个进程在疯狂读写磁盘。ps aux | awk '$8=="D" {print $0}':直接找出系统中所有处于 D 状态(不可中断睡眠)的进程。
- 确认等待类型
解决方案
- 针对 I/O 密集型应用优化:
- 若是数据库写入过大,考虑增加缓存、读写分离或更换 SSD。
- 检查是否有非正常的日志轮转(Log Rotation)导致瞬间大文件写入。
- 清理异常进程:
- 如果是某个特定进程 Bug 导致的 D 状态,通常
kill -9无效,可能需要重启相关服务或重启服务器来清除内核挂起的句柄。
- 如果是某个特定进程 Bug 导致的 D 状态,通常
- 检查网络挂载点:
- 如果是 NFS 导致的问题,尝试
umount -l(强制卸载) 挂载点,并检查网络连接。
- 如果是 NFS 导致的问题,尝试
内存调优:
- 如果是因为 Swap 导致的 Load 高,应增加物理内存或调低
vm.swappiness参数,减少系统对 Swap 的依赖。 vm.swappiness参数,取值范围:0~100,数值越大,内核越倾向于把内存里不活跃的数据换到 swap;数值越小,越倾向于留在物理内存。
- 如果是因为 Swap 导致的 Load 高,应增加物理内存或调低
文件系统检查:
- 如果磁盘硬件没坏但 I/O 异常,可能需要执行
fsck修复文件系统错误。
- 如果磁盘硬件没坏但 I/O 异常,可能需要执行
- 针对 I/O 密集型应用优化:
1.2 内存管理
⭐ 什么是 OOM Killer?内核根据什么标准决定杀掉哪个进程?
内核如何决定杀掉哪个进程?
- 内核为每个进程计算一个分数,称为
oom_score。分数越高,进程就越容易被选中杀掉。 - 分数计算方式
- 内存消耗量(核心标准): 进程消耗的内存(包括常驻内存 RSS 和页表占用的内存)越多,得分越高。
- 进程优先级: 普通进程(Nice 值高)比关键进程更容易被杀。
- 运行时间: 运行时间非常长的老牌系统服务,其得分会略微降低(内核倾向于认为它们更重要)。
- 特权等级: 以
root用户运行的进程通常比普通用户进程得分稍低(有 3% 的“免死”加权)。 - 子进程影响: 即使父进程内存占用不大,如果它有很多消耗内存的子进程,父进程的分数也会增加。
- 内核为每个进程计算一个分数,称为
人工调整方式
| 文件路径 | 作用 |
|---|---|
/proc/[pid]/oom_score |
只读。显示当前进程的最终得分。 |
/proc/[pid]/oom_adj |
旧接口。范围 -16 到 +15,数值越大越容易被杀。 |
/proc/[pid]/oom_score_adj |
推荐接口。范围 -1000 到 +1000。设置 -1000 相当于给进程发了“免死金牌”。 |
- 查看OOM的发生事件
- 查看日志
dmesg | grep -i "out of memory"
# 或者查看系统消息日志
journalctl -k | grep -i "oom-killer"
- 解决与预防方案
- 临时解决: 增加物理内存或扩大 Swap 分区。
- 限制资源: 使用 Cgroups 限制特定容器或进程的最大内存使用量(这样只会杀掉超限的进程,不影响系统整体)。
- 参数优化:
- 设置
vm.panic_on_oom = 1:如果内存耗尽,直接重启系统而不是乱杀进程(适用于高可用架构)。
- 设置
- 业务层优化:
- 检查是否存在内存泄漏(Memory Leak)或查询返回了过大的数据集。
1.3 文件系统
⭐ 如何快速找出一个目录下所有大于 100M 且在 7 天内修改过的文件?
find /path -type f -size +100M -mtime -7
1.4 综合
⭐ 如果现在一台线上服务器突然响应极慢,你的排查思路是什么?
- 情况确认与尽快恢复
- 确认范围
- 是单个接口慢,还是整台服务器所有请求都慢?是个别用户反馈,还是全网大面积故障?
- 查看近期变更
- 询问团队或查看发布记录,最近 10 分钟内是否有代码上线、配置更改或压测任务?
- 初步隔离
- 如果是集群环境,先将该节点从负载均衡(如 Nginx/SLB)中摘除,防止影响扩大,保留现场进行排查。
- 确认范围
- 排查原因,寻找性能瓶颈
- 通过CPU、内存、磁盘、网络快速定位大方向。
- CPU
- 执行
top查看load average。 - 重点: 如果
us(用户态)高,说明是业务代码计算量大(如死循环、正则表达式);如果sy(内核态)高,可能是频繁的上下文切换或系统调用。
- 执行
- 内存
- 执行
free -m查看可用内存。 - 重点: 观察
available是否触底。检查是否触发了 Swap 交换,一旦用到 Swap,响应速度会掉几个数量级。检查dmesg | grep -i oom看是否有进程被杀。
- 执行
- 磁盘IO
- 执行
iostat -x 1或iotop。 - 重点: 观察
%util(磁盘忙碌度)和await(平均等待时间)。如果 I/O 阻塞,进程会进入D状态,导致系统假死。
- 执行
- 网络
- 执行
sar -n DEV 1查看带宽是否跑满。sar [选项] [间隔秒] [次数]
- 执行
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'统计 TCP 连接状态。 - 重点: 是否有大量的
TIME_WAIT(连接释放太慢)或SYN_RECV(可能遭受攻击)。
- 执行
- 应用与链路层排查
- 日志分析
- 查看应用错误日志(Error Log)和访问日志(Access Log)的耗时字段。
- 查看数据库慢查询日志(Slow Query Log)。
- 进程内部分析
- Java: 使用
jstack查看线程堆栈,看是否发生死锁或长时间等待(如等待数据库连接池)。 - PHP/Python/Go: 使用相应的 Profiling 工具(如 pprof)查看函数执行耗时。
- Java: 使用
- 外部依赖
- 检查 Redis、MySQL、MQ 等中间件的响应时间。
- 检查第三方 API(如支付、短信接口)是否响应缓慢。
- 日志分析
- 深度内核调优
- 文件句柄
ulimit -n是否太小导致连接无法建立。
- DNS 解析
- 检查
/etc/resolv.conf,DNS 解析慢也会导致应用请求超时。
- 检查
- 内核参数
- 如
tcp_max_syn_backlog或somaxconn队列溢出。
- 如
- 文件句柄
[root@localhost ~]# sysctl net.ipv4.tcp_max_syn_backlog net.core.somaxconn
net.ipv4.tcp_max_syn_backlog = 256
net.core.somaxconn = 4096
# 修改文件位置
# 半连接队列,没完成握手,高并发场景一般设 8192 ~ 16384
cat /proc/sys/net/ipv4/tcp_max_syn_backlog
# 全连接队列,已经完成tcp握手,高并发服务(Nginx/Redis)一般要设 16384 或更高
cat /proc/sys/net/core/somaxconn
⭐ 一个算力密集型的Linux服务器,如何做初始化配置
- 基础系统环境优化
- 时钟同步(极重要): 算力集群对时间极其敏感,防止分布式计算中的逻辑错误。
- 更新内核: 算力服务器通常推荐使用最新的 LTS 内核,以获得对新 CPU(如指令集优化)和新 GPU 驱动的更好支持。
- 关闭无关服务: 停掉
postfix、cups、avahi-daemon等后台服务,减少对 CPU 时间片的争抢。
- CPU 与 电源管理调优
- 默认情况下,Linux 为了节能会开启“按需调度”,这会导致计算频率波动。
- 将 CPU 频率调节器设置为性能模式,强制 CPU 运行在最高频率。(虚拟机不支持)
cpupower frequency-set -g performance
- 内核参数: 在 GRUB 中添加
processor.max_cstate=1和idle=poll,防止 CPU 进入深度休眠导致的唤醒延迟。 - 禁用超线程(视场景而定),对于某些极度依赖单核 Cache 的高性能计算任务,关闭超线程(HT/SMT)可以减少 L1/L2 缓存竞争,提升 5%~10% 的纯计算效率。
- 默认情况下,Linux 为了节能会开启“按需调度”,这会导致计算频率波动。
[root@localhost ~]# cat /sys/devices/system/cpu/smt/active
0
- 内存与存储优化
- 开启大页内存(HugePages):对于数据库或深度学习任务,开启 2MB 或 1GB 的大页可以显著减少 TLB(转换后备缓冲区)缺失,提升内存访问效率。
echo 1024 > /proc/sys/vm/nr_hugepages
- 调整虚拟内存压力:
- 尽量使用物理内存
sysctl -w vm.swappiness=10 - 增加脏数据缓存,减少频繁 I/O
sysctl -w vm.dirty_ratio=40- 脏数据就是程序要写入磁盘的数据,Linux 内核不会立刻把它写到硬盘,而是先存在内存的 “页缓存(Page Cache)” 里
- 内存中的脏数据占总可用物理内存的比例达到40%时,内核会强制触发刷盘,此时所有新的写操作都会被阻塞,直到脏数据刷到磁盘、比例降到阈值以下。
- 尽量使用物理内存
- 开启大页内存(HugePages):对于数据库或深度学习任务,开启 2MB 或 1GB 的大页可以显著减少 TLB(转换后备缓冲区)缺失,提升内存访问效率。
- 网络栈调优(针对分布式计算)
- 开启 TCP Fast Open: 减少握手延迟。
sysctl -w net.ipv4.tcp_fastopen=3
- 开启 TCP Fast Open: 减少握手延迟。
- 用户资源限制(ulimit)
- 修改
/etc/security/limits.conf
- 修改
* soft nofile 655350
* hard nofile 655350
* soft nproc 655350
* hard nproc 655350
* soft memlock unlimited
* hard memlock unlimited
- 算力专用组件安装
- 驱动与工具链: 安装对应厂商的驱动(如 NVIDIA Driver)、容器运行时(NVIDIA Container Toolkit)。
- 持久化模式: 对于 NVIDIA GPU,开启 Persistence Mode 以缩短驱动加载延迟:
nvidia-smi -pm 1
2. 网络协议与配置
2.1 TCP/IP协议栈
⭐ 服务器出现大量 TIME_WAIT 状态,会影响性能吗?如何处理?
TIME_WAIT 是 TCP 挥手时的正常状态,维持 2MSL 时间。它对性能的影响主要是占用端口资源导致无法发起新连接。我会优先通过应用层长连接来减少连接开销。
- 开启 HTTP Keep-Alive
- 如果是后端程序访问 MySQL 或 Redis,务必使用连接池,避免每次请求都新建/关闭连接。
如果必须调优,我会开启 tcp_tw_reuse 来加速端口回收。开启net.ipv4.tcp_tw_reuse = 1之后,允许内核将处于 TIME_WAIT 状态的端口重新分配给新的连接(仅限作为客户端主动发起连接时)。这是最推荐的内核参数。
还可以增大可用的临时端口总数,net.ipv4.ip_local_port_range = 1024 65535
还可以设置系统允许的最大 TIME_WAIT 数量。超过此值,系统会直接清理多余的连接并记录日志。net.ipv4.tcp_max_tw_buckets = 20000
⭐ 线上服务器突然收到大量 SYN 包,导致正常用户无法建立连接,你该如何排查和防御?
- 快速排查与确认
- 使用
netstat或ss命令统计当前各状态的连接数。ss -ant | awk 'NR>1 {++S[$1]} END {for(a in S) print a, S[a]}'- 如果发现
SYN_RECV状态的数量异常高(通常达到几千甚至上万),基本可以判定遭受了 SYN 攻击。
- 使用
tcpdump查看进入的流量特征。tcpdump -i eth0 -n tcp and port 80- 异常特征: 如果看到大量来自不同随机 IP 的
SYN包,且这些 IP 往往无法 Ping 通(伪造地址),或者没有后续的ACK包。
- 使用
- 短期紧急防御
- 开启 SYN Cookies(最有效):
sysctl -w net.ipv4.tcp_syncookies=1- 原理: 当半连接队列满时,内核不再直接把请求存入队列,而是计算出一个“Cookie”发回给客户端。只有当收到合法的
ACK回包时,才分配资源。这可以有效防止队列被占满。
- 增大半连接队列容量:
sysctl -w net.ipv4.tcp_max_syn_backlog=2048 - 减少 SYN-ACK 重试次数:
sysctl -w net.ipv4.tcp_synack_retries=2
- 开启 SYN Cookies(最有效):
加固网络与防火墙
- 利用 iptables 限制频率:
- 对单个 IP 的
SYN包频率进行限制。 iptables -A INPUT -p tcp --syn -m limit --limit 1/s --limit-burst 3 -j ACCEPT
- 对单个 IP 的
- 丢弃无效包:
- 开启反向路径过滤(Reverse Path Filtering),丢弃那些源 IP 明显不合法的包。
- 检查数据包的「实际进入网卡」是否等于「路由表计算出的反向路径网卡」,不一致则丢弃,本质是验证源 IP 的合法性;
sysctl -w net.ipv4.conf.all.rp_filter=1
- 利用 iptables 限制频率:
长期考虑架构升级
- 接入高防服务(Anti-DDoS)
- 负载均衡分摊
- TCP 代理/中继
2.2 网络工具
⭐ 如何使用 tcpdump 抓包
- 常用的几个参数如下
| 参数 | 含义 | 场景 |
|---|---|---|
-i |
指定网卡 | eth0, any (所有网卡) |
-n |
不解析域名/端口 | 避免 DNS 反查导致的延迟,显示原始 IP |
-X |
以十六进制和 ASCII 显示 | 查看应用层报文内容(如 HTTP Header) |
-v / -vv |
详细信息 | 查看 TTL、ID、标志位等更深层信息 |
-w |
写入文件 | 将抓包结果保存为 .pcap,以便用 Wireshark 分析 |
-c |
抓取指定包数 | 达到数量后自动停止,防止硬盘被塞满 |
- 查看特定IP+端口
tcpdump -i eth0 -nn host 192.168.1.10 and port 3306
- 查看具体的业务,比如http的POST报文
tcpdump -i eth0 -nn -A -s 0 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'
- 排查半连接攻击
tcpdump -i eth0 'tcp[tcpflags] & (tcp-syn) != 0'
主要看的内容
- 看重传(Retransmission): 如果在抓包结果中看到短时间内有很多相同序号的包,说明网络丢包严重或对方没收到。
- 看 RST 包: 如果刚握手就收到
RST,通常是端口没开、防火墙拦截或连接超过了服务器负载。 - 看时间偏移: 观察请求包和响应包之间的时间差。如果请求很快到了服务器,但响应包很久才发出来,说明是后端业务逻辑慢,而非网络问题。
- 看 Window Size: 如果看到
win 0,说明接收方缓存已满,导致“零窗口”,数据传输会暂停。
报文太复杂,可以存本地使用wireshark工具查看
tcpdump -i eth0 -w dump.pcap
2.3 负载均衡
- 常问的负载均衡服务有如下几种
| 工具 | 工作层级 | 核心特点 |
|---|---|---|
| LVS | 四层 (Transport) | 基于 IP + Port 的负载均衡,工作在内核空间,性能极高。 |
| Nginx | 七层 (Application) | 强大的反向代理和 Web 处理能力,支持根据 URL、Header 转发。 |
| HAProxy | 四层 & 七层 | 专业负载均衡器,具备极强的会话保持和健康检查能力。 |
⭐ 为什么 LVS 的性能比 Nginx 高
- LVS 工作在内核态,报文处理路径极短,不涉及复杂的上下文切换。
- Nginx 工作在用户态,需要进行两次 TCP 连接(客户端到 Nginx,Nginx 到后端),消耗更多 CPU 和内存。
⭐ LVS 的 DR 模式为什么快
- 因为 DR 模式下,只有请求流量经过 LVS,响应流量(DS)直接由后端服务器返回给客户端,不经过负载均衡器,解决了带宽瓶颈。
⭐ 什么时候该选 HAProxy 而不是 Nginx?
- HAProxy 支持 TCP 四层级的负载均衡(如数据库 MySQL、Redis 的高可用),而 Nginx 早期主要强在 HTTP 七层(虽然现在也有 Stream 模块)。
- HAProxy 的健康检查更精细(可以检查具体的业务返回码),且在连接数极高时,其稳定性通常优于 Nginx。
⭐ LVS不适合的场景
- LVS 无法感知应用层信息。如果你需要根据 Cookie、URL 路径、User-Agent 来做分流,或者需要支持 SSL 卸载,LVS 做不到,必须用 Nginx 或 HAProxy。
⭐ 你会如何设计一个日活千万级系统的接入层?
- 推荐标准架构:LVS + Keepalived + Nginx
- 第一层(入口):LVS
- 负责抗流量,做 VIP 高可用,分发给多台 Nginx。
- 第二层(代理):Nginx
- 负责七层转发、Rewrite、Gzip 压缩、SSL 证书卸载、缓存以及业务逻辑分流。
- 第三层(后端):App Server
- 第一层(入口):LVS
2.4 DNS与CDN
⭐ DNS递归查询与迭代查询的区别
- 递归查询 (Recursive Query)
- 客户端(通常是你的电脑)向本地 DNS 服务器(LDNS)发起请求。在这种模式下,客户端只发一次请求,剩下的事情全部交给本地 DNS 服务器去处理。
- 迭代查询 (Iterative Query)
- 这通常发生在 DNS 服务器之间。本地 DNS 服务器向根域名服务器发起请求,根服务器不会直接给 IP,而是回复:“我不知道这个域名的 IP,但我知道
.com服务器的地址,你去问它吧。”
- 这通常发生在 DNS 服务器之间。本地 DNS 服务器向根域名服务器发起请求,根服务器不会直接给 IP,而是回复:“我不知道这个域名的 IP,但我知道
⭐ 当用户访问一个接入了 CDN 的域名时,整个解析过程发生了什么变化?
用户查询域名,DNS 发现该域名配置了 CNAME,指向 CDN 厂商的调度域名。
调度域名通过 智能 DNS(GSLB),根据用户的出口 IP,判断其地理位置、运营商(如电信、联通)。
返回离用户最近、负载最低的边缘节点 IP。
⭐ 如果某天源站压力突然暴增,发现 CDN 回源率很高,你会从哪些方面排查?
- 缓存策略: 检查
Cache-Control或Expires响应头设置是否合理(是否太短)。 - 参数过滤: URL 是否带了随机参数(如
?timestamp=xxx)导致 CDN 认为每次都是新资源。 - 热点资源: 是否有突发热点文件过期导致“缓存击穿”。
3. 故障排查与性能调优 (核心)
3.1 CPU
⭐ 如果系统 CPU Load 很高,但 CPU 使用率(User/Sys)却很低,可能是什么原因?如何解决
- 参见本篇1.2
3.2 磁盘IO
⭐ 磁盘 I/O 持续 100% 但读写速度极低
- 使用
iostat -xz 1查看瓶颈,如果util满但rkB/s(读速度)和wkB/s(写速度)加起来只有几百 KB,基本可以断定系统卡在了 “随机小文件读写” 或 “硬件故障” 上。 - 硬件老化或物理坏道,
dmesg | grep -iE "error|exception|status",观察是否有I/O error、sector报错。 - 文件系统损坏或日志回滚,查看
top中的systemCPU 占比是否异常。必要时需卸载分区进行fsck修复。
3.3 性能工具
⭐ 常用到的性能排查工具,性能排查五剑客(top, iostat, vmstat, sar, strace )
- top
- 系统状态“总览”
- us 高
- 去查哪个进程、哪个函数吃 CPU
- 高了说明计算密集
- sy 高
- 去查系统调用、线程切换、中断、I/O
pidstat -w查看上下文切换,切换越频繁sy占比越高vmstat 1显示cs列(总切换数),但是不知道是谁导致的strace -tt -Tp PID查看进程与内核的交互,可以知道是哪一个操作比较耗时
- 频繁网络收发(小包、高并发)
- 大量线程切换
- 大量日志写入
- 频繁创建关闭连接
- 去查系统调用、线程切换、中断、I/O
iostat
- 磁盘 I/O 性能监视
iostat -xz 1:每秒刷新一次,显示详细(-x)的扩展指标。- 关键指标:
%util:磁盘忙碌度。如果接近 100%,说明磁盘几乎满负荷。await:每次 I/O 操作的平均等待时间。如果超过 10ms,通常认为磁盘压力过大。rkB/s/wkB/s:每秒读写的数据量。
vmstat
- 用于观察上下文切换、内存交换和进程队列。它比
top更轻量,适合看整体趋势。 vmstat 1 5:每秒采样一次,共采样 5 次。- 关键指标:
r(Running):等待 CPU 的进程数。如果长期大于 CPU 核数,说明 CPU 资源极度匮乏。b(Blocked):等待 I/O 的进程数。cs(Context Switch):每秒上下文切换次数。数值过高说明内核开销巨大(比如大量线程竞争)。si/so:Swap 换入/换出量。如果大于 0,说明物理内存已耗尽。
- 用于观察上下文切换、内存交换和进程队列。它比
sar
- 历史统计
- 核心命令:
sar -n DEV 1 5:查看网络流量趋势。sar -q:查看历史负载。sar -f /var/log/sa/sa20:查看本月 20 号的历史记录。
strace
- 当一个程序卡住或报错,但日志里什么都没写时。它可以列出程序执行的所有系统调用。
- 核心命令:
strace -p <pid>:实时跟踪某个进程。strace -c -p <pid>:统计一段时间内该进程各系统调用的耗时分布(寻找最慢的系统调用)。strace -e open,connect -p <pid>:只查看打开文件和网络连接相关的调用。- 程序启动时报错‘找不到文件’,但代码里没打印路径,怎么办?
- 使用
strace -e trace=file ./app观察它到底在尝试 open 哪个路径。
- 使用