Linux运维常见问题


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 无效,可能需要重启相关服务重启服务器来清除内核挂起的句柄。
    • 检查网络挂载点:
      • 如果是 NFS 导致的问题,尝试 umount -l (强制卸载) 挂载点,并检查网络连接。
    • 内存调优:

      • 如果是因为 Swap 导致的 Load 高,应增加物理内存或调低 vm.swappiness 参数,减少系统对 Swap 的依赖。
      • vm.swappiness 参数,取值范围:0~100数值越大,内核越倾向于把内存里不活跃的数据换到 swap;数值越小,越倾向于留在物理内存。
    • 文件系统检查:

      • 如果磁盘硬件没坏但 I/O 异常,可能需要执行 fsck 修复文件系统错误。

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 1iotop
      • 重点: 观察 %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)查看函数执行耗时。
    • 外部依赖
      • 检查 Redis、MySQL、MQ 等中间件的响应时间。
      • 检查第三方 API(如支付、短信接口)是否响应缓慢。
  • 深度内核调优
    • 文件句柄
      • ulimit -n 是否太小导致连接无法建立。
    • DNS 解析
      • 检查 /etc/resolv.conf,DNS 解析慢也会导致应用请求超时。
    • 内核参数
      • tcp_max_syn_backlogsomaxconn 队列溢出。
[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 驱动的更好支持。
    • 关闭无关服务: 停掉 postfixcupsavahi-daemon 等后台服务,减少对 CPU 时间片的争抢。
  • CPU 与 电源管理调优
    • 默认情况下,Linux 为了节能会开启“按需调度”,这会导致计算频率波动。
      • 将 CPU 频率调节器设置为性能模式,强制 CPU 运行在最高频率。(虚拟机不支持)
      • cpupower frequency-set -g performance
    • 内核参数: 在 GRUB 中添加 processor.max_cstate=1idle=poll,防止 CPU 进入深度休眠导致的唤醒延迟。
    • 禁用超线程(视场景而定),对于某些极度依赖单核 Cache 的高性能计算任务,关闭超线程(HT/SMT)可以减少 L1/L2 缓存竞争,提升 5%~10% 的纯计算效率。
[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%时,内核会强制触发刷盘,此时所有新的写操作都会被阻塞,直到脏数据刷到磁盘、比例降到阈值以下。
  • 网络栈调优(针对分布式计算)
    • 开启 TCP Fast Open: 减少握手延迟。sysctl -w net.ipv4.tcp_fastopen=3
  • 用户资源限制(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 包,导致正常用户无法建立连接,你该如何排查和防御?

  • 快速排查与确认
    • 使用 netstatss 命令统计当前各状态的连接数。
      • 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
  • 加固网络与防火墙

    • 利用 iptables 限制频率:
      • 对单个 IP 的 SYN 包频率进行限制。
      • iptables -A INPUT -p tcp --syn -m limit --limit 1/s --limit-burst 3 -j ACCEPT
    • 丢弃无效包:
      • 开启反向路径过滤(Reverse Path Filtering),丢弃那些源 IP 明显不合法的包。
      • 检查数据包的「实际进入网卡」是否等于「路由表计算出的反向路径网卡」,不一致则丢弃,本质是验证源 IP 的合法性;
      • sysctl -w net.ipv4.conf.all.rp_filter=1
  • 长期考虑架构升级

    • 接入高防服务(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
    1. 第一层(入口):LVS
      • 负责抗流量,做 VIP 高可用,分发给多台 Nginx。
    2. 第二层(代理):Nginx
      • 负责七层转发、Rewrite、Gzip 压缩、SSL 证书卸载、缓存以及业务逻辑分流。
    3. 第三层(后端):App Server

2.4 DNS与CDN

DNS递归查询与迭代查询的区别

  • 递归查询 (Recursive Query)
    • 客户端(通常是你的电脑)向本地 DNS 服务器(LDNS)发起请求。在这种模式下,客户端只发一次请求,剩下的事情全部交给本地 DNS 服务器去处理。
  • 迭代查询 (Iterative Query)
    • 这通常发生在 DNS 服务器之间。本地 DNS 服务器向根域名服务器发起请求,根服务器不会直接给 IP,而是回复:“我不知道这个域名的 IP,但我知道 .com 服务器的地址,你去问它吧。”

当用户访问一个接入了 CDN 的域名时,整个解析过程发生了什么变化?

  • 用户查询域名,DNS 发现该域名配置了 CNAME,指向 CDN 厂商的调度域名。

  • 调度域名通过 智能 DNS(GSLB),根据用户的出口 IP,判断其地理位置、运营商(如电信、联通)。

  • 返回离用户最近、负载最低的边缘节点 IP。

如果某天源站压力突然暴增,发现 CDN 回源率很高,你会从哪些方面排查?

  • 缓存策略: 检查 Cache-ControlExpires 响应头设置是否合理(是否太短)。
  • 参数过滤: 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 errorsector 报错。
  • 文件系统损坏或日志回滚,查看 top 中的 system CPU 占比是否异常。必要时需卸载分区进行 fsck 修复。

3.3 性能工具

常用到的性能排查工具,性能排查五剑客(top, iostat, vmstat, sar, strace )

  • top
    • 系统状态“总览”
    • us 高
      • 去查哪个进程、哪个函数吃 CPU
      • 高了说明计算密集
    • sy 高
      • 去查系统调用、线程切换、中断、I/O
        • pidstat -w 查看上下文切换,切换越频繁sy占比越高
        • vmstat 1 显示 cs列(总切换数),但是不知道是谁导致的
        • strace -tt -Tp PID 查看进程与内核的交互,可以知道是哪一个操作比较耗时
      • 频繁网络收发(小包、高并发)
      • 大量线程切换
      • 大量日志写入
      • 频繁创建关闭连接
  • 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 哪个路径。
施工现场未完待续...

3.4 日志分析

4. 容器化与云原生

5. 安全与自动化脚本


文章作者: AaronXu
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 AaronXu !
评论
  目录