跳转到内容

Linux 性能分析与故障排查面试题

14 道题
分类
Linux
题目数
14 道
已阅读 0 / 14 题
1 top / vmstat / iostat / perf / strace / bpftrace 等性能分析工具有什么区别?如何选用?

答案:

第一梯队:全局性能快照

  • top / htop:实时进程级 CPU、内存、负载信息;/proc/<pid>/stat 数据聚合;快速定位可疑进程。
  • vmstat 1:系统级 CPU(us/sy/wa/id)、内存(si/so)、IO(bi/bo)、系统调用(in/cs)、上下文切换(cs)每秒采样;r 列持续 > CPU 核心数表示 CPU 饱和。
  • iostat -dx 1:块设备层 IOPS、await、svctm、%util%util ≠ IO 饱和度(高 IO 队列时可能 100% 但仍有性能),更应看 aqu-szrareq-sz
  • mpstat -P ALL 1:每核 CPU 分布,识别单核热点(常见于锁竞争)。
  • sar -n DEV 1:网卡 PPS / 带宽,定位丢包(rxdrop/stxdrop/s)。

第二梯队:进程级深挖

  • perf top / perf record -g:基于硬件性能计数器(PMU)的采样 profiler;定位 CPU 热点函数、内核热点。
  • strace -p <pid> / strace -c -p <pid>:跟踪进程系统调用与信号;诊断进程卡在内核哪一步(如 futexepoll_wait)。
  • ltrace:跟踪库函数调用。

第三梯队:高级内核分析

  • bpftrace(eBPF):动态追踪,跟踪任意内核/用户态函数 + 上下文;如 bpftrace -e 'kprobe:do_sys_open { printf("%s\n", comm); }'
  • perf trace:类似 strace 但基于 eBPF,性能开销极低。
  • ftrace:内核函数跟踪器,轻量。
  • systemtap:类 DTrace 内核分析工具,脚本化。

选用决策树:

系统慢 → top/vmstat/mpstat/iostat/sar  → 找到瓶颈维度
  ├─ CPU 热点 → perf top / bpftrace
  ├─ IO 等待 → iostat / blktrace / bpftrace biolatency
  ├─ 网络丢包 → sar -n / nicstat / tcpdump
  └─ 进程卡顿 → strace / perf trace
2 cgroups 与 namespace 的作用分别是什么?容器是如何利用两者实现资源隔离的?

答案:

namespace(命名空间)—— 资源视图隔离:

  • 提供进程视角的资源视图隔离,使进程组看不到其他进程组的资源。
  • 8 种 namespace:mount、UTS、IPC、PID、network、user、cgroup(v4.6+)、time(v5.6+)。
  • 系统调用:clone(CLONE_NEWNS | CLONE_NEWPID | ...)unshare()
  • PID namespace 实现 PID 重新编号(容器内 PID 1)、network namespace 提供独立网络栈(veth pair 连接)、mount namespace 提供独立文件系统视图。

cgroups(Control Groups,cgroup v2 推荐)—— 资源限制与统计:

  • 提供 CPU、内存、IO、网络、进程数等资源的限额、统计、优先级控制。
  • 层级结构:/sys/fs/cgroup/<subsystem>/<cgroup-path>/
  • cgroup v2 统一接口、引入 memory.high(软限制触发回收)、memory.max(硬限制触发 OOM)、io.max(BFQ/io.weight)。
  • 关键控制器:
    • cpu.maxquota period(如 100000 100000 即 1 核)。
    • memory.max:硬限制。
    • io.maxmajor:minor rbps=10485760 wbps=10485760
    • pids.max:进程数限制。

容器实现:

// 容器进程伪代码
unshare(CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWNET | CLONE_NEWUTS);
mount("proc", "/proc", "proc", 0, NULL);
write_cgroup("memory.max", "536870912");
execvp(argv[0], argv);

OCI 运行时(runc / crun) 串联 namespace + cgroup + seccomp + capabilities + AppArmor/SELinux 形成完整容器边界。Docker、containerd、Kubernetes 容器均基于此实现。

3 SELinux / AppArmor / capabilities 三种安全机制有何区别?生产环境如何选用?

答案:

SELinux(Security-Enhanced Linux,NSA + Red Hat 主导):

  • 基于**标签(label)**的强制访问控制(MAC):每个文件、进程、端口都有安全上下文(user:role:type:sensitivity),策略定义 type 间的访问规则。
  • 策略语言:M4 宏 + 模块化策略。
  • 工作模式:enforcing(强制执行)、permissive(仅告警)、disabled(关闭)。
  • 优势:粒度极细,RHEL/CentOS 默认开启;劣势:策略复杂、配置学习成本高。

AppArmor(Canonical/Ubuntu 主导):

  • 基于混合模型(路径 + capability + 网络能力),配置文件以 #include <tunables/global> 开头,规则示例:/usr/sbin/nginx { file read, network inet stream, capability net_bind_service; }
  • 优势:易上手、路径化、与 Docker 默认集成(docker-default profile);劣势:粒度不如 SELinux。

capabilities(Linux capabilities):

  • 将 root 权限拆分为 40+ 个细粒度能力CAP_NET_ADMINCAP_SYS_ADMINCAP_NET_BIND_SERVICECAP_DAC_OVERRIDE 等)。
  • 替代方案:传统 SUID root(粗糙),用 capabilities 让进程仅拥有必要权限。
  • 容器默认丢弃大量 capabilities(Docker --cap-drop=ALL --cap-add=NET_BIND_SERVICE)。

对比:

维度SELinuxAppArmorcapabilities
模型标签 (TE/RBAC)路径能力位
复杂度
粒度极细粗(仅 root 操作类)
集成RHEL 系Ubuntu / SUSE全平台

生产建议:

  • RHEL / CentOS 保持 SELinux enforcing,重要业务进程开发自定义 .te 模块。
  • Ubuntu / Debian 使用 AppArmor profile,关键服务定制 profile。
  • 容器所有 capabilities 丢弃后按需添加--cap-drop=ALL --cap-add=NET_BIND_SERVICE),同时启用 seccomp 默认 profile。
4 dmesg / journalctl / core dump 各自的用途是什么?生产环境如何进行系统性故障排查?

答案:

dmesg(内核环形缓冲区)—— 内核事件:

  • 记录内核启动日志、硬件探测、Oops/Panic、内核模块加载、磁盘错误、内存硬件错误(mce)等。
  • dmesg -T 显示人类可读时间;dmesg -l err,warn 按级别过滤。
  • 生产关键场景:磁盘 IO 错误(ata1: soft reset failed)、OOM Killer 记录(Out of memory: Killed process)、硬件故障(mce: [Hardware Error])。

journalctl(systemd 日志)—— 系统服务日志:

  • 替代传统 syslog,统一收集内核、systemd、服务、审计日志,按服务、优先级、时间、进程 PID 过滤。

  • 持久化配置:/etc/systemd/journald.confStorage=persistent

  • 常用命令:

    journalctl -u nginx --since "1 hour ago"
    journalctl -p err -b        # 当前启动的错误日志
    journalctl _PID=1234        # 按 PID 过滤
    journalctl -k               # 仅内核日志(等同 dmesg)
    journalctl --vacuum-time=7d # 清理 7 天前日志
    

**core dump(核心转储)—— 进程崩溃快照:**

