性能分析与故障定位实战

共 21 题
📑 题目列表 21 题
#
★★★

1. kernel.core_pattern 如何配置 core dump 落盘(路径、命名与管道转发),core 大小限制(ulimit -c)与生产环境的安全处置

kernel.core_pattern 如何配置 core dump 的落盘路径、命名与管道转发?ulimit -c 与 core 文件的生产环境安全处置如何配合?

  • core_pattern 语法:路径、%p/%e/%t 等占位符与管道转发(|)
  • ulimit -c 软硬限制与 systemd 对 core 的接管(core 存储到 journald/coredumpctl)
  • 生产安全:权限、敏感内存、磁盘空间与保留策略

core dump 是进程崩溃时内核写入的内存转储,用于事后 gdb 调试。kernel.core_pattern 控制落盘行为:/var/crash/core.%p.%e 按 pid/可执行名落盘;支持 %p(pid)、%u(uid)、%e(可执行名)、%t(时间戳)、%s(信号)等占位符;以 | 开头为管道转发(如 |/usr/lib/systemd/systemd-coredump 交给 systemd-coredump 处理,或转发给自建采集服务),管道形式便于统一收集、压缩、脱敏。是否产生 core 还受 ulimit -c 限制:soft 为 0 时不生成(ulimit -c unlimited 放开),且须注意 core 生成还要求崩溃进程的 RLIMIT_CORE 与文件系统权限。

生产环境安全处置:core 含进程内存(可能含密钥、数据),必须限制属主与权限(如 umask 077、专用目录、设置 fs.suid_dumpable=0 禁止 setuid 程序 dump);限定大小与数量(systemd-coredump 的 Compress=、ExternalSizeMax、Storage=)防止磁盘打满;对核心业务可用 systemd-coredump + coredumpctl gdb <pid> 抓取调试;崩溃频繁时先定位根因再决定是否关闭 dump(kernel.core_pattern=/dev/null 或 ulimit -c 0 是临时止血)。容器内 dump 落盘与宿主路径需打通(通常配置到宿主共享目录)。

本题考察崩溃调试基础设施的配置与安全。回答要点:core_pattern 路径/占位符/管道三种形态、ulimit -c 与 systemd-coredump 的联动、权限与容量安全处置,形成"能产生、能取到、不泄漏、不拖垮磁盘"的完整方案。

sysctl kernel.core_pattern                    # 查看当前配置
sysctl -w kernel.core_pattern='/var/crash/core.%e.%p.%t'
ulimit -c unlimited                           # 当前 shell 放开 core
echo "kernel.core_pattern=|/usr/lib/systemd/systemd-coredump %p %u %g %s" >> /etc/sysctl.d/99-core.conf
coredumpctl list; coredumpctl gdb 12345       # systemd 侧查看/调试
#
★★★

2. memory cgroup 的 memory.high 与 memory.max 如何实现软、硬内存限制?

cgroup v2 中 memory.high 与 memory.max 如何实现软、硬内存限制?两者行为差异与生产配置建议是什么?

  • memory.max:硬上限,超限触发回收/OOM(OOM Kill)
  • memory.high:软上限,超限后回收/节流但不直接 OOM
  • 配置策略:high 作预警水位、max 作硬边界,避免频繁 reclaim

cgroup v2 的 memory 控制器用两级限制:memory.max 是硬上限,cgroup 内存用量超过它时内核强制回收(reclaim)缓存,仍无法满足分配则对该 cgroup 触发 OOM Kill(kill 组内进程或按 oom.group 整组处理),进程表现为被杀或分配失败,是"最后边界";memory.high 是软上限,超过后内核立即尝试回收该 cgroup 的页缓存并对其内存分配进行节流(throttle),但不保证强制——若无法回收(如全是匿名页),进程会被延迟而非杀死。两者关系:high 应小于 max,形成"先预警节流、后强制兜底"的两级防护。

生产建议:不要只设 max 或只设 high。典型做法是 max 设为容器承诺配额(硬隔离,防止单容器拖垮宿主),high 设为略低于 max 的预警水位(如 max 的 80%-90%),让突发内存被提前回收平滑;同时配合 memory.swap.max 控制交换、观察 memory.events 中的 high/max/oom 计数判断触顶频率。注意:若业务内存不可回收(匿名页为主),high 的节流会造成吞吐下降与延迟尖峰,需结合真实负载调试;数据库类应用建议把 buffer pool 控制在 max 之内并关闭 swap(swappiness 低),避免被 max 触发 OOM。监控 memory.current 与 PSI 指标评估实际压力。

本题考察 cgroup 内存隔离的核心机制。回答要点:max 的"强制回收+OOM"与 high 的"软回收+节流"语义差异、两级配置的工程方法(high 预警、max 兜底)、以及高/低水位对延迟与吞出的影响权衡,体现容器内存治理的实操理解。

cat /sys/fs/cgroup/<cg>/memory.high /sys/fs/cgroup/<cg>/memory.max
echo "1G" > /sys/fs/cgroup/<cg>/memory.high
echo "1.2G" > /sys/fs/cgroup/<cg>/memory.max
cat /sys/fs/cgroup/<cg>/memory.events     # high/max/oom 事件计数
#
★★★

3. transparent hugepage 在数据库主机的禁用原因

为什么数据库主机通常要禁用透明大页(THP)?THP 的工作原理与对数据库的影响机制是什么?

  • THP 机制:khugepaged 后台合并与 fault 时分配 2MB 大页
  • 影响:页合并/分裂带来 CPU 抖动与延迟尖峰、内存碎片化
  • 禁用方式:never/madvise、grub 内核参数与运行时切换

透明大页(THP)让内核自动以 2MB 大页代替 4KB 页,减少 TLB miss,本意是提升性能,但数据库主机通常禁用:一是在线合并(khugepaged 把相邻小页合并为大页)与分裂(THP 页面部分访问触发 split)过程会占用 CPU 并产生内存操作,引发可观测的延迟尖峰(在延迟敏感的数据库上表现为周期性的慢查询);二是 THP 与内存碎片化相互作用,defrag 模式的直接压缩分配(direct compaction)可能阻塞分配路径造成卡顿;三是数据库多使用 mmap 的大块匿名内存(如 InnoDB buffer pool),THP 的合并行为与数据库自管理的预分配模式冲突,且 NUMA 环境下大页分配的跨节点问题更复杂。

