Почему NVMe не всегда ускоряет сайт: смотрим на latency, p95/p99 и профиль нагрузки

от автора

У дисковой подсистемы слишком хорошая репутация в тарифных таблицах и не самая однозначная в инженерных обсуждениях. В первом случае нам продают гигабайты в секунду, во втором часто говорят, что для веба диск почти не важен.

Я работаю контент-маркетологом в Scalehost и по работе регулярно разбираю темы, связанные с производительностью веб-проектов. Вопрос “нужен ли сайту NVMe или это просто маркетинговая галочка” возникает так часто, что мне захотелось собрать его в один технически внятный разбор.

На практике обе крайности слишком упрощают картину. Для веб-проекта важно как он ведет себя на мелком random I/O, при параллельных запросах и под нагрузкой. Когда начинают вылезать не средние значения, а хвосты задержек.

Предлагаю разобрать, какие дисковые метрики действительно коррелируют с TTFB и стабильностью отклика. Почему для веба важнее latency и tail latency, чем красивые цифры последовательного чтения. И в каких сценариях переход с SATA на NVMe реально дает эффект, а в каких почти не влияет на поведение сайта.

Почему для веба важнее latency и поведение под нагрузкой, чем последовательные MB/s

Когда в описании сервера пишут “до 3 500 МБ/с” или “до 7 000 МБ/с”, почти всегда речь идет о последовательном чтении больших блоков данных. Для диска это понятный сценарий. Он читает длинный непрерывный участок и тратит минимум усилий на переключение между операциями.

Веб-проект работает немного иначе. Динамическая страница редко упирается в один длинный поток чтения. Намного чаще сервер обрабатывает множество коротких и разнородных операций. Например, прочитать несколько файлов, обратиться к индексам базы данных, записать что-то в журнал, отработать временные файлы и параллельно обслужить другие запросы.

В такой нагрузке на первый план выходит не пиковая скорость интерфейса, а то, насколько быстро диск отвечает на отдельные операции и насколько хорошо держит параллельный I/O без резкого роста задержек.

Поэтому для веба полезнее смотреть не только на мегабайты в секунду, а на три других вещи:

  • latency — сколько времени занимает одна операция чтения или записи;

  • queue depth — сколько операций диск может обрабатывать одновременно без заметной деградации;

  • поведение под нагрузкой — насколько сильно растут задержки, когда запросов становится много.

Разница между SATA и NVMe проявляется как раз здесь. SATA исторически создавался в логике более простого и ограниченного стека: небольшая глубина очереди, выше накладные расходы на каждый запрос, хуже масштабирование при росте параллельности. Для одиночных или последовательных операций этого может быть достаточно. Но когда запросов много и они мелкие, диск начинает чаще “спотыкаться” о собственные ограничения.

Источник: phoenixNAP

Источник: phoenixNAP

NVMe проектировался уже под флеш-память и параллельную обработку I/O. Поэтому его преимущество для веба не столько в гигабайтах в секунду, сколько в более низкой задержке и более предсказуемом поведении под нагрузкой. 

Для сайта важнее стабильность отработки сотни и тысячи коротких операций, из которых и складывается реальный отклик приложения.

Что типичный HTTP-запрос делает с диском?

Если смотреть на сайт как на цепочку внутренних операций, становится понятнее, почему дисковая подсистема вообще влияет на TTFB. Даже относительно обычный запрос к динамической странице может включать в себя несколько шагов подряд:

  1. веб-сервер принимает запрос и передает его приложению;

  2. приложение читает конфигурацию, шаблоны, служебные файлы или кэш;

  3. PHP, Python или другой runtime обращается к базе данных;

  4. база читает индексы и страницы таблиц;

  5. по ходу запроса могут выполняться записи в журнал, временные файлы или служебные операции;

  6. параллельно в той же системе идут другие запросы, фоновые задачи, очереди, cron-процессы.

Каждая из этих операций сама по себе может быть очень маленькой. Но проблема в том, что для пользователя важна не одна операция, а вся цепочка целиком. Если на каждом шаге диск добавляет пусть небольшую, но ненулевую задержку, в сумме это превращается в заметные миллисекунды TTFB.

