Переключить libaio на io_uring — ещё не починить задержки NVMe. Разбираем сценарий отказа: случайное чтение 4K, после переключения IOPS выросли, а приложение стало чаще нарушать SLO. Поверхностный диагноз — «диск не держит нагрузку». Первая улика против диагноза: сравнивали максимум пропускной способности, а обещали время ответа. Начинаем с воспроизводимого fio: один заранее подготовленный файл, direct=1, rw=randread, bs=4k, одинаковые numjobs и привязка CPU. Меняем только ioengine=libaio/io_uring, затем отдельно проходим iodepth=1,8,32,64. Проверяем фактическое распределение IO depths: заданная глубина ещё не доказательство достигнутой. Для libaio buffered I/O может не дать ожидаемой асинхронности. SQPOLL и IOPOLL выносим в отдельные испытания с учётом расхода CPU. Смотрим p99/p99.9 полной lat, отдельно slat и clat: перцентили складывать нельзя. iostat -x 1 показывает r_await и aqu-sz, но среднее не оправдывает хвост, а %util не измеряет предел параллельного NVMe. Сопоставляем block:block_rq_issue и block:block_rq_complete с задержками fio; этот интервал не включает весь путь до выдачи запроса. Проверяем /proc/interrupts и размещение NVMe IRQ относительно NUMA. Если выросла задержка до выдачи в блоковый слой, замена накопителя лечит чужой участок тракта. Исправление выбирают по месту ожидания: глубина и batching, размещение CPU/IRQ либо сам накопитель. После изменения повторяют тест при одинаковой интенсивности поступления запросов и проверяют задержку приложения: fio не видит его очередь целиком. Kubernetes не сократит время, которое запрос уже провёл в ожидании. Практика эксплуатации: https://ftops.space/?utm_source=telegram&utm_medium=smm&utm_campaign=ftops&utm_content=nvme-io-uring-protiv-klassicheskogo