禁用方式:运行时写 /sys/kernel/mm/transparent_hugepage/enabled 为 never(立即生效,但已有 THP 页不会自动拆分),持久化需在内核引导参数加 transparent_hugepage=never(grub/efiboot 配置);madvise 模式表示仅对显式 madvise(MADV_HUGEPAGE) 的内存启用,是折中方案。验证:cat 上述文件确认 never,并用 grep AnonHugePages /proc/meminfo 观察是否归零。注意 5.15+ 内核 THP 行为有改进,部分场景可用 madvise,但数据库厂商(如 MySQL/Oracle 官方文档)仍普遍建议关闭。

本题考察数据库性能调优的经典反面参数。回答要点:THP 的合并/分裂机制、对延迟敏感的数据库的伤害路径(CPU 抖动、compaction 阻塞、碎片化)、never/madvise 两种禁用模式与引导参数持久化,并提醒新内核的变化,体现参数选择的依据而非教条。

cat /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/enabled
grep -i huge /proc/meminfo        # AnonHugePages 应为 0
# 持久化:grub 内核参数加 transparent_hugepage=never
#
★★

4. PSI(/proc/pressure)cpu/memory/io stall 指标解读

PSI(Pressure Stall Information)的 cpu、memory、io 指标如何解读?它在容量与性能排障中有什么价值?

  • /proc/pressure 三个文件的 some/avg 与 full 字段语义
  • PSI 度量"任务因资源不足被延迟"而非资源使用率
  • 应用场景:容器压力监控、早期容量预警

PSI 通过 /proc/pressure/cpu、/proc/pressure/memory、/proc/pressure/io 暴露资源压力:每个文件含 some 与 full 两组行,some 表示"至少一个任务被资源不足延迟"的时间占比,full 表示"所有任务都被延迟"(资源严重不足,进程完全停滞)的时间占比,均提供 10 秒/60 秒/300 秒窗口的 avg 值与累计 total。与 CPU 利用率、IO util 等"使用率指标"不同,PSI 直接度量"任务被卡住的时间比例",能反映资源竞争对业务的实际伤害——例如 CPU 使用率 60% 但 some avg 很高,说明存在周期性争用。