Здесь и кроется типичная ошибка при оценке диска для веба. Смотреть на него как на устройство, которое должно быстро “качать мегабайты”. Для сайта куда важнее как диск ведет себя на мелком random I/O, как растут задержки при увеличении числа одновременных операций и насколько стабильно система переживает пики нагрузки.

Поэтому вопрос “поможет ли NVMe” лучше ставить так: “Есть ли в моем проекте много мелких I/O-операций и начинает ли диск быть узким местом под параллельной нагрузкой?”

Если ответ на вопрос положительный, разница между SATA и NVMe обычно начинает проявляться гораздо отчетливее, чем это видно по маркетинговым таблицам.

Что в этой статье считать “веб-профилем нагрузки”

Когда говорят, что для веба важны не красивые MB/s, а latency и поведение под нагрузкой, возникает вопрос: а какой профиль вообще считать близким к реальному сайту?

Для динамического веб-проекта обычно показательны не длинные последовательные чтения, а множество коротких операций. Random read, mixed read/write, работа с мелкими блоками и умеренная параллельность. 

Это не означает, что любой HTTP-запрос один в один повторяет fio-профиль. Но такие тесты хотя бы ближе к реальной картине, чем сценарий, где диск просто читает большой непрерывный файл с максимально возможной скоростью. Поэтому в контексте веба обычно имеет смысл смотреть на:

  • мелкие блоки, например 4k;

  • random read и mixed randrw;

  • низкую и среднюю глубину очереди — QD1, QD4, иногда QD16;

  • не только IOPS, но и p95/p99 latency.

В таких режимах становится видно, где диск действительно влияет на отклик приложения, а где цифры из спецификации почти не доходят до пользователя.

Профиль теста

Что показывает

Насколько это близко к вебу

Последовательное чтение больших блоков

Пиковую пропускную способность

Слабо похоже на типичную динамическую страницу

4k randread QD1

Базовую latency на мелком чтении

Хорошо показывает чувствительность к коротким I/O

4k randread QD4

Поведение при умеренной параллельности

Уже ближе к реальной веб-нагрузке

4k randread QD16

Реакцию на конкурирующие обращения к диску

Полезно для пиков и многопоточности

randrw (смешанный профиль)

Как диск держит одновременное чтение и запись

Хорошо подходит для БД, логов и фоновых операций

Почему это особенно заметно не в среднем, а в “плохих” запросах?

Среднее время ответа почти всегда выглядит лучше, чем реальные ощущения пользователя. Сайт может показывать приличный average response time, но при этом часть запросов будет периодически “подвисать”. Это и формирует ощущение нестабильной работы.

Часто смотрят не только на среднее значение, но и на так называемые p95 и p99:

  • p95 означает, что 95% запросов укладываются в это время, а оставшиеся 5% — медленнее;

  • p99 — что 99% запросов быстрее этого значения, а 1% — еще медленнее.

Именно этот “плохой хвост” чаще всего и связан с очередями, параллельностью и поведением диска под нагрузкой. На SATA такие хвосты обычно растут раньше: в спокойном режиме система может работать нормально, но как только запросов становится больше, часть операций начинает заметно замедляться. На практике это выглядит как плавающий отклик, нестабильная работа фильтров, медленное открытие сложных страниц или внезапно долгий checkout.

NVMe не всегда делает сайт кратно быстрее в среднем, но часто заметно улучшает именно предсказуемость поведения: уменьшает разброс задержек и делает “плохой хвост” короче. Для eCommerce, личных кабинетов, API и любых нагруженных динамических сценариев это часто важнее, чем красивое среднее число в отчете.

Когда NVMe действительно нужен, а когда почти ничего не меняет

У NVMe нет магического свойства ускорять сайт сам по себе. Его эффект зависит от того, попадает ли диск в критический путь обработки запроса.

NVMe дает заметную пользу там, где приложение регулярно упирается в мелкий случайный I/O, чувствительно к параллельным обращениям к диску и начинает страдать не столько от среднего времени ответа, сколько от хвостов задержек под нагрузкой. 

Это хорошо совпадает и с архитектурой интерфейсов. У AHCI/SATA очередь команд намного уже, а у NVMe изначально заложена масштабируемая модель с большим числом I/O queues и большим числом outstanding commands на очередь. 