- 进程崩溃(SIGSEGV、SIGABRT、SIGBUS)时将**内存、寄存器、栈**写入文件,便于事后分析。
- 配置 `coredumpctl`(systemd-coredump)集中管理。

  ```bash
  echo '/tmp/core.%e.%p' > /proc/sys/kernel/core_pattern
  ulimit -c unlimited
  # 启用 systemd-coredump
  systemctl enable systemd-coredump.socket
  • 分析工具:gdb <binary> <core-file>coredumpctl gdb

系统性故障排查流程:

1. 现象确认 → 监控/告警/用户反馈
2. 时间点定位 → 关联监控指标(Prometheus)、日志时间戳
3. dmesg 优先 → 硬件/内核问题(OOM、disk error、mce、kernel panic)
4. journalctl 服务日志 → 应用层异常(启动失败、配置错误)
5. 进程状态 → strace / gdb / /proc/<pid>/status
6. 资源使用 → vmstat / iostat / mpstat / perf / bpftrace
7. 网络层 → ss / netstat / tcpdump / nicstat
8. 根因定位 → 横向对比(正常 vs 异常)、纵向时间线(何时开始变化)
9. 修复 → 规避 → 复盘 → 文档

关键命令速查:

ss -s              # 套接字统计
lsof -p <pid>      # 进程打开文件
strace -p <pid>    # 进程系统调用
perf top -g        # 实时热点函数
bpftrace -e 'tracepoint:syscalls:sys_enter_* { @[comm] = count(); }'

生产铁律:

  • 所有节点开启 kernel.panic=10 自动重启、kdump 保留内核崩溃现场。
  • journald 日志集中收集(ELK / Loki)+ 监控告警(log_level=error 即触发)。
  • 关键进程开启 core dump,按需转储不滥用磁盘。
5 Linux 系统启动流程详解:BIOS→GRUB→内核→initramfs→systemd 各阶段发生了什么?

答案:

理解启动流程是排障"卡启动"问题的前提。

完整启动流程:

flowchart TD
    S1["1. 硬件上电(Power On)
CPU 从 reset vector 跳到固件入口"] S2["2. 固件阶段(BIOS/UEFI)
POST → 硬件自检
BIOS: MBR 模式加载 446 字节引导程序
UEFI: ESP 分区读取 EFI 应用(grubx64.efi)
加载 ACPI 表、SMBIOS 信息"] S3["3. 引导加载器(GRUB2)
/boot/grub/grub.cfg → 内核 + initramfs 路径
显示菜单 → 加载 vmlinuz 到内存
加载 initramfs(cpio 归档,临时根文件系统)"] S4["4. 内核自解压 + 启动
start_kernel() → setup_arch() → mm_init()
初始化调度器、内存管理、rootfs
挂载 initramfs 作为临时根
启动 init 进程(PID 1)→ 执行 /init"] S5["5. initramfs 阶段(早期用户空间)
/init 脚本(dracut 生成的 systemd)
加载内核模块(lvm/dm/fs/storage 驱动)
组装 RAID / 解密 LUKS / 激活 LVM VG
挂载真实根到 /sysroot → switch_root"] S6["6. systemd 阶段(PID 1)
加载 unit 配置(/etc/systemd、/usr/lib)
解析依赖图 → 并行启动 unit
激活 default.target(graphical/multi-user)
getty → login → 用户登录"] S1 --> S2 --> S3 --> S4 --> S5 --> S6

每个阶段的排障方法:

阶段 2-3 失败(开机黑屏或 GRUB rescue):

# 现象:屏幕显示 "grub rescue>"
# 原因:GRUB 找不到正常启动项

# 进入 GRUB 命令行手动启动
grub rescue> set root=(hd0,msdos1)      # 引导分区
grub rescue> linux /vmlinuz-<ver> root=/dev/sda2 ro
grub rescue> initrd /initramfs-<ver>.img
grub rescue> boot

阶段 4-5 失败(kernel panic 或 initramfs drop to shell):

# 现象:"You are now being dropped into an emergency shell"
# 原因:根文件系统找不到(驱动缺失、LVM 未激活、UUID 错)

# 在 emergency shell 中排查
ls /dev/sd* /dev/vd* /dev/nvme*        # 看可用设备
blkid                                   # 看文件系统 UUID
ls /lib/modules/$(uname -r)            # 看已加载模块
cat /proc/modules                       # 确认驱动加载情况
dmesg | tail -30                        # 内核日志

# 修复:手动挂载根 + 修复 fstab
mount /dev/sda2 /sysroot
mount -o bind /dev /sysroot/dev
chroot /sysroot
vi /etc/fstab

阶段 6 失败(系统卡在某个 service):

# 在 GRUB 启动参数加 systemd.unit=rescue.target
# 编辑 /etc/default/grub
GRUB_CMDLINE_LINUX="... systemd.unit=rescue.target"
grub2-mkconfig -o /boot/grub2/grub.cfg

# rescue.target 启动后
systemctl list-jobs                    # 看卡在哪个 job
systemctl status                       # 看失败 unit
journalctl -xb                         # 看本次启动日志
systemctl reset-failed                 # 重置失败状态

关键启动日志:

# 内核日志(启动过程)
dmesg | less

# 启动耗时分解
systemd-analyze
# Startup finished in 2.456s (kernel) + 8.123s (userspace) = 10.579s
# graphical.target reached after 9.876s in userspace

# 启动耗时排序
systemd-analyze blame | head -20

# 关键路径
systemd-analyze critical-chain multi-user.target

生产实践:

  • K8s 节点:systemd 还要管理 kubelet/containerd,节点启动慢的常见原因是 kubelet.service 等待 containerd.service
  • 启动慢的常见原因:
    • NetworkManager-wait-online.service(等网络就绪,可禁用)
    • 大量 mount unit(/etc/fstabnofail 跳过)
    • LVM 激活慢(lvm.confuse_lvmetad
  • initramfs 自定义:dracut -f --add "lvm network" /boot/initramfs-$(uname -r).img
6 关键 sysctl 参数分类与推荐配置(生产级基线)

答案:

sysctl 调优是 SRE 日常必做。下面按子系统分类整理生产基线

网络子系统(net.*):

# === 1. 缓冲区 ===
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# === 2. 拥塞控制 ===
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq

# === 3. 连接队列 ===
net.core.somaxconn = 32768              # 监听 backlog 上限
net.ipv4.tcp_max_syn_backlog = 65535    # SYN 队列
net.core.netdev_max_backlog = 5000      # 网卡接收队列

# === 4. TIME_WAIT 优化 ===
net.ipv4.tcp_tw_reuse = 1               # 允许 TIME_WAIT 重用
net.ipv4.tcp_fin_timeout = 15           # 默认 60s → 15s

# === 5. SYN 防护 ===
net.ipv4.tcp_syncookies = 1             # 开启 SYN Cookie
net.ipv4.tcp_synack_retries = 2         # SYN+ACK 重试 2 次
net.ipv4.tcp_max_syn_backlog = 65535

# === 6. Keepalive ===
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3

# === 7. 安全 ===
net.ipv4.tcp_rfc1337 = 1                # 防御 TIME_WAIT 攻击
net.ipv4.conf.all.rp_filter = 1         # 反向路径过滤
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.icmp_echo_ignore_broadcasts = 1

# === 8. IP 转发(如需 NAT/路由) ===
net.ipv4.ip_forward = 1
net.ipv6.conf.all.forwarding = 1

# === 9. TCP Fast Open ===
net.ipv4.tcp_fastopen = 3

# === 10. 端口范围 ===
net.ipv4.ip_local_port_range = 10000 65535

虚拟内存子系统(vm.*):

# === 1. 脏页回写 ===
vm.dirty_background_ratio = 10         # 内存 10% 脏页时后台回写
vm.dirty_ratio = 20                    # 内存 20% 脏页时同步阻塞
vm.dirty_expire_centisecs = 3000       # 30s
vm.dirty_writeback_centisecs = 500     # 5s 唤醒一次回写

# === 2. Swap 倾向 ===
vm.swappiness = 60                     # 默认 60
# 数据库:vm.swappiness = 1(优先用内存)

# === 3. 缓存压力 ===
vm.vfs_cache_pressure = 100            # 默认 100
# 文件服务器可调高(>100)优先回收 dentry

# === 4. 大页(数据库) ===
vm.nr_hugepages = 1024                 # 2GB

# === 5. 透明大页(生产数据库关闭) ===
# echo never > /sys/kernel/mm/transparent_hugepage/enabled

# === 6. OOM 行为 ===
vm.overcommit_memory = 0               # 0=启发式 1=总允许 2=严格
vm.overcommit_ratio = 50
vm.oom_kill_allocating_task = 0        # 默认杀占用最高,可改 1 杀触发者

内核子系统(kernel.*):

# === 1. 进程数限制 ===
kernel.pid_max = 4194304
kernel.threads-max = 4194304

# === 2. 文件句柄 ===
fs.file-max = 2097152                  # 系统级
# 进程级:ulimit -n / /etc/security/limits.conf

# === 3. 信号队列 ===
kernel.sem = 250 32000 32 128

# === 4. 共享内存 ===
kernel.shmmax = 68719476736            # 64GB
kernel.shmall = 4294967296

# === 5. 消息队列 ===
kernel.msgmax = 65536
kernel.msgmnb = 65536

# === 6. NUMA(数据库可关) ===
kernel.numa_balancing = 0              # 0=关闭 1=启用

# === 7. 软死锁检测 ===
# hung_task_timeout_secs 默认 120,调小可更快发现卡死
# echo 30 > /proc/sys/kernel/hung_task_timeout_secs

文件系统(fs.*):

# === 1. inotify 限制(影响 K8s/IDE/agent) ===
fs.inotify.max_user_watches = 524288    # 默认 8192,K8s 节点需调大
fs.inotify.max_user_instances = 512
fs.inotify.max_queued_events = 16384

# === 2. file-max 已在 kernel. 中

# === 3. 目录项缓存 ===
fs.dir-notify-enable = 1

生产场景配置包:

高并发 Web 服务器:

# /etc/sysctl.d/99-web.conf
net.core.somaxconn = 32768
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq
fs.file-max = 2097152
fs.inotify.max_user_watches = 524288

K8s 节点:

# /etc/sysctl.d/99-k8s.conf
fs.inotify.max_user_watches = 524288
fs.inotify.max_user_instances = 8192
fs.file-max = 2097152
kernel.pid_max = 4194304
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
vm.swappiness = 1                       # 容器节点推荐 1(kubeadm 默认),避免 OOM 时完全无 swap 缓冲

数据库服务器:

# /etc/sysctl.d/99-db.conf
vm.swappiness = 1
vm.dirty_background_ratio = 3
vm.dirty_ratio = 10
vm.nr_hugepages = 16384                 # 32GB 大页
kernel.numa_balancing = 0
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728

应用方式:

# 1. 直接生效
sysctl -w net.core.somaxconn=32768

# 2. 从文件加载
sysctl -p /etc/sysctl.d/99-k8s.conf

# 3. 持久化(写入 /etc/sysctl.d/)
echo "net.core.somaxconn = 32768" > /etc/sysctl.d/99-k8s.conf
sysctl --system

# 4. 验证
sysctl net.core.somaxconn

生产建议:

  • sysctl --system 一次性加载 /etc/sysctl.d/ 所有文件
  • 修改前先 sysctl -w 试运行,确认无问题再写文件
  • K8s 节点用 tuned profile(如 tuned-adm profile virtual-host
  • 生产变更通过 Ansible/Salt 推送,避免手工操作
7 /proc 伪文件系统详解:哪些关键路径必须掌握?

答案:

/proc 是 Linux 内核提供的伪文件系统(procfs),挂载在 /proc,提供进程和内核信息的运行时接口。几乎所有性能工具都依赖 /proc

核心路径分类:

1. 系统级(无 PID 后缀):

# === 内存信息 ===
/proc/meminfo                  # 全局内存统计
# MemTotal: 67108864 kB
# MemFree: 12345678 kB
# MemAvailable: 45678901 kB     # 真正可用(MemFree + 可回收缓存)
# Buffers: 234567 kB
# Cached: 12345678 kB
# SwapTotal/Cached/Available

# === CPU 信息 ===
/proc/cpuinfo                  # CPU 型号、频率、cache、flags
/proc/loadavg                  # 负载(1/5/15 分钟)+ running/total 进程数
# 0.50 0.45 0.40 1/1234 12345

/proc/stat                     # 全局 CPU 统计(user/nice/system/idle/iowait/irq/softirq/steal)
# cpu  1234567 0 234567 89012345 12345 0 6789 0 0 0
# 计算 CPU 使用率:100 - (idle4 - idle0) / (total4 - total0) * 100

# === 启动信息 ===
/proc/uptime                   # 启动秒数 + idle 秒数
/proc/version                  # 内核版本 + GCC 版本
/proc/cmdline                  # 内核启动参数
/proc/filesystems             # 支持的文件系统类型

# === 中断信息 ===
/proc/interrupts               # 硬件中断统计
/proc/softirqs                 # 软中断统计
# 看哪个 CPU 软中断高 → 网络瓶颈或调度问题

# === IO 信息 ===
/proc/diskstats                # 块设备 IO 统计(iostat 数据源)
/proc/partitions               # 分区信息

# === 网络信息 ===
/proc/net/dev                  # 网卡统计(bytes/packets/errors/drops)
/proc/net/tcp                  # TCP 连接表(netstat 数据源)
/proc/net/tcp6                 # IPv6 TCP
/proc/net/udp                  # UDP
/proc/net/arp                  # ARP 表
/proc/net/route                # 路由表
/proc/net/sockstat             # socket 统计

# === 模块与符号 ===
/proc/modules                  # 已加载内核模块
/proc/kallsyms                 # 内核符号表(需 root)

# === cgroup 挂载点 ===
/proc/cgroups                  # cgroup 控制器信息
/proc/self/cgroup              # 当前进程 cgroup 归属
/proc/<pid>/cgroup             # 指定进程 cgroup

# === 挂载点 ===
/proc/mounts                   # 当前挂载(mount 命令数据源)
/proc/self/mountinfo           # 详细挂载信息

2. 进程级(/proc//):

# === 基础信息 ===
/proc/<pid>/cmdline            # 启动命令行(\0 分隔)
/proc/<pid>/comm               # 进程名
/proc/<pid>/status             # 易读进程状态(vs stat)
# Name: nginx
# State: S (sleeping)
# Pid: 1234
# PPid: 1
# Threads: 8
# VmRSS: 123456 kB
# VmSize: 234567 kB

/proc/<pid>/stat               # 详细状态(52 字段,空格分隔)
/proc/<pid>/statm              # 简化 stat(size/resident/shared/text/lib/data)

# === 内存信息 ===
/proc/<pid>/maps               # 虚拟内存映射(VMA 段)
/proc/<pid>/smaps              # 每段详细 RSS/Pss 统计
/proc/<pid>/numa_maps          # NUMA 内存分布
/proc/<pid>/oom_score          # 0-1000
/proc/<pid>/oom_score_adj      # -1000 ~ +1000
/proc/<pid>/oom_adj            # 旧版

# === IO 信息 ===
/proc/<pid>/io                 # 进程 IO 统计(rchar/wchar/syscr/syscw/...)
# rchar: 123456789  读字节
# wchar: 987654321  写字节
# syscr: 12345      读系统调用
# syscw: 6789       写系统调用
# read_bytes: 23456789  真实磁盘读
# write_bytes: 9876543  真实磁盘写

# === 文件描述符 ===
/proc/<pid>/fd/                # fd 符号链接(0,1,2 是 stdin/stdout/stderr)
/proc/<pid>/fdinfo/            # fd 详细信息
/proc/<pid>/limits             # 资源限制
# Max open files: 65535

# === 调度信息 ===
/proc/<pid>/sched              # 调度统计(runtime/waittime/...)
/proc/<pid>/schedstat          # 调度器统计
/proc/<pid>/cpuset             # CPU 亲和性
/proc/<pid>/task/<tid>/        # 线程级(与进程级类似)

# === 网络 ===
/proc/<pid>/net/               # 进程 namespace 网络视图
/proc/<pid>/ns/                # namespace 引用

实战命令:

# 1. 查进程命令行(绕过 ps 解析问题)
cat /proc/1234/cmdline | tr '\0' ' '

# 2. 查进程打开的文件(lsof 备选)
ls -la /proc/1234/fd/ | head

# 3. 查进程 IO 统计
cat /proc/1234/io
# watch -n 1 'cat /proc/1234/io'  # 持续观测

# 4. 查进程实际内存
cat /proc/1234/status | grep -E "VmRSS|VmSize|Threads"

# 5. 查谁在使用某端口
ls -la /proc/*/fd/ 2>/dev/null | grep socket | head

# 6. 系统内存可用量
awk '/MemAvailable/ {print $2 " kB"}' /proc/meminfo

# 7. 系统负载 + 内存 + 进程数
echo "load: $(cat /proc/loadavg | awk '{print $1,$2,$3}')"
echo "mem: $(awk '/MemAvailable/{a=$2}/MemTotal/{t=$2}END{printf "%.1f%% used", (t-a)/t*100}' /proc/meminfo)"

# 8. 找 CPU 占用最高的进程(无 ps/top)
for pid in /proc/[0-9]*; do
    pid_num=$(basename $pid)
    cpu=$(awk '{print "cpu "$2+$3+$4+$5+$6+$7+$8}' /proc/$pid_num/stat 2>/dev/null)
    echo $pid_num $cpu
done | sort -k2 -rn | head -10

生产建议:

  • 容器内 top/ps 受 namespace 限制时,/proc 仍可见(同一 PID namespace)
  • /proc/sys/ 是 sysctl 的底层接口,可直接 echo 调参
  • /proc/kcore 是 ELF 格式的内核映像(GB 大小),勿读
  • k8s 中 kubectl debug node/<node> 即可看到节点 /proc
8 bpftrace 与 perf 实战:如何用 eBPF 工具定位疑难问题?

答案:

eBPF(extended Berkeley Packet Filter)是 Linux 内核革命性技术,无需修改内核或加载模块就能在内核/用户态运行沙箱程序,性能开销极低(1-5%)。

bpftrace 入门:

# 安装(Ubuntu)
apt install bpftrace
# 或 RHEL
yum install bpftrace

# 1. Hello World(追踪 open 系统调用)
bpftrace -e 'kprobe:do_sys_open { printf("%s [%d]\n", comm, pid); }'

# 2. 看谁在读 /etc/passwd
bpftrace -e 'tracepoint:syscalls:sys_enter_openat /str(args->filename) == "/etc/passwd"/ { printf("%s\n", comm); }'

# 3. 统计进程系统调用次数(top 10)
bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'
# Ctrl-C 后输出 @comm[nginx]: 12345
#         @comm[mysqld]: 6789

# 4. 跟踪进程系统调用(strace 增强版)
bpftrace -e 'tracepoint:syscalls:sys_enter_read /pid == 1234/ { printf("read %d bytes\n", args->count); }'

# 5. 统计进程退出时间
bpftrace -e 'tracepoint:sched:sched_process_exit { printf("%s exit code %d duration %d\n", comm, args->code, args->timestamp_ns - $self->start); }'

# 6. 看 TCP 重传统计
bpftrace -e 'tracepoint:tcp:tcp_retransmit_skb { @[args->sport] = count(); }'

bpftrace 脚本(保存为 .bt 文件):

#!/usr/bin/env bpftrace
/* biolatency.bt - 块设备 IO 延迟分布直方图 */

#include <linux/blkdev.h>

BEGIN {
    printf("Tracing block device I/O... Hit Ctrl-C to end.\n");
}

kprobe:blk_mq_start_request {
    @start[tid] = nsecs;
}

kretprobe:blk_mq_end_request /@start[tid]/ {
    @usecs = hist((nsecs - @start[tid]) / 1000);
    delete(@start[tid]);
}

END {
    printf("\nBlock IO latency (us):\n");
    print(@usecs);
}
# 跑脚本
bpftrace biolatency.bt
# 1  -> 2                 : 5 |
# 2  -> 4                 : 15 ||
# 4  -> 8                 : 156 ||||||||
# ...
# 512 -> 1024             : 3 |
# 1024 -> 2048            : 1 |
# @usecs:
# [1]                  5 |@@@@|
# [2]                 15 |@@@@@@@@@@@|
# [16]                156 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
# ...

perf 实战(采样型 profiler):

# 安装
apt install linux-tools-common linux-tools-generic

# 1. 实时 CPU 热点(按函数)
perf top
# 5.0%  [kernel]  [k] __schedule
# 3.0%  mysqld    [.] buf_calc_page_new_checksum
# ...

# 2. 记录 30 秒 profile
perf record -F 99 -a -g -- sleep 30
perf report --sort=comm,symbol

# 3. 看调用栈
perf record -F 99 -p 1234 -g -- sleep 10
perf script | stackcollapse-perf.pl | flamegraph.pl > flame.svg

# 4. 跟踪系统调用(类似 strace)
perf trace -p 1234
perf trace -e open,read,write -- your-command

# 5. 性能计数器(PMC)查询
perf stat -e cache-misses,cache-references,L1-dcache-load-misses -p 1234

# 6. 内存分配热点
perf mem record -t load -p 1234 -- sleep 10
perf mem report

# 7. 调度延迟分析
perf sched record -- sleep 10
perf sched latency

# 8. 锁竞争分析
perf lock contention -a -- sleep 10

常见生产场景:

场景 1:CPU 100% 不知是哪个函数

# 1. 找进程
top -bn1 | head
# PID 1234 mysqld 100% CPU

# 2. 采样(不需要停服务)
perf top -p 1234
# 或
perf record -F 99 -p 1234 -g -- sleep 30
perf report

场景 2:服务响应慢,卡在 IO

# 跟踪读/写系统调用
bpftrace -e '
kprobe:__x64_sys_read /pid == 1234/ {
    @start[tid] = nsecs;
    @fd[tid] = args->fd;
}
kretprobe:__x64_sys_read /@start[tid]/ {
    $lat_us = (nsecs - @start[tid]) / 1000;
    @usecs = hist($lat_us);
    if ($lat_us > 10000) {  # > 10ms 记录
        printf("slow read: fd=%d lat=%d us\n", @fd[tid], $lat_us);
    }
    delete(@start[tid]); delete(@fd[tid]);
}'

场景 3:网络丢包位置

# 看内核丢包位置
perf trace -e skb:kfree_skb -a
# 看到大量 skb:kfree_skb 来自 tcp_v4_rcv → TCP 校验和错

# 或用 bpftrace
bpftrace -e '
kprobe:__kfree_skb /args->reason == SKB_DROP_REASON_TCP_CSUM/ { 
    printf("TCP CSUM drop: skb=%p reason=%d\n", args->skb, args->reason); 
}'

场景 4:磁盘延迟分布

# 跑预先写好的脚本
bpftrace /usr/share/bpftrace/tools/biolatency.bt
# 看 IO 延迟直方图
# 99% IO 在 100μs 内 → NVMe 健康
# 99% IO > 10ms → 慢盘或队列深

bpftrace 工具集(已预装):

ls /usr/share/bpftrace/tools/
# bashreadline.bt     - bash 击键统计
# biolatency.bt       - 块 IO 延迟
# biosnoop.bt         - 块 IO 跟踪
# capable.bt          - 能力检查
# cpudist.bt          - 进程 on-CPU 延迟
# dcsnoop.bt          - 目录项缓存
# execsnoop.bt        - 进程 exec 跟踪
# gethostlatency.bt   - getaddrinfo 延迟
# killsnoop.bt        - 进程 kill 跟踪
# mdflush.bt          - 元数据 fsync
# naptime.bt          - 进程 off-CPU 时间
# oomkill.bt          - OOM Kill 事件
# opensnoop.bt        - 进程 open 跟踪
# pidpersec.bt        - 进程创建速率
# runqlat.bt          - CPU 运行队列延迟
# syscount.bt         - 系统调用计数
# tcpaccept.bt        - TCP accept 跟踪
# tcpconnect.bt       - TCP connect 跟踪
# tcpretrans.bt       - TCP 重传
# vfsstat.bt          - VFS 统计

生产实践:

  • bpftrace 单次跑 < 30 分钟,避免长期挂载影响性能
  • bpftrace 写脚本前先用 bpftrace --info 看探针列表
  • perf 长期跑用 perf record -F 99 -a -g -- sleep 86400 一天后停
  • FlameGraphflamegraph.pl)是 perf 数据可视化的标准工具
  • 生产部署:考虑 bpftrace 程序安全——bpftrace 默认带 1M 指令上限 + 内核 verifier 静态检查,不会无限循环。主要风险:探针数量过多导致 attach 开销、BPF map 未设上限导致内存泄漏、高 QPS 下 printf 输出开销
9 Linux PSI(Pressure Stall Information)是什么?如何用于性能监控?

答案:

PSI(Pressure Stall Information,压力失速信息)是 Linux 4.20+ 引入的内核特性,量化系统因资源争用而损失的时间。比传统"CPU 利用率"更精准,直接反映"被卡了多久"

三类资源 PSI:

# CPU
cat /proc/pressure/cpu
# some avg10=0.00 avg60=0.05 avg300=0.10 total=123456
# full avg10=0.00 avg60=0.00 avg300=0.00 total=0

# 内存
cat /proc/pressure/memory
# some avg10=2.30 avg60=1.50 avg300=0.80 total=987654321
# full avg10=0.00 avg60=0.00 avg300=0.00 total=0

# IO
cat /proc/pressure/io
# some avg10=5.20 avg60=3.10 avg300=2.40 total=1234567890
# full avg10=0.00 avg60=0.00 avg300=0.00 total=0

关键字段:

  • some至少一个任务因该资源被阻塞(抢占/失忆/IO 等待)
  • full所有任务都被阻塞(完全无法工作)
  • avg10/60/300:最近 10/60/300 秒的阻塞时间占比(百分比)
  • total:从启动以来累计阻塞时间(微秒)

为什么需要 PSI:

  • 传统监控:CPU 利用率 = 100%,但你不知道"卡了多久"
  • PSI:直接告诉你 “最近 10 秒内,因为内存阻塞损失了 2.3 秒时间”
  • 这对 SLO 监控至关重要(“99% 请求延迟 < 100ms” → “99% 时间 CPU 没 stall”)

典型解读:

PSI 指标含义阈值告警
cpu/some > 5%频繁有任务等 CPU检查负载、CPU 核数
cpu/full > 1%频繁 100% 所有任务都等 CPU严重:CPU 满载
memory/some > 10%内存频繁紧张检查内存泄漏、cgroup 限制
memory/full > 1%频繁 OOM 边缘严重:扩容或减负载
io/some > 10%频繁 IO 等待检查慢盘、队列深
io/full > 1%频繁所有任务都等 IO严重:盘故障或饱和

cgroup v2 PSI(Pod 级别):

# Pod 的 PSI(K8s 1.20+)
cat /sys/fs/cgroup/kubepods/burstable/pod<uid>/cpu.pressure
cat /sys/fs/cgroup/kubepods/burstable/pod<uid>/memory.pressure
cat /sys/fs/cgroup/kubepods/burstable/pod<uid>/io.pressure

# 单个容器
cat /sys/fs/cgroup/kubepods.slice/.../memory.pressure

Prometheus 监控集成:

# node-exporter 默认暴露 PSI 指标
node_pressure_cpu_waiting_seconds_total
node_pressure_memory_stalled_seconds_total
node_pressure_io_stalled_seconds_total
node_pressure_memory_full_seconds_total

# 告警规则示例
- alert: HighCPIPressure
  expr: |
    rate(node_pressure_cpu_waiting_seconds_total[1m]) > 0.2
  for: 5m
  labels:
    severity: warning
  annotations:
    summary: "CPU 压力高"

- alert: CriticalMemoryPressure
  expr: |
    rate(node_pressure_memory_full_seconds_total[1m]) > 0.01
  for: 2m
  labels:
    severity: critical
  annotations:
    summary: "内存严重不足"

实战案例:

案例 1:CPU 利用率高但服务慢

# 现象:top 显示 CPU 100%,但应用延迟高
# 诊断
cat /proc/pressure/cpu
# some avg10=45.00 → 45% 时间有任务等 CPU(CPU 不足)
# full avg10=2.00  → 2% 时间所有任务都等 CPU(CPU 饱和)
# 结论:CPU 真的不够,不是别的问题

# vs 如果是
# some avg10=45.00
# full avg10=0.00  → 0% 时间全等(虽然利用率高但还有余量)
# 结论:CPU 接近满载但还没瓶颈,应该查别的原因(IO?锁?)

案例 2:内存泄漏早期发现

# 监控 memory/some 趋势
watch -n 5 'cat /proc/pressure/memory'
# memory/some 持续上升 → 内存压力越来越大 → 可能是泄漏

# K8s Pod 级
kubectl exec -it <pod> -- cat /sys/fs/cgroup/memory.pressure

案例 3:数据库 IO 抖动

# 数据库延迟高
# 1. 看 IO PSI
cat /proc/pressure/io
# some avg10=15.20 → 15% 时间有任务等 IO

# 2. 看具体设备
iostat -dx 1

# 3. 关联监控
# 若 PSI 高 + iostat 看到 svctm 高 → 盘慢
# 若 PSI 高 + iostat 看到高 await → 队列深
# 若 PSI 高 + aqu-sz 低 → NVMe 设备自身慢

生产建议:

  • PSI 是比利用率更准的指标,优先基于 PSI 配 SLO 告警
  • some 是常态指标,full 是极端指标(应保持 0)
  • K8s 节点开启 PSI,配合 Vertical Pod Autoscaler(VPA)做资源动态调整
  • 容器内(无特权)可读 cgroup PSI,但需 resources.monitoring.path = /sys/fs/cgroup/...
10 CPU 使用率过高(> 80%)该如何系统化排查?

答案:

CPU 使用率高本身不是问题,问题在于使用率高的部分是不是业务预期的。可能是:正常业务流量、突发任务、失控的循环、GC、加密/序列化、调度器开销、内核中断。排查目标是找出占用 CPU 的代码

Step 1: 区分 us / sy / wa / si / st / id

# 总体分布
top -b -n 1 | head -20
# %Cpu(s): 45.0 us, 30.0 sy,  0.0 ni, 20.0 id,  5.0 wa,  0.0 hi,  0.0 si,  0.0 st
#           ^     ^                ^     ^     ^     ^
#           |     |                |     |     |     虚拟化偷取(宿主机过载)
#           |     |                |     |     软中断(网络包处理)
#           |     |                |     硬中断(网卡/磁盘)
#           |     |                idle
#           |     内核态
#           用户态

# vmstat 持续观察
vmstat 1 5
# 看 sy 高 = 系统调用/内核开销大
# 看 us 高 = 应用层热点
# 看 wa 高 = IO 等待
# 看 hi/si 高 = 软硬中断(网络包/IO 频繁)

Step 2: 定位到进程

# 进程级 CPU 占用
ps -eo pid,ppid,user,pcpu,pmem,etime,comm --sort=-pcpu | head -20

# 看是哪个用户的进程(区分业务/系统)
ps -eo user,pcpu --sort=-pcpu | awk 'NR>1 {sum[$1]+=$2} END {for (u in sum) print u, sum[u]}'

# 看是哪个线程
top -H -p <pid>
# 按 CPU 排序,记录最高 tid

Step 3: 定位到代码(on-CPU 火焰图)

# perf 采样
perf record -F 99 -p <pid> -g -- sleep 30
perf report --sort=comm,symbol  # 看热点函数
perf script | stackcollapse-perf.pl | flamegraph.pl > cpu.svg

# 简化版:用 perf top 实时看
perf top -p <pid>
# 看到 hot 函数名后去代码查

Step 4: 常见热点与处理

现象根因处理
应用层单函数占比 > 30%算法热点算法优化、加缓存、并行化
GC 占用 > 20%JVM 频繁 GC调堆大小、改 G1/ZGC
系统调用占比高频繁 IO / forkstrace -c -p <pid> 看具体 syscall
软中断占比高(si)网络包处理多队列 RSS、irqbalance、DPDK
内核态占比高(sy)锁竞争 / 调度perf lock、减少锁粒度
大量 R 态任务在等 CPU线程数过多减少线程、用协程
单核 100% 其他核空单线程应用绑核或多线程改造
wa% 高IO 阻塞见"磁盘 IO 性能"专项

Step 5: Java 进程 CPU 高

# 找到 CPU 高的线程
top -H -p <pid>
# tid 转 16 进制
printf '%x\n' <tid>
# jstack 找对应线程栈
jstack <pid> | grep -A 30 "nid=0x<hex>"

# 用 async-profiler 取火焰图
./profiler.sh -d 30 -e cpu -f /tmp/cpu.html <pid>

Step 6: 持续监控 + 告警

# 业务进程 CPU 突增
rate(container_cpu_usage_seconds_total{pod=~"myapp-.*"}[5m]) > 0.9

# 整体节点 CPU 接近饱和
1 - avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) > 0.8

典型场景:

  • us=80% + sy=20% → 应用热点,火焰图

  • us=20% + si=60% → 网络包处理,看网卡多队列

  • wa=80% → 实际不是 CPU 瓶颈,是 IO 瓶颈(CPU 等盘)

  • 容器内 CPU 监控 100% 但宿主机 CPU 低 → CPU limit 设小导致 throttling

    # 看 throttling
    cat /sys/fs/cgroup/cpu.stat
    # nr_throttled 100  throttled_usec 12345678
    # ^^^^^^^^^^ 有 100 次被限流
    

    处理:调大 cpu.cfs_quota_us / cpu.max,或改 --cpu-manager=static + Guaranteed pod QoS

11 服务器响应缓慢该如何系统化排查?

答案:

“服务器响应慢"是最高频的线上问题,根因分布很广:CPU、内存、磁盘、网络、应用、数据库、外部依赖。关键是快速定位瓶颈层(USE 方法:Utilization / Saturation / Errors)。

黄金排查流程(自顶向下):

[应用层]  应用响应慢
    ↓ 排查
[运行时]  GC / 锁 / 线程池
    ↓ 排查
[OS 资源] CPU / 内存 / IO / 网络
    ↓ 排查
[依赖]    数据库 / 缓存 / 第三方 API
    ↓ 排查
[外部]    网络 / DNS / 运营商

Step 1: 看应用指标(先确定慢在哪)

# 业务侧:RT 是不是真涨了
# 看 APM / 监控 / 业务日志

# 应用层拆解 RT
curl -w "DNS: %{time_namelookup}\nConnect: %{time_connect}\nTLS: %{time_appconnect}\nTTFB: %{time_starttransfer}\nTotal: %{time_total}\n" \
     -o /dev/null -s <url>
# DNS 慢 → 解析问题
# Connect 慢 → 网络/防火墙
# TLS 慢 → 证书/算法
# TTFB 慢 → 服务端处理
# Total-TTFB 慢 → 响应体下载

# 应用服务状态
systemctl status myapp
journalctl -u myapp -n 100 --no-pager

Step 2: 看运行时(JVM 视角)

# 线程数(线程池满 = 排队)
jstack <pid> | grep "java.lang.Thread.State" | sort | uniq -c | sort -rn
# BLOCKED 多 → 锁竞争
# WAITING 多 → 等待资源(数据库连接池、IO)
# RUNNABLE 多 → 真的在跑

# GC 频率
jstat -gcutil <pid> 1s 5
# YGC 列:每秒几次?老年代 Full GC 时间?

# 数据库连接池
# 看 active / idle / waiting

Step 3: 看系统资源(USE 方法)

资源UtilizationSaturationErrors
CPUtop %Cpuload averagePSI cpu
内存free usedPSI memory、swap si/soOOM Kill
磁盘iostat %utilaqu-szawaitPSI iodmesg IO error
网络nicstat 吞吐dropscollisionsethtool -S errors
# 30 秒快速诊断脚本
{ 
  echo "=== uptime ==="; uptime
  echo "=== top ==="; top -b -n 1 | head -20
  echo "=== free ==="; free -h
  echo "=== iostat ==="; iostat -dx 1 3
  echo "=== vmstat ==="; vmstat 1 3
  echo "=== ss ==="; ss -s
  echo "=== D 态进程 ==="; ps -eo pid,ppid,stat,comm | awk '$3 ~ /D/'
  echo "=== dmesg 错误 ==="; dmesg | tail -20
  echo "=== PSI ==="; for f in cpu memory io; do echo "--- $f ---"; cat /proc/pressure/$f; done
} | tee /tmp/perf-$(date +%s).log

Step 4: 看依赖

# 数据库慢
# 看数据库监控:QPS、慢查询、连接数、InnoDB 行锁、buffer pool 命中率
# 看慢查询日志
mysql -e "SHOW FULL PROCESSLIST" | head
# 看 lock 等待
mysql -e "SELECT * FROM information_schema.innodb_trx" 
# 看主从延迟
mysql -e "SHOW SLAVE STATUS\G" | grep Seconds_Behind_Master

# 缓存
redis-cli --latency          # 持续测延迟
redis-cli INFO stats | grep instantaneous

# 外部 API:业务代码看对方响应时间,或抓包

Step 5: 性能基线 + 历史回放

# 用 atop 持续记录,每 10 分钟采样(默认 10min 历史)
atop -a -w /var/log/atop.log 60

# 回放历史(看问题发生时间点的状态)
atop -r /var/log/atop.log -b 14:30 -e 14:35

Step 6: 网络层慢

# TCP 重传率高 = 网络丢包
ss -s           # 看 retrans
netstat -s | grep -i retrans
# 抓包看是否 RST / 重传
tcpdump -i eth0 -nn -w /tmp/cap.pcap 'port 80'
# Wireshark: Statistics → Conversations → 看每个流的 RTT

Step 7: 应急处置

# 1. 临时扩容(云上)
# 加 pod 副本 / 加机器
# 2. 限流
nginx: limit_req / limit_conn
应用: Sentinel / Envoy
# 3. 降级
关非核心功能,返回缓存
# 4. 重启
# 5. 回滚

典型场景:

  • 凌晨 3 点批量任务致响应慢 → 看 cron、批处理 schedule
  • 流量突增致响应慢 → 看 pv/uv 是否异常、是否被刷
  • 数据库锁等待致响应慢 → 查 innodb_trx、pg_locks
  • K8s pod 调度慢致响应慢 → 节点资源满、镜像拉取慢
  • 看似随机慢 → 看 PSI cpu some 是否有 spike,对应时间段 CPU 突发
12 服务器频繁重启可能有哪些原因?该如何排查?

答案:

服务器重启可能由硬件、内核、关键进程、资源耗尽、外部控制等多类原因触发,关键是保留现场:启动日志、kdump 核心转储、/var/log/messages、硬件指示灯。SRE 必问。

常见原因分类:

类别典型原因排查点
硬件电源故障、CPU 过热、内存 ECC、硬盘 SMARTBMC/IPMI 日志、SMART、mcelog
内核kernel panic、soft lockup、hard lockup、Oopskdump、dmesg、/var/crash/
资源OOM、cgroup 限制、磁盘写满dmesg OOM、/var/log/syslog
系统systemd 重启、rsyslog 配置、看门狗journalctl/var/log/wtmp
外部控制IPMI 远程断电、云厂商运维、负载均衡健康检查失败云监控、控制台、API 审计
误操作人为 reboot、脚本 bug命令历史、sudo 审计

Step 1: 看是 graceful 重启还是 crash

# 看重启时间 + 时长
last reboot
# reboot   system boot  2.6.32  Mon Jun  8 09:00 - 14:00  (05:00)
#                                   ^^^^^ 启动时间
# 频繁时间点 = 找出规律

# 看 wtmp 完整登录历史
last -f /var/log/wtmp

# 看 runlevel 切换
cat /var/log/wtmp | last -x

Step 2: 系统日志

# 找出最后一次启动之前的日志(关键)
journalctl --list-boots
# 0 = 当前
# -1 = 上一次
journalctl -b -1 -n 200        # 上一次启动的最后 200 行
journalctl -b -1 -p err        # 只看错误
journalctl -k -b -1            # 只看内核

# 看重启前是否有 OOM
journalctl -k | grep -iE "oom|killed process|out of memory"
dmesg | grep -iE "oom|panic|lockup|bug|trace"

# systemd 主动重启?
journalctl -u myapp.service --since "2 hours ago"
# 看 Restart= 触发记录

Step 3: kernel panic / kdump

# 启用 kdump(开机预留内存给 kdump kernel)
systemctl enable kdump
systemctl start kdump
# 配置文件 /etc/kdump.conf
# crashkernel=256M 或 auto

# panic 后会自动生成 vmcore
ls -la /var/crash/
# drwxr-xr-x 2 root root  2024-06-08 14:00 127.0.0.1-2024-06-08-14:00:21/
#   vmcore      ← 核心转储
#   vmcore-dmesg.txt

# 分析 vmcore
crash /usr/lib/debug/lib/modules/$(uname -r)/vmlinux /var/crash/.../vmcore
# crash> bt -a         # 所有 CPU 调用栈
# crash> ps            # 进程列表
# crash> kmem -i       # 内存信息

# 或用 makedumpfile 提取关键信息(不需完整 crash)
makedumpfile --dump-dmesg /var/crash/.../vmcore /tmp/dmesg.txt

Step 4: 硬件层

# CPU 温度
sensors              # lm-sensors
# coretemp-isa-0000
# Core 0:       +45.0°C  (high = +80.0°C, crit = +100.0°C)

# 硬盘 SMART
smartctl -a /dev/sda
# 看 Reallocated_Sector_Ct(重映射)、Current_Pending_Sector(待重映射)

# 内存 ECC 错误
mcelog               # 老式
# 现代在 dmesg / RAS daemon
journalctl -k | grep -iE "mce|machine check"

# IPMI/BMC
ipmitool sel list    # 系统事件日志
ipmitool sdr list    # 传感器读数

# 电源稳定
ipmitool sensor get "PSU1 Status"

Step 5: OOM 与 cgroup

# OOM 记录
journalctl -k | grep -i oom
dmesg | grep -i oom
# "Out of memory: Killed process 1234 (myapp) ..."
# "total-vm:..., anon-rss:..., file-rss:..., shmem-rss:..."

# cgroup 内存限制触发
journalctl -k | grep -i "memory cgroup"
# "memory cgroup out of memory: Killed process 1234 (myapp) ..."
# "memory cgroup: charge failed"

# cgroup 触发的 OOM Killer
cat /sys/fs/cgroup/memory/events
# low 0
# high 0
# max 5          ← 触发 max 5 次
# oom 3          ← OOM Kill 3 次
# oom_kill 3

Step 6: 监控与告警配置

# 节点重启告警
node_boot_time_seconds    # 当前时间 - 启动时间 < 600s = 刚启动
# 触发: time() - node_boot_time_seconds < 600

# 内核 panic
node_vmstat_panic         # 如果能拿到

# OOM 事件
rate(node_vmstat_oom_kill[5m]) > 0

典型场景:

  • 凌晨固定时间重启 → cron 任务、备份脚本、UPS 自检
  • 每次重启都是 kernel panic → 驱动/硬件故障,启用 kdump 留现场
  • OOM 反复触发 → 应用内存泄漏、cgroup limit 太小
  • 偶发重启 + 无日志 → IPMI 远程断电(云厂商运维)、机房空调故障
  • K8s 节点频繁 NotReady → 节点组件崩溃、kubelet 健康检查失败
13 服务器响应慢且 CPU 不高,可能是什么根因?

答案:

“CPU 不高但响应慢” 通常意味着等待(IO、锁、网络、依赖),而非计算。常见根因:磁盘 IO 慢、数据库慢、外部 API 慢、锁竞争、线程池满、配置错误(DNS 解析慢、文件描述符耗尽)。

核心排查思路:识别"在哪一层等"

应用层 wait
[线程状态] BLOCKED / WAITING / TIMED_WAITING 多 = 等锁 / 等连接 / 等 IO
[系统调用] 阻塞 IO read/write / connect / accept
[内核等待] D 态进程 / iowait / netstat 大量 TIME_WAIT / SYN_SENT
[外部依赖] 数据库 RT 高 / Redis 慢 / 第三方 API 超时

Step 1: 看线程都在干什么(Java 示例)

jstack <pid> > /tmp/jstack.log

# 状态统计
grep "java.lang.Thread.State" /tmp/jstack.log | sort | uniq -c | sort -rn
# 234 BLOCKED           ← 锁竞争
# 1234 WAITING          ← 等资源(连接池 / 队列)
# 567 TIMED_WAITING     ← 等超时(sleep / IO 超时)
# 89 RUNNABLE           ← 真正在跑

# 找 BLOCKED 线程
grep -A 5 "BLOCKED" /tmp/jstack.log | head -30
# 通常显示:waiting to lock <0x000000076bf12345>
# 找持有这把锁的线程
grep "locked <0x000000076bf12345>" /tmp/jstack.log

# 找 WAITING 的具体等待目标
grep -B 1 -A 10 "WAITING" /tmp/jstack.log | grep "at "
# 常见:at java.lang.Object.wait、at java.util.concurrent.locks.AbstractQueuedSynchronizer
# 进一步看是哪个类的 wait

Step 2: 系统调用层

# 看进程在哪些系统调用上阻塞
strace -p <pid> -c -f
# Ctrl+C 后看汇总
# 看 read/write/connect/accept 各多少

# 看具体调用栈
strace -p <pid> -k
# TID 1234: futex(0x7f1234, FUTEX_WAIT, ...
#             __lll_lock_wait+0x16 (libpthread)
#             __GI___pthread_mutex_lock+0x6e (libpthread)
#             Java_java_util_concurrent_locks_ReentrantLock_lock+0x1a (libjvm)
#             → 在等 Java ReentrantLock

# 网络 IO 阻塞
strace -e trace=read,write,recv,send,connect -p <pid>
# 看是不是 read() 一直不出

Step 3: IO 与依赖

# 看磁盘 IO
iostat -dx 1 5
# 看 await 高不高,aqu-sz 大不大

# 看具体进程 IO
iotop -oP

# 看网络连接状态
ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -rn
# 看 ESTABLISHED、SYN_SENT、CLOSE_WAIT 比例
# 大量 SYN_SENT → 目标端口不通
# 大量 CLOSE_WAIT → 本端没关连接
# 大量 TIME_WAIT → 高频短连接

# 数据库慢
mysql -e "SHOW ENGINE INNODB STATUS\G" | head -100
# 看 LATEST DETECTED DEADLOCK、最近事务

# 抓包看 RTT
tcpdump -i eth0 -nn -w /tmp/cap.pcap host <db_ip> and port 3306
# Wireshark: Statistics → Conversations → TCP → RTT

Step 4: 常见"等"对照

现象根因处理
大量 BLOCKED锁竞争减少锁粒度、改读写锁、用无锁数据结构
大量 WAITING on LockSupport.parkNanos线程池排队满加大线程池、用队列限流
大量 TIMED_WAITING on Object.wait(timeout)数据库/Redis 客户端超时调超时、调连接池、查服务端 RT
大量 D 态磁盘 IO hung慢盘、NFS 卡死、设备 hung
大量 SYN_SENT上游连不上防火墙、网络、目标端口未开
大量 CLOSE_WAIT应用没 close找泄漏的代码路径
iowait 高磁盘慢见"磁盘 IO"专项
TCP 重传多链路丢包mtr 找丢包点、联系运营商

Step 5: 配置错误类(容易被忽略)

# DNS 解析慢(每次请求解析 1-2s)
# 看 glibc nscd / systemd-resolved 缓存
strace -e trace=connect curl <url> 2>&1 | head
# 看有没有 connect 之前先调 getaddrinfo

# Nagle 算法 + 延迟 ACK 冲突(小包场景 RT 飙 40ms)
sysctl net.ipv4.tcp_nodelay=1    # 业务代码 setsockopt(IPPROTO_TCP, TCP_NODELAY, 1)

# 文件描述符耗尽(应用日志报 Too many open files)
ulimit -n
# 调大 /etc/security/limits.conf

# TCP backlog 满(accept queue 满,新连接丢弃)
ss -ltn
# Recv-Q 接近 Send-Q → 满了
# 应用层调 listen(backlog) 加大 + sysctl net.core.somaxconn

典型场景:

  • “应用 RT 涨 10 倍,CPU 没涨” → 数据库慢查、连接池满、第三方 API 慢
  • “JVM CPU 20% 但 RT 慢” → GC 频繁但采样窗口短,看 jstat -gcutil
  • “响应慢但监控都正常” → DNS 解析慢(每次请求多 1s)、TCP_NODELAY 未开
  • “白天慢、晚上不慢” → 定时任务抢资源、数据库白天流量高
14 系统级核心性能调优:CPU/内存/IO/网络四大基线是什么?

答案:

生产级 Linux 服务器有一组通用基线调优(sysctl / ulimit / 文件系统 / cgroup),覆盖 CPU/内存/IO/网络四个维度。这些是 SRE 装机/调优的"标准动作",面试必问、运维必备。

CPU 基线:

# 调度器
sysctl -w kernel.sched_migration_cost_ns=5000000   # 减少跨核迁移
sysctl -w kernel.sched_min_granularity_ns=1000000 # 1ms 最小粒度

# 透明大页(数据库建议关闭 THP)
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag

# 频率调节
cpupower frequency-set -g performance    # 服务器关节能
# 验证:cpupower frequency-info

内存基线:

# swappiness(数据库/延迟敏感 → 1-10)
sysctl -w vm.swappiness=10

# 脏页比例
sysctl -w vm.dirty_ratio=10              # 物理内存 10%
sysctl -w vm.dirty_background_ratio=5    # 5% 后开始后台回写
sysctl -w vm.dirty_expire_centisecs=3000 # 30s 过期
sysctl -w vm.dirty_writeback_centisecs=500  # 5s 触发回写

# 内核缓存压力
sysctl -w vm.vfs_cache_pressure=100      # 默认 100,200 = 更激进回收 dentry/inode

# 透明大页(如未关)
# 见 CPU 部分

# OOM 行为
sysctl -w vm.panic_on_oom=0              # 0=触发 OOM Killer,1=panic
sysctl -w vm.overcommit_memory=1         # 0=严格,1=总允许,2=比例

磁盘 IO 基线:

# IO 调度器(按设备选)
# NVMe:none(设备自身够快)
# SATA SSD / 虚拟化透传:none 或 kyber
# HDD / SATA SSD 普通:mq-deadline
echo mq-deadline > /sys/block/sda/queue/scheduler

# 队列深度
echo 1024 > /sys/block/sda/queue/nr_requests
echo 256 > /sys/block/nvme0n1/queue/nr_requests

# 预读(顺序读多则加大)
blockdev --setra 4096 /dev/sda      # 4MB 预读
# 验证:blockdev --getra /dev/sda

# 文件系统 mount 选项
# /etc/fstab
# UUID=... /data xfs defaults,noatime,nodiratime,allocsize=64m 0 0
# noatime:禁用访问时间更新(IO 减少 30%+)
# xfs / ext4 都推荐

网络基线:

# 通用
sysctl -w net.core.somaxconn=32768            # accept 队列
sysctl -w net.core.netdev_max_backlog=16384   # 网卡 backlog
sysctl -w net.core.rmem_max=16777216          # 16MB 接收缓冲
sysctl -w net.core.wmem_max=16777216          # 16MB 发送缓冲
sysctl -w net.ipv4.tcp_rmem="4096 87380 16777216"
sysctl -w net.ipv4.tcp_wmem="4096 65536 16777216"

# TIME_WAIT
sysctl -w net.ipv4.tcp_tw_reuse=1             # 出向连接复用(安全)
sysctl -w net.ipv4.ip_local_port_range="1024 65535"
sysctl -w net.ipv4.tcp_fin_timeout=15         # 缩短

# 连接跟踪(用 iptables/nft 时调大)
sysctl -w net.netfilter.nf_conntrack_max=1048576

# TCP 优化
sysctl -w net.ipv4.tcp_fastopen=3
sysctl -w net.ipv4.tcp_slow_start_after_idle=0  # 长连接带宽探测
sysctl -w net.ipv4.tcp_mtu_probing=1            # PMTUD 黑洞探测
sysctl -w net.core.default_qdisc=fq            # BBR 友好
sysctl -w net.ipv4.tcp_congestion_control=bbr   # BBR 拥塞控制

# 文件描述符
echo "* soft nofile 1048576" >> /etc/security/limits.conf
echo "* hard nofile 1048576" >> /etc/security/limits.conf
ulimit -n 1048576

容器化基线:

# kubelet 推荐
--cgroup-driver=systemd
--cpu-manager-policy=static
--topology-manager-policy=single-numa-node
--max-pods=110

# K8s 1.22+ 启用 swap(可选)
--feature-gates=NodeSwap=true
--fail-swap-on=false

# cgroup v2(K8s 1.25+ 默认)
# 配合 systemd cgroup_driver

应用侧建议基线:

应用关键调优
Nginxworker_processes autoworker_rlimit_nofile 1048576multi_accept onuse epoll
MySQLinnodb_buffer_pool_size = 70% RAMinnodb_log_file_size = 4Ginnodb_io_capacity = 1000+(NVMe)
Redismaxmemory-policy allkeys-lruio-threads 4io-threads-do-reads yes
Kafkanum.network.threads = 8num.io.threads = disk数 × 2log.segment.bytes = 1G
Java-Xms = -XmxUseG1GCMaxRAMPercentage=75.0+UseContainerSupport

典型场景:

  • 新机器装机 → 按上面基线跑一遍 sysctl / 调优
  • 性能问题定位 → 对照基线找差异(哪个没设 / 哪个和业务不匹配)
  • 容器化迁移 → 注意 ulimit / cgroup driver / 大页 等与宿主机的对齐
  • 业务变更后 RT 涨 → 重新评估基线(流量特征变了,原来设的拥塞控制可能不优)