В 03:00 NVMe назначили виновным по графику задержек чтения. Учебный постмортем: после замены libaio на io_uring средняя задержка выглядит прилично, но p99 случайного чтения 4K пробивает бюджет. Рабочая гипотеза — поток, принимающий результаты, конкурирует за CPU. Быстрый накопитель не выдаёт процессу внеочередной квант планировщика. Сначала честный A/B на существующем тестовом файле: for e in libaio io_uring; do fio --name=read4k --filename=/mnt/nvme/readset --readonly --rw=randread --bs=4k --direct=1 --ioengine=$e --iodepth=1 --numjobs=1 --time_based=1 --runtime=60 --ramp_time=10 --lat_percentiles=1 --percentile_list=99:99.9 --group_reporting; done. Затем отдельно повторить с глубиной 32. Фиксируем ядро, fio, CPU affinity и фон; проверяем достигнутую глубину. Сравниваем total lat, slat и clat: граница между подачей и ожиданием completion зависит от движка и режима. Одного clat для приговора недостаточно. Разделяем очередь устройства и ожидание CPU: iostat -x 1 показывает await и aqu-sz, но среднее await не оправдывает хвост. sudo perf sched record -- sleep 30, затем sudo perf sched latency помогают увидеть задержки планирования. В cgroup приложения проверяем дельты nr_throttled и throttled_usec в cpu.stat. Интервалы block_rq_issue → block_rq_complete сопоставляем с задержкой приложения, учитывая слияния запросов. Если блочный путь стабилен, а задержка планирования растёт, покупка NVMe лечит бюджет поставщика. SQPOLL опрашивает очередь подачи; IOPOLL — отдельный режим опроса завершений с требованиями к стеку. Ни один не гарантирует выигрыш p99 под конкуренцией за CPU. Выбирать API нужно по воспроизводимому профилю нагрузки и стоимости CPU, а не по свежести названия. Эксплуатация bare metal: https://ftops.space/?utm_source=telegram&utm_medium=smm&utm_campaign=ftops&utm_content=nvme-io-uring-protiv-klassicheskogo.