Для веба это важно не на уровне абстрактных спецификаций, а в тех сценариях, где запросов много, операции короткие, а задержки начинают расти именно при конкуренции за I/O.

Где NVMe дает реальный эффект

1. Проект активно работает с базой данных, и часть чтений регулярно уходит на диск.

Чем чаще приложение дергает индексы, страницы таблиц, временные структуры и журналы, тем сильнее итоговый отклик зависит от latency, а не MB/s. Для каталогов, фильтров, поиска, страниц с большим числом SQL-обращений и других динамических сценариев это особенно заметно. Здесь NVMe полезен как более предсказуемый инструмент для большого числа коротких операций.

2. Нагрузка параллельная, и в системе много одновременных запросов.

В спокойном режиме разница между SATA SSD и NVMe может быть не сильно ощутимой. Но когда одновременно идут веб-запросы, обращения к БД, фоновые задачи, логирование и служебные операции, узкая очередь и больший накладной путь AHCI начинают проявляться сильнее. В таких условиях NVMe чаще дает более ровное и предсказуемое поведение.

3. Важна не только средняя скорость, но и стабильность p95/p99.

Если пользователи жалуются на то, что сайт иногда подвисает, смотреть нужно не только на average response time. В fio процентильная статистика как раз показывает, какое время укладывается в X-й процентиль. Иными словами, p95/p99 помогают увидеть тот самый “плохой хвост” задержек, который и воспринимается как нестабильность. Для проектов, чувствительных к этим хвостам, NVMe часто ценен именно тем, что сглаживает разброс latency под нагрузкой.

4. Есть заметная смешанная нагрузка: чтение плюс запись.

В реальном веб-стеке диск не только читает. База журналирует транзакции, сервисы пишут логи, приложение работает с временными файлами, а фоновые процессы конкурируют за ресурсы. Чем ближе профиль к mixed I/O, тем важнее становится то, как система держит много коротких операций одновременно. Здесь NVMe обычно раскрывается лучше, чем в синтетике с последовательным чтением.

Где переход на NVMe даст мало эффекта

1. Рабочий набор данных базы в основном помещается в RAM.

В MySQL/InnoDB таблицы и индексы кэшируются в buffer pool в оперативной памяти, и часто используемые данные могут обслуживаться прямо из памяти. В документации MySQL это описано прямо: буферный пул хранит данные таблиц и индексов в оперативной памяти, и чем он больше, тем больше InnoDB напоминает базу данных, работающую в памяти. В таком сценарии тип диска не исчезает совсем, но его влияние на пользовательский отклик становится заметно ниже.

2. Проект агрессивно кэшируется.

Если большая часть трафика обслуживается из full-page cache, object cache или другого верхнего слоя кэширования, до диска в критическом пути запроса доходит уже не так много операций. Тогда переход на NVMe может улучшить отдельные внутренние процессы, но пользователь увидит разницу только в части сценариев, и то не всегда.

3. Узкое место уже не в I/O, а выше по стеку.

Если проект упирается в CPU, PHP-логику, медленные SQL-запросы как таковые, внешние API или сеть, замена SATA на NVMe не уберет главную причину деградации. Это как раз тот случай, когда быстрее становится компонент, который не определяет итоговый TTFB.

4. Сайт небольшой и с низкой параллельностью.

Для небольшого проекта без тяжелых запросов, с малым числом одновременных пользователей и хорошим кэшем разница между современным SATA SSD и NVMe может быть очень скромной. NVMe все равно остается более технологичным и устойчивым выбором, но пользовательский эффект в таком сценарии часто меньше, чем ожидают после чтения тарифных таблиц.

Сценарий

Эффект от NVMe

Почему

Большой каталог, фильтры, поиск, много SQL-обращений

Высокий

Много мелких random I/O и чувствительность к latency

Параллельные запросы, API, checkout, фоновые задачи

Высокий

Под нагрузкой важны queue depth и tail latency

Смешанная нагрузка read/write

Средний-высокий

Играет роль не скорость чтения, а поведение под конкурирующим I/O

Большая buffer pool / hot data в RAM

Низкий–средний

Значимая часть чтений обслуживается из памяти

Full-page cache и мало динамики

Низкий

Диск редко попадает в критический путь запроса

Bottleneck в CPU, коде, сети или внешних API

Низкий