价值与应用:一是排障语义清晰——memory full 高说明内存不足导致进程集体停滞(配合 memory.events 与 swap 判断)、io full 高说明磁盘饱和、cpu some 高说明调度争用;二是容量预警更早——PSI 在资源接近饱和前就出现 nonzero,适合作为容量与 SLO 告警指标;三是与 cgroup 结合可看容器级压力(/sys/fs/cgroup//cpu.pressure 等)。K8s 生态中 kubelet 也支持用 PSI 做内存/CPU 驱逐参考(cgroup v2 下)。解读注意:some 高而 full 低是"局部争用",full 高才是"整体瘫痪";avg 窗口选择要匹配业务周期。

本题考察现代资源压力度量体系。回答要点:some/full 与 avg 窗口语义、"压力=任务延迟"的本质、三类资源各自的典型告警解读,以及与使用率指标的区别(PSI 反映伤害而非占用),体现对内核 4.20+ 压力接口的理解。

cat /proc/pressure/cpu /proc/pressure/memory /proc/pressure/io
# 容器级
cat /sys/fs/cgroup/<cg>/memory.pressure
# 持续监控
while true; do cat /proc/pressure/memory; sleep 10; done
#
★★

5. USE 方法(利用率/饱和度/错误)系统性排障

USE 方法的三个维度是什么?如何用它系统性地排查资源瓶颈?

  • USE:利用率(Utilization)、饱和度(Saturation)、错误(Errors)
  • 逐资源检查顺序与对应工具
  • 与其他方法论(RED)的互补关系

USE 方法(Brendan Gregg 提出)对每个资源(CPU、内存、磁盘、网络、锁)依次回答三个问题:利用率——资源忙于服务的时间占比(如 CPU util、磁盘 util、网络带宽占用);饱和度——资源排队等待的程度(如运行队列长度、磁盘队列、TCP 重传);错误——软硬件错误计数(如网卡 drops/errors、磁盘 CRC 错误、内存 ECC)。检查顺序按"从下游到上游"或"从系统到组件",先定位哪个资源异常,再下钻到该资源的三维指标,避免大海捞针。对应工具:CPU(top 的 us/sy/wa、vmstat 的 r、perf)、内存(free、vmstat si/so、PSI)、磁盘(iostat -x 的 util/await、iostat -d 的 errors)、网络(sar -n DEV/ERRORS、netstat -s、ss、ethtool -S)。

价值:把"排查动作标准化"——对每个资源逐项回答三问,能把"系统慢"快速收敛为"某资源的某维度异常"(如"磁盘利用率不高但饱和度很高"指向队列问题)。与 RED(请求速率/错误/耗时,服务视角)互补:USE 是资源视角(系统),RED 是请求视角(应用),结合使用形成"系统有瓶颈吗→业务受损吗"的完整判断。注意区分利用率与饱和度的换算(如 CPU 利用率 80% 时队列可能已很长),错误指标常被忽略但往往是最直接根因。

本题考察排障方法论的系统化应用。回答要点:USE 三问的准确定义与"逐资源"检查流程、常用工具映射、与 RED 方法论的互补关系,体现"方法驱动而非感觉驱动"的排障习惯。

# USE 检查示例:CPU
top -b -n 1 | head -5; vmstat 1 3
# 磁盘
iostat -x 1 3; cat /sys/block/sda/stat
# 网络
sar -n DEV,EDEV 1 3; netstat -s | head -20
#
★★

6. btrace(blktrace 封装)如何跟踪块设备 IO 请求?

btrace/blktrace 如何跟踪块设备 IO 请求?它能回答什么问题,使用中有哪些注意点?

  • blktrace 的事件流与 btrace 封装的用法
  • 追踪内容:请求的生命周期(insert/merge/issue/complete)、队列行为
  • 注意点:blk-mq 下的行为、开销与输出解析(blkparse)

blktrace 是内核块层 IO 追踪工具,通过 block 层的 tracepoint(blk_queue_rq、blk_mq_issue、blk_complete_request 等)记录每个请求在队列、调度、下发、完成各阶段的时序;btrace 是其轻量封装(等价 blktrace -d /dev/sda -o - | blkparse -i -),实时输出请求事件流。它可以回答:IO 请求在块层的排队时长、请求合并(merge)行为、下发与完成延迟分布、IO 模式(顺序/随机、读/写、块大小),并可与 iostat 的队列指标互证,定位"应用提交后卡在哪一层"。

注意点:blk-mq 多队列时代事件字段含义与单队列不同(如 mq 的插桩路径差异),输出字段(major/minor、pid、action、rq 信息)需结合 blkparse 文档解读;生产环境开启 blktrace 有可观开销(每个 IO 事件都要落 trace buffer),应短时采样、按设备过滤(-d 指定盘、-a 按 action 过滤);解析流水线用 blkparse -i trace 汇总统计(如每进程 IO 量、设备利用、深度)。高 IOPS 生产盘不建议长时间开启,改用电站级方案(如 iostat、bpftrace 的块层探针)更安全。结合 debugfs 的 io latency(如 rq_hist)可获得按设备/分区/进程的延迟分布。

本题考察块层 IO 追踪工具链。回答要点:blktrace 的事件流原理与 btrace 用法、能回答的"块层内部时序"问题、blk-mq 差异与生产开销注意点,体现对存储排障工具适用边界的把握。

btrace /dev/sda                     # 实时跟踪 sda 的块层事件
blktrace -d /dev/sda -o /tmp/trace --stopwatch=10
blkparse -i /tmp/trace              # 解析汇总
blkparse -i /tmp/trace -o /tmp/parse.txt
#
★★

7. free -h 输出的内存指标如何解读,可用内存如何估算?

free -h 输出的 total、used、free、shared、buff/cache、available 各字段如何解读?可用内存如何正确估算?

  • 各字段语义与"used"统计口径的误导性
  • available 的估算方式(内核基于回收成本的估计)
  • 与 top、PSI 结合判断真实内存压力

free -h 输出:total 是物理内存总量;used 是"减去 free 与 buff/cache 后的数值"(旧口径),它把大部分页缓存算作已用,容易造成"内存不够"的误判;free 是未被分配的空闲页;shared 是 tmpfs/shared 内存;buff/cache 是页缓存与缓冲区——这部分在压力下可回收,属于"可牺牲"内存;available 是内核估算的"不触发显著交换即可用于新分配的内存",综合考虑可回收缓存与回收成本,是判断内存是否够用的最可靠字段。因此看内存不看 used,而看 available:available 接近 total 说明宽松,available 明显低于需求(如低于 buffer pool 预留)才需关注。

估算与验证:估算可用性时以 available 为准,必要时扣除不可回收部分(如 tmpfs 大小、锁定页 mlock);进一步看压力用 vmstat 的 si/so 与 /proc/pressure/memory 的 full 值,判断是否已进入真实回收;进程视角用 top 按 RES 排序找内存大头、cat /proc/<pid>/smaps 看细分(Rss、Swap、Dirty)。K8s/容器场景注意 cgroup 视角(memory.current/available 与宿主口径不同),防止"宿主 available 充足但容器已限流/OOM"。

本题考察内存指标的正确读法。回答要点:各字段口径、used 的统计陷阱、available 的估算语义及其作为决策依据的地位,并延伸 vmstat/PSI/进程级验证,纠正"看 used 判断内存"的常见错误。

free -h
cat /proc/meminfo | grep -E "MemTotal|MemAvailable|MemFree|Buffers|Cached"
top -o %MEM -b -n 1 | head -15
cat /proc/pressure/memory
#
★★

8. kernel.pid_max 与 fork 失败/无法创建进程的排查中 pid_max 与 threads-max 的关系、容器内 PID 限制与 cgroup pids.max

kernel.pid_max 与无法创建进程(fork 失败)有什么关系?pid_max、threads-max、容器 PID 限制与 cgroup pids.max 如何协同排查?

  • pid_max 与线程数(CLONE_THREAD 共享 pid)的关系、threads-max 的限制
  • fork 失败报错(EAGAIN/Resource temporarily unavailable)的排查链路
  • 容器 cgroup pids.max 与 K8s PID 限制的叠加

kernel.pid_max 是系统 PID 号上限(默认 32768 或按内存自动调整),进程数逼近它时 fork 返回 EAGAIN(Resource temporarily unavailable);注意线程数与 PID 数不同——同一进程的线程共享 PID,但每个线程有独立 TID,仍占用 pid 号空间,因此高并发线程场景(如每连接一线程的服务)pid_max 需调大(如 4194304,与 nr_open 类似量级考虑)。fs.threads-max 是系统级线程总数上限(默认约 memory/8KB),同样导致创建线程失败;更常见的元凶是单进程/容器级限制:ulimit -u(nproc)限制用户进程数、cgroup pids.max(cgroup v2)限制组内任务数,容器环境(K8s pod 默认 pids 限制、kubelet 的 podPidsLimit)叠加后即使宿主 PID 充足,容器内仍可能 fork 失败。

排查链路:确认报错上下文(应用日志 EAGAIN)→ 查看 /proc/sys/kernel/pid_max 与当前 pid 使用(sysctl kernel.pid_maxcat /proc/sys/kernel/pid_max、ps -eLf | wc -l)→ 检查 threads-max、ulimit -u、pids.current/pids.max → 定位是系统、用户还是容器层级。处置:合理提高对应层级上限(调 pid_max 需持久化并评估 PID 表内存)、修复线程泄漏根因、容器场景调 kubelet podPidsLimit 与 cgroup pids.max。内核 4.4+ 默认按内存扩展 pid_max,多数现代机器 pid 空间充足,故"系统 PID 满"在运维中少见,优先查容器与 ulimit 层级。

本题考察进程创建失败的层级化排查。回答要点:pid_max 与线程/pid 空间的关系、threads-max/ulimit -u/cgroup pids.max 的多层限制语义、从系统到容器逐层验证的排查路径,体现"先确认在哪一层受限"的排障思维。

sysctl kernel.pid_max fs.threads-max
ulimit -u
cat /sys/fs/cgroup/<cg>/pids.max /sys/fs/cgroup/<cg>/pids.current
ps -eLf | wc -l                    # 当前线程数
#
★★

9. kernel.shmmax、shmmni、shmall 如何实现共享内存段?

kernel.shmmax、shmmni、shmall 三个参数如何控制系统 V 共享内存?它们在数据库(如 Oracle)部署中的意义是什么?

  • 三个参数语义:单段上限、段数上限、页总数上限
  • SysV IPC 共享内存的使用场景(数据库 SGA、消息队列)
  • 调优依据与查看方式(ipcs)

SysV 共享内存是进程间共享内存的经典机制(shmget/shmat),内核以三个参数限制:kernel.shmmax 是单个共享内存段的最大字节数(现代内核默认 SHMMAX=ULONG_MAX-2^24 字节,64 位下约 16EB,实际部署常按 SGA 需求显式调小至物理内存级别);kernel.shmmni 是系统可创建的共享内存段总数上限(默认 4096);kernel.shmall 是系统共享内存页总数上限(现代内核默认 SHMALL=ULONG_MAX-2^24 页,64 位下极大,实际部署按需调小),三者的乘积约束(段数 × 单段大小)共同决定可用共享内存总量。段被 shmget 创建后挂载进各进程地址空间,通过 shmat 共享,配合信号量(sem)做同步。

数据库意义:Oracle 等传统数据库的 SGA(System Global Area)历史上常直接用 SysV 共享内存(或 mmap 替代),shmmax 过小会导致实例启动时报无法分配共享内存,需要按 SGA 大小调大(如 shmmax 设为 SGA 目标或更大);shmall 过小同样限制总容量;同时 ipc 段泄漏(进程退出未 shmdt/shmctl IPC_RMID)会累积耗尽 shmmni。现代实践:多数数据库改用 mmap 或优化后的共享内存(如 Oracle 现代版本使用 /dev/shm 与大页),SysV 参数主要用于兼容旧应用与 Oracle classic SGA;排障用 ipcs -m 查看段、ipcrm -m <id> 清理孤儿段。

本题考察 SysV IPC 内存参数的配置语义。回答要点:shmmax/shmmni/shmall 分别限制"单段大小、段数量、总页数"、与数据库 SGA 部署的对应关系、ipcs/ipcrm 的运维手段,展示对传统 IPC 机制与现代数据库部署衔接的理解。

sysctl kernel.shmmax kernel.shmmni kernel.shmall
ipcs -m                              # 查看共享内存段
ipcrm -m <shmid>                     # 清理孤儿段
# Oracle 常见配置示例
sysctl -w kernel.shmmax=17179869184  # 16G
sysctl -w kernel.shmall=4194304
#
★★

10. kernel.yama/ptrace_scope 如何实现 ptrace 限制?

kernel.yama.ptrace_scope 如何限制 ptrace 操作?不同取值的语义、对调试与容器的影响是什么?

  • ptrace_scope 的取值语义:0 无限制、1 同祖先可 attach、2 仅 CAP_SYS_PTRACE、3 禁止并锁定
  • 对 gdb/strace 调试与容器运行的影响
  • 运维调整与安全权衡

kernel.yama.ptrace_scope 是 Yama LSM 提供的 ptrace 访问控制,默认 1:仅允许进程 attach 到其直接祖先或同父兄弟进程,防止普通用户通过 ptrace 调试/注入其他用户进程(传统保护是 root 属主与 dumpable 标志,scope 在此基础上加了基于血缘的约束)。取值:0 完全禁用 Yama 限制(任何同 uid 进程可被 ptrace);1(默认)仅同祖先;2 仅允许 root 或有 CAP_SYS_PTRACE 者;3 完全禁止 ptrace 并拒绝通过 sysctl 再降级(需重启解除),适合强审计环境。

影响:取值 1 时 gdb/strace 调试自己启动的子进程正常(父-子关系),但"attach 到已运行的无关进程"会失败(报 Operation not permitted),需用 root 或临时调 0;容器场景,容器内进程对宿主进程无血缘,scope 提供宿主与容器间的调试隔离(结合容器 runtime 默认配置),但容器内调试自身进程组内的进程不受影响;取值 2/3 会破坏依赖 ptrace 的调试器、部分调试工具与 tracing 工具(如旧版 bpftrace 用 ptrace 注入时)。运维建议:默认保持 1,需要跨进程调试时临时 sysctl -w kernel.yama.ptrace_scope=0 并在调试后恢复;安全审计要求高的环境可设 2,设置前评估调试与监控工具兼容性。

本题考察 ptrace 安全控制的层级语义。回答要点:四个取值的行为差异、默认 1 的"血缘限制"对调试工具的影响、容器与安全审计场景的取舍,体现"安全限制与调试便利"的平衡判断。

sysctl kernel.yama.ptrace_scope
sysctl -w kernel.yama.ptrace_scope=0   # 临时放开(调试后恢复)
# 验证:gdb attach 非子进程是否被拒
gdb -p <pid>                           # 可能报 Operation not permitted
#
★★

11. load average 高但 CPU 空闲(D 态/IO 等待)的分析路径

load average 很高但 CPU 显示空闲时,问题可能出在哪里?D 态进程与 IO 等待的分析路径是什么?

  • load average 的统计对象:运行态 + 不可中断睡眠(D 态)任务
  • D 态来源:磁盘/NFS/锁等待等不可中断内核路径
  • 分析路径:ps 查 D 态、iostat/进程 IO、栈(/proc//stack、wchan)

load average 统计的是"可运行任务数 + 不可中断睡眠任务数",因此 D 态(不可中断睡眠,常见于等待磁盘 IO、NFS 网络 IO、内核锁、内存回收等路径)任务堆积时,load 飙升但 CPU 利用率可能很低。分析路径:先用 top -b -n 1 看 load 与 wa,再用 ps -eo state,pid,comm | awk '$1=="D"'(或 ps aux | awk '$8 ~ /D/')找出 D 态进程;确认后进一步定位等待对象:iostat -x 看磁盘 util/await 判断是否磁盘饱和,cat /proc/<pid>/stack/proc/<pid>/wchan 看阻塞在内核哪个函数(如 wait_on_page_bit 是页面 IO、nfs 相关函数是网络文件系统、mutex 是锁等待),配合 dmesg 排除硬件错误(磁盘介质错误、光纤断连)。NFS/网络盘挂载点失联是 D 态高发的常见场景(NFS 服务端故障导致客户端进程 D 态堆积)。

处置方向:定位到资源后处理根因(磁盘故障换盘/限流、NFS 恢复或切换、卸载失联挂载点),D 态进程无法用 kill 直接杀掉(不可中断),只能等内核路径返回或重启;批量 D 态还可能是内存回收风暴(PSI memory full)或并发 IO 过载。注意区分 load 高 + CPU 忙(真 CPU 瓶颈)与 load 高 + CPU 闲(D 态/IO/锁)两类形态,处理方式截然不同。

本题考察 load 与 CPU 解耦的经典场景。回答要点:load 的统计口径包含 D 态、D 态来源枚举、从 ps→iostat→/proc/stack→dmesg 的逐层定位路径、以及"不可中断不可强杀"的处理边界,体现对负载语义的准确理解。

ps -eo pid,state,wchan:32,comm | awk '$2=="D"'
cat /proc/<pid>/stack; cat /proc/<pid>/wchan
iostat -x 1 5
dmesg -T | tail -50
mount | grep nfs
#
★★

12. net.core.somaxconn 与 tcp_max_syn_backlog 溢出导致的连接建立失败(connection reset)如何用 ss 与 netstat 定位

net.core.somaxconn 与 tcp_max_syn_backlog 溢出如何导致连接建立失败?如何用 ss 与 netstat 定位是哪个队列溢出?

  • accept 队列(somaxconn)与 SYN 队列(tcp_max_syn_backlog)的溢出表现差异
  • connection reset/超时的不同路径(SYN cookie、全连接队列满)
  • ss 与 netstat 的定位手段(Send-Q、Recv-Q、dropped 计数)

服务器侧两个队列都可能让客户端连接失败:SYN 队列(半连接队列,上限 tcp_max_syn_backlog)满时,新 SYN 被丢弃或触发 SYN cookie,客户端表现为连接建立慢、SYN 重传后超时;accept 队列(全连接队列,上限取 min(backlog, net.core.somaxconn),somaxconn 默认 4096)满时,内核按 tcp_abort_on_overflow 决定行为——默认不主动 abort,但客户端重传的 ACK 得不到服务端响应,或队列溢出后新完成握手被丢弃,客户端常见"connection reset by peer"或偶发超时,Nginx/Java 高并发场景频发。两队列同时受限的还有 fd 与单进程并发能力,需组合排查。

定位手段:ss -lnt 看监听端口的 Recv-Q(已就绪待 accept 的连接数,满则等于 backlog)与 Send-Q(backlog 配置值),Recv-Q 持续顶满即 accept 队列溢出;netstat -s 的 "times the listen queue of a socket overflowed"(ListenOverflows)与 "SYNs to LISTEN sockets dropped" 计数分别指认 accept 队列与 SYN 队列溢出;再结合 ss -lnt state syn-recv 看半连接堆积。处置:调大应用 backlog 与 somaxconn(如 65535)、开启 tcp_abort_on_overflow=1 让溢出时显式 reset 以暴露问题、优化 accept 循环(事件驱动、多 worker)、必要时加负载均衡分摊。修改后验证 ListenOverflows 归零。

本题考察连接建立失败的两队列根因定位。回答要点:两队列溢出各自的客户端表现、ss 的 Recv-Q/Send-Q 与 netstat 两类计数两个定位抓手、以及"队列上限+应用 accept 能力+负载分摊"的处置组合,体现对握手队列的实战排查能力。

ss -lnt | head -20                    # Recv-Q/Send-Q 观察监听队列
netstat -s | grep -iE "listen queue|SYNs to LISTEN"
sysctl net.core.somaxconn
sysctl -w net.core.somaxconn=65535
sysctl -w net.ipv4.tcp_abort_on_overflow=1
#
★★

13. net.netfilter.nf_conntrack_buckets 如何实现 hash 桶数?

net.netfilter.nf_conntrack_buckets 的作用是什么?conntrack 表满会导致什么问题,如何调优与观测?

  • nf_conntrack 机制与 hash 桶结构(buckets × 链长)
  • 表满表现:新连接被 drop、丢包、NAT 异常
  • 调优:nf_conntrack_max/buckets 的估算与观测(/proc/sys/net/netfilter、conntrack 计数)

net.netfilter.nf_conntrack_buckets 是连接跟踪(conntrack)hash 表桶数,内核按 nf_conntrack_max / nf_conntrack_buckets 控制每条链的期望长度(通常 4-8)。conntrack 记录每条通过的状态连接(含 NAT 映射、跟踪状态),默认 nf_conntrack_max 通常为 65536(或按内存自动计算),满载后新连接因无法分配跟踪条目而被静默丢弃,表现为:高并发下新建连接失败/超时、NAT 场景流量异常、dmesg 报 "nf_conntrack: table full, dropping packet"。此外桶数过小导致 hash 冲突严重时,查找与插入 CPU 开销上升(softirq 升高)。

调优与观测:估算公式——生产峰值并发连接数(如 ss -s 的 established 峰值、NAT 网关按内网主机 × 每机连接数)确定 nf_conntrack_max,再按期望链长设定 buckets(如 max=1048576、buckets=262144,链长 4);注意 conntrack 条目与 hash 表内存占用(每条约 300-400B,含时序),超大表需评估内存;观测用 cat /proc/sys/net/netfilter/nf_conntrack_count 与 max 对比、conntrack -L 查看条目、conntrack -S 看统计(insert_failed 即失败数)。Docker/K8s 环境普遍调大 conntrack(默认偏小),配合清理超时(tcp/timeouts)防止无效条目堆积。修改持久化到 /etc/sysctl.d。

本题考察连接跟踪表的结构与容量治理。回答要点:hash 桶结构(buckets×链长)、表满的丢包表现与 dmesg 特征、按并发估算 max/buckets 的方法、count/insert_failed 观测手段,体现对 NAT 与容器网络核心组件的容量管理能力。

sysctl net.netfilter.nf_conntrack_max net.netfilter.nf_conntrack_buckets
cat /proc/sys/net/netfilter/nf_conntrack_count
conntrack -S | grep -E "insert_failed|found"
# 调优示例
sysctl -w net.netfilter.nf_conntrack_max=1048576
sysctl -w net.netfilter.nf_conntrack_buckets=262144
#
★★

14. ps auxf 如何以进程树形式查看进程父子关系?

ps auxf 如何以进程树形式查看进程父子关系?它的输出结构与其他 ps 用法有何区别,排障中如何利用?

  • ps auxf 的森林结构(f 选项)与 PPID 关系
  • 与 ps -ef --forest、pstree 的等价与差异
  • 排障价值:定位孤儿进程、确认服务启动链条

ps auxf 在 ps aux(全格式)基础上加 f 选项,以 ASCII 树形展示进程层级:首列由进程名变为"缩进 + 树状分支"结构,子进程挂在父进程下方,直观呈现进程的启动链条与从属关系;等价命令还有 ps -ef --forest(--forest 显式开启树形)、pstree -p(更精简的树)。树形视图的价值:确认服务的启动路径(systemd → 中间进程 → worker 池的完整链路)、排查孤儿进程(被父进程遗弃后挂在 init/systemd 下的进程)、发现异常派生(被挖矿/病毒进程挂载的子树)与僵尸进程层级。

排障中配合使用:ps -o pid,ppid,stat,cmd 精确核对父子 PID;用 pgrep -P <pid> 查直接子进程;结合 /proc/<pid>/stat 的 PPID 与 /proc/<pid>/status 的 PPid 字段做程序化确认;定位容器内外进程关系时注意 pid namespace 隔离(宿主视角树与容器内不同)。注意 auxf 的树形以终端宽度截断,长命令行用 ps auxf | cut -c1-200 或改 ps -ef --forest 排版。

本题考察进程树视角的排障工具。回答要点:f/--forest 的树形输出语义、与 pstree/PPID 字段的配合、在孤儿进程与异常派生排查中的价值,并提示 pid namespace 的视角差异,体现对进程模型的完整把握。

ps auxf | head -50
ps -ef --forest
pstree -ap | head -50
pgrep -P <pid>                # 列出直接子进程
cat /proc/<pid>/status | grep PPid
#
★★

15. vm.overcommit_memory 三种模式与 malloc 大内存申请的关系,以及 overcommit 导致进程被 OOM 的排查

vm.overcommit_memory 的三种模式分别如何影响内存申请?overcommit 与进程被 OOM 的关联及排查路径是什么?

  • 三种模式:0 启发式、1 永远允许、2 严格禁止(overcommit_ratio)
  • malloc 的乐观分配与"用到才真实占用"导致的 OOM
  • 排查:内存分配成功后崩溃、dmesg OOM、cgroup 与系统层 OOM 的区别

vm.overcommit_memory 控制内核是否允许"超卖"内存:0(默认)启发式——根据映射类型(共享可写/私有)粗略判断,允许合理超卖;1 总是允许(任何 malloc 都成功,适合科学计算等内存密集场景,风险是进程可能集体 OOM);2 严格模式——按 overcommit_ratio(默认 50%)计算可承诺额度 = swap + ram × ratio,超过则 malloc/mmap 直接失败(返回 NULL 或 ENOMEM),把"超卖风险"前置为"分配失败"。由于 Linux 的 malloc 是乐观分配(写时才真正占用物理页),模式 0/1 下大内存申请往往成功,直到进程实际触达物理内存上限才被 OOM Killer 击杀,表现为"申请成功、运行到高峰突然被杀"。

排查路径:确认是"分配失败"(模式 2 的 ENOMEM、应用报 Cannot allocate memory)还是"运行期被杀"(dmesg 的 Out of memory: Killed process + oom_score 信息,或容器 cgroup OOM 事件);前者查 overcommit_memory/ratio 与 ulimit -v、实际可用内存(available);后者用 /proc/<pid>/oom_score_adj 保护关键进程、查看 cat /proc/<pid>/status 的 VmPeak 确认峰值、配合 PSI/swap 判断是否内存不足而非配置错误。处置:模式 2 下按真实需求调整 ratio 或改回 0 并靠监控兜底;模式 0/1 下优化内存占用(缓存、GC、泄漏)并设置进程优先级,避免误杀。注意 cgroup v2 的 memory.max 在容器内优先于系统级 OOM。

本题考察内存超卖机制的完整链路。回答要点:三种模式的承诺语义、乐观分配导致"申请成功被杀"的因果链、分配失败(ENOMEM)与运行期 OOM 两条排查路径的区分,体现对虚拟内存与实际占用关系的准确理解。

sysctl vm.overcommit_memory vm.overcommit_ratio
cat /proc/meminfo | grep -i commit
dmesg -T | grep -i "Out of memory"
cat /proc/<pid>/oom_score_adj /proc/<pid>/status | grep -E "VmPeak|VmRSS"
#
★★

16. 磁盘 IO 调度器(mq-deadline/none/bfq)在 NVMe 与机械盘场景的选型依据与验证方法

mq-deadline、none、bfq 三种 IO 调度器分别在什么场景选型?NVMe 与机械盘的差异如何影响选择,如何验证?

  • 调度器语义:none(无调度)、mq-deadline(截止时间排序)、bfq(公平带宽)
  • NVMe 与机械盘的队列特性差异(多队列、寻道成本)
  • 选型依据与验证方法(fio 对照、iostat 观察)

Linux 块层调度器决定请求下发顺序:none 不做调度(请求按提交顺序直接下发,交由设备自身队列处理),适合 NVMe/SSD——设备内部队列深、寻道代价低,调度器收益小且增加开销,因此 RHEL 8 等发行版对 NVMe 默认 none;mq-deadline 按截止时间合并排序(读优先、限时),对机械盘等"服务时间差异大"的设备有意义,通过减少寻道与保证读延迟换取整体吞吐;bfq 按进程公平分配带宽,追求低延迟与公平性(适合桌面/多租户共享盘),但 CPU 开销较高。选型依据:机械盘(旋转介质,寻道是主要成本)用 mq-deadline 或 bfq(多租户公平场景);SSD/NVMe 用 none;混合场景按设备分别设置(如系统盘 none、数据盘 deadline)。

验证方法:用 fio 做对照基准(readwrite=randrw、bs=4k/1m、iodepth 组合),对比不同调度器下的 IOPS、吞吐与 P99 延迟(fio 的 clat 分布);运行期用 iostat -x 观察 util/await/aqu-sz 与延迟曲线;机械盘场景关注 seek 行为(如 iostat 的 svctm 与工具如 blktrace 的请求分布)。切换方式:运行时可写 /sys/block//queue/scheduler 即时切换(IO 在途请求会受轻微影响,生产谨慎),持久化用 udev 规则或内核参数 elevator=。注意内核 5.0+ 多队列统一后,none 在部分场景下等同于直通,调度器选择更多是"特性取舍"而非"性能神话"。

本题考察块层调度器的选型工程。回答要点:三种调度器的机制差异与典型适用盘型、NVMe"无需调度"与机械盘"需要排序"的本质原因、用 fio/iostat 做对照验证的方法,体现基于存储介质特性的决策而非跟风。

cat /sys/block/sda/queue/scheduler        # 查看当前调度器
echo none > /sys/block/sda/queue/scheduler
fio --name=test --filename=/dev/sdb --rw=randrw --bs=4k --iodepth=64 --numjobs=4 --runtime=60
iostat -x 1
#

17. cat /proc//clear_refs 如何重置页表引用位以测量进程内存使用?

/proc//clear_refs 如何重置进程页表引用位?它在测量进程真实内存使用中的原理与用法是什么?

  • clear_refs 的写入语义(1/2/3 分别清除引用位/软脏位等)
  • 结合 smaps/smaps_rollup 测量"一段时间内被访问的页"
  • 用途:识别驻留但长期未用的内存(候选回收/优化对象)

/proc/ /clear_refs 用于重置进程页表/页面的引用位(accessed bit)与软脏位,写入不同值控制清除范围:1 清除所有页的引用位(含匿名页与文件页),2 仅清除匿名页引用位,3 清除软脏位(soft-dirty,配合 /proc/kpageflags 可用于增量追踪)。原理:页面被访问时硬件会置位 accessed 位,内核周期性(或按配置)扫描;先 clear_refs 清零,等待一段时间后读取 /proc//smaps 的 Referenced 字段(或 smaps_rollup 汇总),即可得知该时段内实际被访问的页面数量与占比——未被置位的页即为"驻留但未被触碰"的内存。

应用场景:判断进程内存是否"虚高"——如加载了大量文件映射但只用了少部分、缓存类进程的冷数据占比;结合测量结果决定优化方向(减少预加载、调低 buffer pool、增加 swap 倾向);也可用于容量评估(实际工作集 vs RSS)。注意:clear_refs 需要与目标进程相同权限(root 或同 uid),对内核线程/其他用户进程写入会失败;测量窗口要避开业务高峰的偏差,多次测量取稳定值;现代内核推荐结合 cgroup v2 的 memory.stat 的 inactive/active 字段与 PSI 更宏观地评估。引用位清除对性能影响极小,但频繁操作仍建议短时使用。

本题考察进程级内存工作集的测量技巧。回答要点:clear_refs 的清除语义与 smaps Referenced 的配合测量原理、"驻留未用页"的识别价值、权限与窗口等使用注意点,体现对内存页生命周期机制的实操理解。

echo 1 > /proc/<pid>/clear_refs
sleep 300
grep -E "Referenced|Rss" /proc/<pid>/smaps_rollup
awk '/Referenced/ {sum+=$2} END {print sum/1024 " KB"}' /proc/<pid>/smaps
#

18. cat /proc//io 如何查看进程的 IO 统计?

/proc//io 中的字段如何解读?如何用它排查"哪个进程在大量写盘"?

  • 字段语义:rchar/wchar 与 read_bytes/write_bytes 的区别(逻辑 vs 物理)
  • 与 pidstat -d、iotop 的关系
  • 排查流程:定位进程 → 确认写路径

/proc//io 提供进程级 IO 统计:rchar/wchar 是进程通过 read/write 系统调用请求的逻辑读写字节数(含缓存命中,反映应用 IO 意图);read_bytes/write_bytes 是真正落到块设备的物理读写字节数(页面缓存命中不算,反映磁盘流量);syscr/syscw 是读写系统调用次数。四个字段的组合能区分"应用层频繁读写"与"实际磁盘压力":如 wchar 巨大但 write_bytes 很小,说明写被页缓存吸收(延迟写);反之 write_bytes 大说明缓存回写压力大。

排查"谁在写盘"的流程:先 iostat 确认设备忙,再 pidstat -d 1(按进程实时列读写)或 iotop -o(只显示有 IO 的进程)抓取;深入时读 /proc/ /io 观察 write_bytes 增长速率,配合 lsof 或 /proc/ /fd 与 /proc//mountinfo 确认写入的具体文件与挂载点,必要时用 strace 或 audit 记录 open/write 路径。注意:多线程进程的 IO 统计按进程聚合;delayed 字段(cgroup 支持时)表示因限流被延迟的量。容器场景用 cgroup io.stat 看组级 IO 更准确。

本题考察进程级 IO 观测的字段语义。回答要点:逻辑 IO(rchar/wchar)与物理 IO(read/write_bytes)的本质区别及其组合判读、pidstat/iotop 的抓取流程与 /proc 下钻、与 cgroup io.stat 的容器视角衔接,体现 IO 排障的进程定位能力。

cat /proc/<pid>/io
pidstat -d 1                      # 进程级 IO 实时统计
iotop -o -b -n 3
ls -l /proc/<pid>/fd | head        # 查看打开的文件的写入目标
cat /sys/fs/cgroup/<cg>/io.stat    # 容器级 IO 统计
#

19. cat /proc//oom_score_adj 如何调整进程的 OOM 优先级?

/proc//oom_score_adj 如何调整进程的 OOM 被选优先级?取值语义、生效条件与生产使用场景是什么?

  • oom_score_adj 的取值范围(-1000 到 1000)与 oom_score 的关系
  • -1000 的豁免语义与权限要求
  • 使用场景:保护数据库、标记可牺牲进程、cgroup oom.group

内核 OOM Killer 按 oom_score 挑选被杀进程:oom_score 由进程内存占用(RSS/swap、页表等)与 oom_score_adj 共同计算,oom_score_adj 取值范围 -1000 到 1000,正值提高被选概率(内存大户 + adj 高者优先被杀),负值降低概率,-1000(OOM_SCORE_ADJ_MIN)表示该进程"对 OOM Killer 免疫",不会被选中。写入 -1000 需要特权(root 或 CAP_SYS_RESOURCE),普通用户只能在不提高自身优先级范围内调整。调整立即生效,读 /proc//oom_score 可看当前得分、oom_score_adj 看配置值。

生产使用场景:数据库、消息中间件等关键进程设 oom_score_adj=-1000(或按 cgroup 统一设置,cgroup v2 的 memory.oom.group 可整组处理),防止内存压力时核心服务被误杀;监控/批处理等可牺牲任务设正值,让内核优先杀它们;系统服务(如 sshd)设负值保活。注意:-1000 只豁免 OOM Killer 选择,不阻止进程自身崩溃或 cgroup 级 OOM(容器内 memory.max 触发的 OOM 优先在 cgroup 内选择,宿主级 OOM 才考虑 adj);豁免过多关键进程会导致 OOM 时无"可杀对象"而触发内核 panic(panic_on_oom=2 场景),需平衡豁免范围。临时保护也可用 systemd 的 OOMScoreAdjust 指令声明。

本题考察 OOM 选择机制的可控性。回答要点:adj 与 score 的计算关系、-1000 豁免的权限与生效边界(宿主 OOM 层面)、关键服务保护与可牺牲进程标记的使用场景、以及豁免过多导致 panic 的副作用,体现对 OOM 治理的精细操作。

echo -1000 > /proc/<pid>/oom_score_adj
cat /proc/<pid>/oom_score /proc/<pid>/oom_score_adj
# systemd 声明
[Service]
OOMScoreAdjust=-1000
#

20. cat /proc/cpuinfo 如何查看 CPU 型号、核数与特性?

/proc/cpuinfo 中的字段如何解读?如何从中获得 CPU 型号、物理核数、逻辑核数与特性(flags)?

  • 关键字段:model name、physical id、core id、cpu cores、processor、flags
  • 物理核/逻辑核/超线程的计算方法
  • flags 与特性判断(如 avx2、sse4、aes)及与 nproc/lscpu 的关系

/proc/cpuinfo 按逻辑 CPU 逐段列出信息:model name 是型号(如 Intel(R) Xeon(R) Gold 6230R);每个逻辑 CPU 一段,processor 是逻辑 CPU 编号;physical id 标识物理 CPU 插槽,core id 标识物理核,cpu cores 是每个物理 CPU 的核数。物理核数 = cpu cores 总和(按 physical id 去重);逻辑核数 = processor 条目数;超线程开启时逻辑核数 = 物理核数 × 每核线程数(siblings 字段)。flags 列出 CPU 特性(如 avx2、sse4_2、aes、ssse3、vme、hypervisor 表示虚拟机),用于判断向量化/加密指令支持,指导编译参数与软件特性开关。

使用注意:直接用 nprocnproc --all 看逻辑核数(注意 cgroup 与 taskset 限制下 nproc 会受亲和性影响),lscpu 输出结构化摘要(型号、架构、Socket/核/线程数、NUMA 节点、flags 概要)更易读;统计时 grep -c ^processor /proc/cpuinfo 是经典计数;容器内 /proc/cpuinfo 反映宿主 CPU(数量可能受限),程序化判断应用 lscpu -p 或 cpuinfo 脚本。特性判断影响部署:如依赖 avx2 的向量数据库需先确认 flags 包含 avx2。

本题考察 CPU 信息读取的基础能力。回答要点:关键字段与物理/逻辑核的换算方法、flags 与特性判断的用途、nproc/lscpu/cpuinfo 三者的关系与容器视角差异,体现对硬件信息的准确解读。

grep -E "model name|physical id|core id|cpu cores|siblings" /proc/cpuinfo | sort -u
grep -c ^processor /proc/cpuinfo          # 逻辑核数
lscpu                                      # 结构化摘要
grep -o "avx2\|aes\|ssse3" /proc/cpuinfo | sort -u
#

21. cat /proc/meminfo 如何查看内存的详细统计?

/proc/meminfo 中关键字段如何解读?如何用它做内存状态的深度诊断?

  • 核心字段:MemTotal/MemFree/MemAvailable、Buffers/Cached、SwapTotal/SwapFree、Committed_AS、HugePages
  • MemAvailable 的估算逻辑与 Cached 的可回收性
  • 诊断应用:确认 swap 用量、判断内存压力与提交承诺

/proc/meminfo 是内存统计的事实来源:MemTotal/MemFree 是总量与未分配量;MemAvailable 是内核估算的可分配内存(MemFree + 可回收缓存,并扣除回收成本与保留量),比 MemFree 更真实;Buffers 是块设备缓冲、Cached 是页缓存(文件缓存,压力下可回收,含 tmpfs 一部分为不可回收);SwapTotal/SwapFree 是交换分区容量与剩余;Committed_AS 是内核"已承诺"的虚拟内存总量(与 overcommit 模式联动,可对比 CommitLimit);HugePages_Total/Free 是大页池;Slab 是内核对象缓存;KReclaimable 是可回收 slab。内存压力场景看 MemAvailable 持续走低、SwapFree 快速消耗、以及 PSI memory。

深度诊断套路:先用 MemAvailable 判断总量是否够;再拆"谁占用"——进程 RSS(top 按 %MEM、ps aux --sort=-rss)+ 页缓存(Cached,必要时看 /proc/meminfo 的 Dirty 与 Writeback 判断回写压力)+ Slab/内核缓存(排查内核对象泄漏,如 dentry/inode 可通过 slabtop 看);swap 用量大时看 si/so 与 vm.swappiness 是否合理;Committed_AS 超 CommitLimit 提示 overcommit 模式 2 下可能分配失败。结合 free -h、vmstat、smem 交叉验证,形成"总量-分布-压力"三层诊断。

本题考察内存统计文件的深度解读。回答要点:各字段语义(尤其 MemAvailable 与 Cached 可回收性)、按"总量-分布-压力"三层诊断的方法、与 swap/overcommit 的联动判断,体现从原始内核数据做内存审计的能力。

cat /proc/meminfo | head -30
grep -E "MemAvailable|CommitLimit|Committed_AS|Dirty|Writeback" /proc/meminfo
smem -t -k | head -15                 # 按比例展示内存占用
slabtop -o | head -20