关键不是加速读取,而是让worker进程永远不等磁盘:aio负责发起不卡,thread_pool负责做完不回挤;二者协同且仅在sendfile off、directio启用、文件≥阈值、显式绑定线程池时生效。

必须满足的触发条件
光开 aio 或配 thread_pool 都无效,以下四点缺一不可:
- sendfile off:内核零拷贝会绕过用户态读取,线程池根本没机会介入
- 启用 directio(如 directio 4m):小文件走 page cache 一般不阻塞;只有 ≥ 阈值的大文件直读磁盘时,才需要异步卸载
- 文件路径真实触发 open/read:alias、root 返回静态文件、gzip_static off 读 .gz、proxy_cache 未命中等场景才走该路径;SSL 证书加载、日志写入也适用,但需单独配置
- aio threads=xxx 显式绑定:只写 aio on 或 aio threads; 不生效;必须指向已在 main 块定义好的池名
thread_pool 的正确配置方式
它不是加个线程数就行,而是要可控、可测、有边界:
- 定义在 main 块最外层,不能放在 http、server 或 events 里,否则 Nginx 启动报错
- threads 数量按磁盘能力设:SSD 建议 32~64;HDD 或 NFS 可设 24~32;超 64 易引发上下文切换开销
- max_queue 推荐 ≤8192:太大掩盖真实瓶颈,太小易丢任务;可通过 error_log debug 查 "aio thread queue full" 判断是否溢出
- 不同用途建议分池命名:比如 static_io、cache_io、log_io,避免混用导致关键路径被低优先级任务拖慢
验证是否真起效的两个硬指标
别只看 QPS 或平均延迟,盯住这两个系统级信号:
- worker 进程 S 态占比 :用 top -p `pgrep nginx` 或 pidstat -p `pgrep nginx` 观察;开启前若常驻 20%+,开启后回落即说明 I/O 已剥离
- 线程池队列等待时间 :Nginx Plus 可直接监控 thread_pool default queue;开源版可通过自定义日志埋点或 /proc/xxx/stat 计算入队到执行耗时
常见失效原因与避坑提醒
很多配置看似正确,实则静默失效:
- 系统没装 libaio:Ubuntu/Debian 执行 apt install libaio1;CentOS 执行 yum install libaio;否则 thread_pool 任务直接失败,无报错
- 文件小于 directio 阈值:比如设了 directio 4m,但请求的是 2MB 文件,仍走同步 read()
- 用了 alias 却没关 sendfile:alias 路径默认可能触发 sendfile,必须显式 sendfile off;
- 回调里做 CPU 操作:比如在 AIO 完成后立刻解析 JSON、拼接日志,等于又把负载塞回 worker —— 正确做法是只投递轻量 task 到 thread_pool