Ускоряется не тот слой, который ограничивает отклик

На практике все сводится к одному вопросу: участвует ли диск в критическом пути запроса и страдает ли проект от tail latency под нагрузкой? Если да, NVMe почти всегда дает более предсказуемое поведение и меньший разброс задержек. Если нет, переход может оказаться технически приятным, но почти незаметным для пользователя.

Почему один и тот же NVMe в продакшене может вести себя по-разному 

Даже если на двух серверах формально стоит один и тот же класс NVMe-накопителя, результат в реальной эксплуатации может заметно различаться. Причина в том, что диск работает не сам по себе, а внутри конкретной платформы:

  • гипервизор, 

  • файловая система, 

  • CPU, 

  • память, 

  • лимиты I/O, 

  • соседние виртуальные машины 

  • и фоновые процессы тоже влияют на итоговый отклик.

Особенно это заметно в VPS и облачных средах. На бумаге можно получить NVMe storage, но в реальности итоговая картина будет зависеть от того, общий ли это storage, насколько жестко изолированы клиенты, как работает кэш гипервизора и нет ли конкуренции за ресурсы в пиковые моменты. Один и тот же тип диска в тарифе еще не гарантирует одинаковый TTFB на двух разных площадках.

Для веб-проекта это важный момент. Если смотреть только на модель накопителя, легко переоценить влияние диска и недооценить влияние самой платформы.

Фактор платформы

Что происходит на практике

Как это влияет на вывод

Общий storage в VPS/облаке

Несколько клиентов делят одну подсистему хранения

Быстрый NVMe может вести себя нестабильно

Noisy neighbors

Соседняя нагрузка создает конкуренцию за I/O

Растут хвосты latency и плавает отклик

Кэш гипервизора

Часть операций выглядит быстрее, чем есть на самом деле

Синтетика может приукрашивать картину

Лимиты I/O

Платформа искусственно ограничивает throughput или IOPS

Потенциал диска не доходит до приложения

Слабый CPU или нехватка RAM

Узкое место смещается выше по стеку

NVMe есть, а пользователь не видит прироста

Как проверять это у себя, а не верить тарифам

Проблема большинства дисковых бенчмарков в том, что они отвечают на иной вопрос. Когда утилита показывает впечатляющие мегабайты в секунду, она обычно измеряет предельную пропускную способность на упрощенном профиле нагрузки. Для веб-проекта этого почти никогда недостаточно. 

Что показывают

Почему этого мало

Последовательное чтение/запись в MB/s

Это хороший сценарий для диска, но не типичный профиль веб-запроса

Средний IOPS

Среднее значение скрывает “плохой хвост” и не показывает нестабильность

Один синтетический прогон

Не видно, как диск ведет себя при смешанной нагрузке и росте параллельности

Только p50/average

Пользователь чаще замечает p95/p99, а не среднее время ответа

Минимальная практическая схема состоит из двух частей: 

  • проверяем поведение диска на профиле, похожем на веб-нагрузку,

  • смотрим, отражается ли это на реальных страницах и запросах.

Для первой части удобен fio. Он позволяет задать random read, mixed randrw, размер блока 4k, разные значения iodepth и получить не только IOPS, но и latency percentiles. Это важно, потому что iodepth отражает число операций в полете, а процентильная статистика показывает, где начинается тот самый плохой хвост задержек. Именно эта комбинация ближе к реальным I/O-сценариям веб-приложения, чем сухая цифра до “X ГБ/с”.

Простейший тест можно начать с QD1 и QD4. Они лучше показывают, как диск ведет себя в условиях низкой и умеренной параллельности. Затем имеет смысл посмотреть QD16, чтобы понять, насколько растут задержки под конкурирующей нагрузкой. Смотреть нужно не только на IOPS, но и на p50/p95/p99. Если разница между SATA и NVMe есть только в пиковом throughput, но почти не видна в хвостах latency, для веб-проекта это тревожный сигнал. Пользователь может почти не заметить такую победу в синтетике.

fio --name=4k-randread \

--filename=/dev/nvme0n1 \

    --rw=randread \

    --bs=4k \

    --iodepth=1 \

    --ioengine=libaio \

    --direct=1 \

    --runtime=60 \

    --time_based \

    --group_reporting

Что смотреть в продакшене, кроме fio

