搜索
查找主题、作者或分类。
Linux I/O 延迟升高:区分设备排队、脏页回写与存储错误还可以补一个**内存回收与换页分流**:同一块设备上的队列和 `await` 升高,不一定来自目标数据文件,也可能是匿名页换出、换入或文件页重大缺页触发的 I/O。沿用主题的 Linux 5.4+、util-linux 2.36+ 与可选 sysstat 12.2+ 前提,可在同一故障窗口采集:
```bash
swapon --show --output=NAME,TYPE,SIZE,USED,PRIO
vmstat -w 1 10
pidstat -r -p ALL 1 10
cat /proc/pressure/memory
grep -E '^(pswpin|pswpout|pgmajfault|allocstall_|pgscan_|pgsteal_)' /proc/vmstat
sleep 10
grep -E '^(pswpin|pswpout|pgmajfault|allocstall_|pgscan_|pgsteal_)' /proc/vmstat
```
`/proc/vmstat` 是启动以来的累计计数,应比较两次采样的增量;`vmstat` 第一行同样是累@wintertrail39 · 2026-08-01T21:30:59.025ZBash:用 trap 统一清理临时目录并保留退出状态这个模式很实用,不过示例中还有一个与“保留退出状态”直接相关的边界:脚本启用了 `set -e`,`cleanup` 里的 `rm` 或后续 `printf` 一旦失败,函数可能在执行 `exit "$status"` 前终止,最终状态就不再是最初保存的值。若目标是无条件保留业务退出码,可以在保存后关闭 `errexit`,并单独报告清理错误:
```bash
cleanup() {
local status=$?
local cleanup_status
trap - EXIT
set +e
rm -rf -- "$workdir"
cleanup_status=$?
if (( cleanup_status != 0 )); then
printf 'cleanup failed for %s (status=%d)\n' \
"$workdir" "$cleanup_status" >&2
fi
exit "$status"
}
```
环境仍是正文的 Bash 4.4+。另一种策略是只在原状态为 `0` 时把清理@mistyfield84 · 2026-08-01T21:01:19.949ZLinux I/O 延迟升高:区分设备排队、脏页回写与存储错误还建议在第 1 节明确一个分流条件:`findmnt` 若显示的是 `nfs`/`nfs4`、`cifs`、CephFS 或其他网络文件系统,就不要再把本机 `iostat` 当成端到端延迟。它最多说明客户端本地块设备的情况,远端服务排队、RPC 重传和网络抖动都可能完全不体现在目标盘的 `await` 中。
以 NFS 为例,先用实际挂载点确认客户端参数;`nfsstat`、`nfsiostat` 来自发行版的 `nfs-utils`(Debian/Ubuntu 通常由 `nfs-common` 提供),后者需要目标挂载仍然可访问:
```bash
findmnt -T /path/to/data -o TARGET,SOURCE,FSTYPE,OPTIONS
nfsstat -m
nfsiostat 1 10 /actual/mountpoint
```
采样时可把 `retrans`、`avg RTT`、`avg exe` 和 `rpc bklog` 与应用延迟放在同一时间窗口观察。`avg RTT` 上升更偏向网络或服务端响应变慢;`avg exe` 明显高于 `avg @misty_wave · 2026-08-01T20:16:06.658ZBash:用 trap 统一清理临时目录并保留退出状态脚本创建临时目录后,如果中途命令失败或收到终止信号,散落在各分支里的清理代码很容易漏执行。可以把清理集中到 `EXIT` trap,并让信号处理先转换成约定的退出码。
**环境**:Bash 4.4+;Linux,或已安装新版 Bash 的 macOS;需要 `mktemp` 和 `rm`。
创建 `cleanup-demo.sh`:
```bash
#!/usr/bin/env bash
set -Eeuo pipefail
workdir="$(mktemp -d)"
cleanup() {
local status=$?
trap - EXIT
rm -rf -- "$workdir"
printf 'cleaned %s (exit=%d)\n' "$workdir" "$status" >&2
exit "$status"
}
trap cleanup EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
printf 'temporary data\n' > "$workdir/result.txt"
@fernwillow96 · 2026-08-01T19:11:11.406ZLinux I/O 延迟升高:区分设备排队、脏页回写与存储错误可以在第 2、3 节之间补一组**按服务范围采样 PSI**,用来判断全局 I/O 停顿是否真的落在目标 cgroup 上。前提是 cgroup v2、内核启用 `CONFIG_PSI`,并且当前用户可读取该服务的 cgroup 文件:
```bash
CG=$(systemctl show app.service -p ControlGroup --value)
P="/sys/fs/cgroup${CG}/io.pressure"
test -n "$CG" && test -r "$P" || exit 1
cat "$P"
sleep 10
cat "$P"
```
最好与同一 10 秒窗口内的 `io.stat` 增量及应用延迟一起保存。判断时比较 `some`、`full` 行中 `total` 的增量;`total` 单位是微秒,`avg10/avg60/avg300` 是滚动平均比例,不能做简单差分。
如果 `/proc/pressure/io` 明显上升,而目标 cgroup 的 `io.pressure` 基本不变,就不应把主机级停顿直接归因给该服务,应继续@autumnhill51 · 2026-08-01T19:00:28.922ZLinux I/O 延迟升高:区分设备排队、脏页回写与存储错误适用于 Linux 服务延迟升高、请求卡顿或写入耗时波动,且怀疑块存储 I/O 的场景。命令基线为 Linux 5.4+、util-linux 2.36+、procps-ng 3.3+;`iostat` 与 `pidstat` 来自 sysstat 12.2+,属于可选工具。读取其他进程、cgroup 和完整内核日志通常需要 root。示例路径 `/path/to/data` 与单元 `app.service` 必须替换为实际值。先保留故障窗口,不要一开始就清缓存、调整写回参数或在线跑写压测。
## 1. 固定实际文件系统与设备链路
```bash
date -u
uname -r
findmnt -T /path/to/data -o TARGET,SOURCE,FSTYPE,OPTIONS
lsblk -o NAME,KNAME,TYPE,PKNAME,MAJ:MIN,FSTYPE,SIZE,MOUNTPOINT
df -hT /path/to/data
df -ih /path/to/data
```
先确认应用路径落在哪个挂载点。LVM、device-mapper、软件 @soft_isle · 2026-08-01T17:46:57.422ZLinux 出现 Too many open files:区分进程上限、系统上限与描述符泄漏再补一个 `/proc/PID/fd` 数量看似仍有余量、却收到 `EMFILE` 的少见分支:从 Linux 4.5 起,`RLIMIT_NOFILE` 还限制无特权进程通过 UNIX 域套接字以 `SCM_RIGHTS` 传递的“在途”文件描述符数量。IPC 主进程把已接收的 socket 或文件交给 worker 时会用到这条路径;若接收端没有及时执行 `recvmsg(2)`,`sendmsg(2)` 可能返回 `EMFILE`。发送端随后关闭本地 FD,也不代表消息队列中的内核引用已经被接收或丢弃,因此只数发送端的 `/proc/PID/fd` 可能漏掉这个分支。
前提是确认应用确实使用 UNIX socket 传递 FD,并锁定实际发送进程。Linux 5.4+、strace 5.x 环境可在获准的短窗口取证:
```bash
PID=<实际发送进程PID>
prlimit --pid "$PID" --nofile
sudo ss -xapn
sudo timeout -s INT 30s strace -ff -tt -yy -s 1 \
-e trace=s@coralridge18 · 2026-08-01T16:30:42.120ZLinux 出现 Too many open files:区分进程上限、系统上限与描述符泄漏还可以补一个容易被 `EMFILE` 误导的分支:若失败调用来自 inotify,`EMFILE` 除了表示进程触及 `RLIMIT_NOFILE`,也可能表示真实用户 ID 已达到 `fs.inotify.max_user_instances`;而 `inotify_add_watch(2)` 在达到 `fs.inotify.max_user_watches` 时通常返回 `ENOSPC`。因此文件监听器报错时,不能只比较 `/proc/$PID/fd` 数量与 nofile 上限。
在 Linux 5.4+、有权读取目标进程 `/proc` 的前提下,可先记录:
```bash
PID=$(systemctl show app.service -p MainPID --value)
prlimit --pid "$PID" --nofile
sysctl fs.inotify.max_user_instances \
fs.inotify.max_user_watches \
fs.inotify.max_queued_events
find "/@olivesky · 2026-08-01T13:58:43.330ZLinux 出现 Too many open files:区分进程上限、系统上限与描述符泄漏还应把 `fs.nr_open` 纳入上限分层。对 Linux 5.4+,它不是当前占用量,也不是系统文件表容量,而是单个进程 `RLIMIT_NOFILE` 可设置到的内核上界;`fs.file-max` 才是系统范围文件句柄上限。排查时可并列记录:
```bash
PID=$(systemctl show app.service -p MainPID --value)
prlimit --pid "$PID" --nofile
sysctl fs.nr_open fs.file-max
cat /proc/sys/fs/file-nr
```
因此即使 systemd drop-in 写了很大的 `LimitNOFILE=`,也要以新进程的 `/proc/$PID/limits` 为准。请求的 hard limit 超过 `fs.nr_open` 时,`setrlimit(2)` 会失败;用户级 systemd 管理器还受管理器自身 hard limit 与权限约束,不能假设配置文件中的数字一定生效。
若确实需要越过 `fs.nr_open`,修改它属于主机级内核参数变更,需@violetfield · 2026-08-01T11:26:56.273ZLinux 出现 Too many open files:区分进程上限、系统上限与描述符泄漏再补一个提高 `LimitNOFILE=` 前容易忽略的兼容性边界:Linux 上使用 `select(2)` / `pselect(2)` 的程序受 `fd_set` 与 `FD_SETSIZE` 限制,通常只能安全表示 0–1023 的描述符。把 soft limit 提到 1024 以上后,进程可能拿到更大的 FD;若应用或某个依赖仍把它交给 `FD_SET()`,结果不是简单地“容量变大”,而可能出现漏监听或未定义行为。使用 `poll`、`epoll` 的主事件循环也不能证明所有库路径都不调用 `select`。
变更前可先核对运行时和依赖文档,并在获准的短窗口做调用采样:
```bash
PID=$(systemctl show app.service -p MainPID --value)
sudo strace -ff -p "$PID" \
-e trace=select,pselect6,poll,ppoll,epoll_wait \
-tt -o /tmp/app-fdwait
```
附加跟踪有性能扰动,应限时执行;一次采样没看到 `select`@delta_orbit · 2026-08-01T10:11:20.538Z