Worker进程卡D状态本质是等待内核完成不可中断磁盘I/O,需通过ps+stack确认阻塞点、iotop定位IO源、dmesg/smartctl检查硬件健康,并临时调worker_processes、禁用同步写缓解,长期优化挂载参数与IO调度。

Worker 进程卡在 D 状态,本质是它正等待内核完成某次磁盘 I/O 操作,且该等待不可被信号中断。这不是进程崩溃,也不是配置错误,而是底层 I/O 链路出现实质性阻塞。排查必须从内核态出发,跳过 CPU 和内存表象,直击 I/O 路径。
第一步:确认 D 状态是否真由磁盘引起
别一看到 D 就急着调 Nginx 或重启服务。先做快速过滤:
- 用 ps aux | awk '$8 ~ /^D$/ {print $0}' 列出所有 D 态进程,重点关注 nginx worker、php-fpm、Go 二进制或容器主进程
- 对每个可疑 PID,执行 cat /proc/PID/stack(需 root)。若栈中出现 blk_mq_do_dispatch_sched、__wait_on_bit、ext4_writepages、nvme_queue_rq 或 __generic_file_read,基本锁定为块设备或文件系统层阻塞
- 同时运行 iostat -x 1:若 %util 接近 100%、await > 50ms,而 r/s 或 w/s 却很低,说明请求在队列里堆积,不是吞吐高,而是响应慢
第二步:定位真实 I/O 发起者
D 是结果,不是源头。真正拖慢磁盘的是背后那个反复读写、刷盘或同步的进程:
- 运行 sudo iotop -o -P,按 I/O% 排序,找出当前正在发起实际读写的进程(注意看 IO_RATE 列,不是 CPU%)
- 常见“隐形推手”包括:logrotate 定时 truncate 大日志、rsync 未限速同步、MySQL 的 innodb_flush_log_at_trx_commit=1 + 高频小事务、PHP 在 /tmp 下高频创建/删除 session 文件
- 对高 I/O 进程执行 lsof -p PID | grep -E "(REG|DIR)",重点看它是否在反复 open/write 同一个大文件(如 access.log、pg_wal/、/tmp/*.sess)
第三步:检查存储层健康与挂载状态
很多 D 状态持续存在,根本原因是硬件、驱动或远程存储异常:
- 运行 dmesg -T | tail -50,搜索 timeout、I/O error、ata、nvme、nfs 等关键词
- 查磁盘健康:smartctl -a /dev/sdX(需安装 smartmontools),关注 Reallocated_Sector_Ct、Pending_Sector 和 UDMA_CRC_Error_Count
- 若用 NFS/CIFS:mount | grep nfs 看挂载参数;showmount -e server 测试服务端可达性;卡死时可用 umount -f -l /mnt/nfs 懒卸载
- 若跑在 Docker 中,检查 df -h /var/lib/docker 是否满,再用 ls -la /var/lib/docker/overlay2/*/merged 看是否有权限异常或元数据损坏迹象
第四步:临时缓解与长期规避
目标不是“杀死 D 进程”,而是让 worker 尽快脱离阻塞,恢复服务响应:
- 立即降低争抢强度:HDD 环境临时将 worker_processes 设为 2~4;SSD 可试 4~6,避免多 worker 同时触发随机寻道
- 禁用高频同步写:注释掉 Nginx 的 access_log 行,或改用带缓冲的写法:access_log /path/to/access.log buffer=64k flush=5s;PHP 日志改走 syslog,交由 rsyslog 异步刷盘
- 长期预防:关键挂载点启用 errors=remount-ro(ext4)、NFS 加 soft,timeo=10,retrans=3;I/O 密集任务用 ionice -c2 -n7 降级调度优先级

