fio полезен как технический ориентир, но он не отвечает на вопрос о проекте целиком. Даже если тест показал хорошую latency на 4k random read, это еще не означает, что приложение действительно упрется в диск именно так, как ожидается. Поэтому после синтетики важно посмотреть и на поведение системы в боевых или хотя бы близких к боевым условиях.

В продакшене имеет смысл следить не только за самим диском, но и за тем, как его поведение отражается на приложении, базе данных и конечном отклике страницы. Иначе можно получить красивый результат в fio и не увидеть почти никакой разницы на реальном сайте.

Метрика

Что показывает

Зачем нужна

p95/p99 TTFB

Насколько длинным становится “плохой хвост” отклика

Помогает увидеть нестабильность, а не только среднее

iowait

Долю времени, когда CPU ждет I/O

Показывает, не начинает ли диск тормозить систему

p95/p99 latency базы

Как растут задержки SQL-запросов под нагрузкой

Помогает понять, не уходит ли деградация в БД

Hit ratio кэша / buffer pool

Какая часть чтений обслуживается из памяти

Объясняет, насколько проект вообще зависит от диска

Поведение под ростом параллельности

Как система реагирует на увеличение числа одновременных запросов

Позволяет увидеть, где начинается деградация

Ошибки и таймауты в пике

Переходит ли деградация в реальную нестабильность

Важный индикатор для продакшена

Для второй части важно посмотреть уже на сам проект. Для второй части важно посмотреть уже на сам проект: выбрать 2-3 динамические страницы без полного page cache, прогнать нагрузку на нескольких уровнях параллельности и замерить не только средний TTFB, но и p95/p99 по этим страницам. Если после перехода на NVMe уменьшается именно плохой хвост и сайт ведет себя ровнее в пике, это гораздо более честный аргумент, чем любой маркетинговый бенчмарк. И наоборот: если p95/p99 почти не сдвинулись, скорее всего, bottleneck живет не в диске.

Что мерить

Зачем

fio 4k randread QD1

Базовая latency на мелком чтении

fio 4k randread QD4/QD16

Поведение под умеренной и высокой параллельностью

fio randrw

Смешанный профиль ближе к реальному стеку

p50/p95/p99 latency

Понять не только среднее, но и «плохой хвост»

TTFB на динамических страницах

Проверить, доходит ли разница до пользователя

Нагрузка без полного page cache

Исключить ложный комфорт от кэша

Короткий прикладной сценарий: где это проявляется на реальном сайте 

Возьмем пример: страница каталога с фильтрами в интернет-магазине. Пользователь открывает категорию, меняет несколько фильтров, запускает поиск по параметрам, а система параллельно обслуживает десятки похожих запросов от других пользователей.

На уровне приложения это не выглядит как один большой поток чтения. 

Здесь есть обращения к индексам базы, чтение части данных с диска, работа с кэшем, временными структурами, журналированием и фоновыми процессами. 

Пока нагрузка умеренная, SATA SSD может показывать вполне приемлемое среднее время ответа. Но по мере роста параллельности система начинает терять ровность: среднее значение еще не выглядит пугающим, а p95/p99 уже растут заметно быстрее.

Именно в таких сценариях NVMe проявляет себя как более предсказуемая подсистема хранения. Пользователь видит это не в виде рекордных цифр на графике throughput, а в виде меньшего числа подвисаний, более ровной работы фильтров и менее рваного отклика в пиковые часы.

Быстрый диск — не быстрый сайт

Для веб-проекта вопрос редко звучит как “какой диск быстрее по паспорту”. На практике полезнее  задаваться другими критериями:

  1. участвует ли диск в критическом пути запроса, 

  2. растут ли хвосты p95/p99 под нагрузкой 

  3. действительно ли I/O остается узким местом после учета RAM, кэша, CPU и логики приложения.

Если ответ положительный, NVMe обычно дает не столько вау-ускорение, сколько более важную для продакшена вещь — более предсказуемое поведение системы. Если же горячие данные живут в памяти, проект хорошо кэшируется, а bottleneck давно ушел в CPU, код или внешние сервисы, переход на NVMe может оказаться технически приятным, но почти незаметным для пользователя.

ссылка на оригинал статьи https://habr.com/ru/articles/1031330/