Хранилище
Предпосылки: оперативная память (DRAM, row buffer, bandwidth vs latency).
← Оперативная память | Устройство flash | Шины и DMA →
Регистры, кеши и RAM объединяет одно свойство: при отключении питания данные исчезают. Для выполнения программы это нормально — загрузил, выполнил, результат отдал. Но база заказов на 500 ГБ должна переживать сбои: пользователь нажал «оплатить», транзакция зафиксирована, а через секунду в дата-центре пропало питание. Нужен носитель, который хранит данные без питания — энергонезависимый (non-volatile). Цена такой устойчивости — переход из мира наносекунд в мир миллисекунд или микросекунд.
Рынок делят две технологии одной проблемы. HDD (Hard Disk Drive, жёсткий диск) хранит данные как намагниченные участки на вращающихся пластинах: ёмко и дёшево, но случайный доступ стоит миллисекунды — упирается в механику. SSD (Solid State Drive, твердотельный накопитель) хранит данные в полупроводниковых ячейках без движущихся частей: случайный доступ в 150–200 раз быстрее, но ячейки изнашиваются при записи. Оба на порядки медленнее оперативной памяти. Разница в том, что HDD выставил правила игры на десятилетия — последовательное чтение на сотни раз быстрее случайного — а SSD эти правила переписал, и теперь базы данных живут по-другому. Ограничения HDD первичны: из них выросли архитектурные решения, которые SSD ломает, — поэтому сначала HDD.
HDD: механика вращающихся пластин
Данные в HDD хранятся как намагниченные участки на металлических пластинах (platters), вращающихся на общем шпинделе. Чтение и запись выполняет головка (read/write head), парящая над поверхностью на высоте ~10 нм. Поверхность разделена на концентрические дорожки (tracks), дорожки — на секторы (sectors) размером 512 Б или 4 КБ. Серверный диск содержит 2–5 пластин и вращается на 7200 RPM (Revolutions Per Minute, оборотов в минуту) или 15 000 RPM для высокопроизводительных массивов.
вид сверху на пластину
___________________________
/ ______sector______ \
| / _______________ \ |
| | / \ | |
| | | дорожка 0 | | | <-- головка
| | | дорожка 1 | | | двигается
| | | дорожка 2 | | | по радиусу
| | \ ______________/ | |
| \____________________/ |
\___________________________/
шпиндель
(ось вращения)
Чтобы прочитать конкретный сектор, HDD выполняет три физических действия, и каждое стоит времени.
Seek time (время позиционирования) — актуатор физически перемещает головку к нужной дорожке по радиусу пластины. Для серверного диска 7200 RPM: 8–12 мс случайно, 0.5–1 мс до соседней дорожки. Это механическое движение и нижняя граница латентности random I/O.
Rotational latency (задержка вращения) — после того как головка встала на дорожку, нужно дождаться нужного сектора под головкой. В среднем — половина оборота. При 7200 RPM полный оборот занимает 8.33 мс, половина — ~4.17 мс. При 15 000 RPM — ~2 мс.
Transfer time (время передачи) — само чтение данных с поверхности. Для 4 КБ на 7200 RPM — порядка 0.02 мс. Ничтожно по сравнению с seek и rotational latency.
Итого для случайного чтения 4 КБ на 7200 RPM: ~10 мс + ~4 мс + ~0.02 мс ≈ 14 мс. Для сравнения: чтение из DRAM — ~100 нс, разница ~140 000 раз. Seek и rotational latency доминируют настолько, что размер запроса почти не влияет на время: 4 КБ — ~14 мс, 64 КБ — ~14.3 мс, 256 КБ — ~15.4 мс. Почти вся латентность — ожидание, пока головка доберётся до места. Отсюда и правило HDD-ориентированных систем: если уж заплатил ~14 мс за позиционирование — прочитай побольше за один визит.
IOPS: сколько операций в секунду
Если одна случайная операция стоит ~14 мс, максимум случайных операций в секунду: 1000 мс / 14 мс ≈ 70 IOPS (Input/Output Operations Per Second — операций ввода-вывода в секунду). На практике серверный диск 7200 RPM выдаёт 75–100 IOPS random, 15 000 RPM — 180–210.
База данных обрабатывает запрос, и планировщик читает 1000 случайных страниц по 8 КБ (поиск по индексу, когда нужные строки разбросаны по диску). На HDD 7200 RPM это 1000 / 75 ≈ 13 секунд чистого ожидания I/O — один пользовательский запрос. Если в систему приходит 100 таких запросов в секунду, одного диска не хватает даже на один запрос за секунду. До эпохи SSD продакшен жил на RAID-массивах: RAID 10 из 8 дисков суммирует IOPS до 8 × 75 = 600 — позволяет обслуживать несколько запросов параллельно, но требует 8 дисков ценой половины ёмкости на зеркалирование.
Случайная запись подчиняется той же арифметике: seek + rotation + transfer, те же ~14 мс и ~70–100 IOPS. Но с одним нюансом. Системный вызов fsync — команда «действительно записать на диск, не держать в буфере», которую базы используют, чтобы данные пережили сбой питания — заставляет HDD дождаться, пока сектор физически окажется на пластине. С включённым аппаратным буфером запись принимается за ~0.1 мс, но содержимое буфера теряется при сбое. Честный fsync — ~14 мс. Журнал упреждающей записи базы (см. WAL — журнал упреждающей записи) требует именно честного fsync, поэтому latency коммита на HDD ≈ 14 мс, а транзакций в секунду — около семидесяти на один диск.
Последовательный доступ: другая арифметика
Если читать данные подряд, seek выполняется один раз, дальше головка остаётся на месте и поток идёт напрямую. Скорость последовательного чтения на HDD 7200 RPM — 150–200 МБ/с с внешних (быстрых) дорожек, 80–100 МБ/с с внутренних. Контраст со случайным: 75 IOPS × 4 КБ = 300 КБ/с против 150 МБ/с — разница около 500 раз. Это ещё более крутая версия того, что видно в RAM на row buffer hit/miss: там разница в 10–30 раз, потому что DRAM переключает строки электронно, а HDD — механически.
Этот разрыв определил архитектуру хранения данных на десятилетия. Log-structured подход в базах (последовательная дозапись изменений вместо перезаписи на месте, включая WAL — журнал упреждающей записи и log-structured merge tree), физическое упорядочивание таблицы по ключу кластерного индекса, выбор между sequential scan и index scan — всё это существует потому, что на HDD последовательное чтение на два-три порядка быстрее случайного.
Почему внешние дорожки быстрее внутренних? Пластина вращается с постоянной угловой скоростью — значит за один оборот под головкой проходит больше данных на длинной (внешней) дорожке, чем на короткой (внутренней). С зонной записью (Zoned Bit Recording, ZBR) внешние зоны содержат больше секторов на дорожку. Файловые системы и ОС об этом знают: «начало диска» (низкие LBA (Logical Block Address — логический адрес блока)) соответствует внешним, быстрым дорожкам.
I/O scheduler: попытка спрятать seek
400 КБ/с против 150 МБ/с — разрыв колоссальный. На сервере редко бывает один запрос: в очереди стоят десятки. Ими можно торговать, чтобы сократить суммарный seek. ОС не обязана передавать запросы диску в том порядке, в котором приложения их отправили. Планировщик ввода-вывода (I/O scheduler) переупорядочивает очередь, чтобы минимизировать суммарное перемещение головки — как лифт, который двигается в одном направлении, обслуживая все этажи по пути, потом разворачивается. Реальный IOPS может вырасти в 1.5–3 раза по сравнению с наивным FIFO. В Linux для HDD используется mq-deadline: балансирует переупорядочивание и гарантию, что ни один запрос не ждёт дольше настроенного таймаута.
Для SSD переупорядочивание полезно куда меньше — головки нет, seek не существует. Поэтому Linux для NVMe-дисков обычно использует none: запросы передаются устройству напрямую. Проверить текущий планировщик: cat /sys/block/nvme0n1/queue/scheduler. Исключение — нагрузки с жёсткими требованиями к tail latency, где mq-deadline даёт предел времени ожидания на отдельный запрос.
SSD: убираем механику
У SSD нет пластин, головок и вращения. Данные хранятся в NAND flash — полупроводниковой памяти, где каждая ячейка удерживает заряд годами без питания. Чтение — электрический процесс: подать напряжение, измерить ток, определить бит. Случайное чтение одной страницы (4–16 КБ) — 50–100 мкс, в 150–200 раз быстрее HDD. При этом латентность почти не зависит от адреса: страница в начале и в конце диска читаются за одно и то же время — понятий «близко» и «далеко» больше нет.
Те же 1000 случайных чтений по 8 КБ: 1000 × 75 мкс = 75 мс. Запрос, который на HDD занимал 13 секунд, выполняется за время моргания глаза. IOPS: один канал выдаёт ~13 000 операций в секунду, но контроллер работает с 8–16 каналами параллельно, отсюда 75 000–100 000 IOPS для SATA SSD и 500 000–1 000 000 IOPS для NVMe. Внутренний параллелизм определяет IOPS так же, как банки и ранги определяют пропускную способность DRAM: множество независимых блоков работают одновременно, контроллер мультиплексирует запросы.
Последовательное чтение тоже быстрее: SATA SSD — до 550 МБ/с (упирается в интерфейс), NVMe SSD — 3–7 ГБ/с, PCIe 5.0 — до 14 ГБ/с. Но ключевое отличие от HDD в другом: разрыв между последовательным и случайным на SSD — всего в 2–5 раз, а не в сотни. Случайное чтение больше не катастрофа.
Именно это сломало старые правила баз данных. На HDD планировщик PostgreSQL предпочитал sequential scan даже при чтении небольшой доли строк, потому что случайный IOPS стоил в сотни раз дороже последовательного. На SSD index scan выигрывает при значительно меньшей селективности. Конфигурационный параметр random_page_cost в PostgreSQL по умолчанию = 4.0 (предполагает HDD: случайное чтение в 4 раза дороже последовательного с учётом кеша страниц ОС). Для SSD рекомендуется 1.1–1.5. Неправильное значение — и планировщик выбирает sequential scan вместо index scan, а запрос вместо 5 мс занимает 500 мс.
Скрытая цена: три операции одной памяти
Скорость чтения SSD далась не бесплатно. Внутри NAND не две операции, как на HDD (read / write), а три — и характеристики у них радикально разные. Чтение одной страницы быстрее всех — 50–100 мкс. Запись в два раза медленнее чтения: 200–500 мкс, плюс критическое ограничение — записать можно только в страницу, которую уже стёрли. Переписать «поверх» нельзя. Стирание — самая медленная операция, 2–5 мс, и стирается не отдельная страница, а блок из 128–512 страниц целиком. Стереть одну страницу невозможно в принципе — такова физика NAND.
Из этой асимметрии сразу два следствия. Первое: для обновления 4 КБ данных недостаточно записать новую версию «на старое место» — нужно где-то найти уже стёртую страницу, записать туда, а старую пометить как устаревшую. Второе: рано или поздно свободные стёртые страницы кончаются, и SSD должен стирать блоки — но внутри блока почти всегда есть живые данные, которые приходится сначала перенести в другой блок. Эта фоновая работа увеличивает реальный объём записи в несколько раз по сравнению с тем, что попросила ОС — явление называется write amplification (усиление записи). Она же — главная причина tail latency: средняя латентность чтения 75 мкс, но если операция попала в момент фоновой уборки, ждёт 2–5 мс — в 20–50 раз дольше среднего.
Контроллер SSD прячет всю эту сложность за слоем, который ОС видит как обычный блочный диск. Устройство этого слоя — таблица маппинга, сборка мусора, TRIM, выравнивание износа, многоканальный параллелизм — в Устройство flash. Дальше — только те следствия, которые влияют на выбор носителя и настройку систем, работающих поверх.
NVMe vs SATA: один и тот же NAND, разный интерфейс
Первые SSD подключались через интерфейс SATA (Serial ATA, последовательный ATA), спроектированный для HDD. SATA — последовательная шина до 600 МБ/с с протоколом AHCI (Advanced Host Controller Interface), поддерживающим одну очередь команд глубиной 32. Для HDD с его 100 IOPS очередь на 32 — с запасом. Для SSD на 500 000 IOPS — узкое горлышко.
NVMe (Non-Volatile Memory Express, «экспресс-доступ к энергонезависимой памяти») — протокол, разработанный специально для flash. Работает поверх шины PCIe напрямую, без посредников. Пропускная способность PCIe 4.0 x4 — до 8 ГБ/с, PCIe 5.0 x4 — до 16 ГБ/с (13–26 раз больше SATA). Очереди: NVMe поддерживает до 65 535 очередей по 65 535 команд в каждой — каждое ядро CPU может иметь собственные submission queue и completion queue, без конкуренции за общий ресурс. На сервере с 64 ядрами SATA с единственной очередью упирается в конкуренцию ядер за вход; NVMe масштабируется линейно. Протокольные накладные расходы: ~2.5 мкс у NVMe против ~6 мкс у AHCI. Тот же NAND-чип, подключённый через SATA, отдаёт 550 МБ/с и ~50 000 IOPS; через NVMe — 3–7 ГБ/с и 500 000–1 000 000 IOPS. Аналогия: магистральная труба, подключённая через садовый шланг — давление есть, расход ограничен шлангом.
Форм-фактор NVMe — обычно M.2 (компактная плата 22×80 мм, в разъём на материнской плате) или U.2 (2.5-дюймовый корпус с кабелем, для серверов). Важно не путать форм-фактор с протоколом: существуют M.2-диски с SATA-интерфейсом (550 МБ/с) и M.2-диски с NVMe (3–7 ГБ/с). Одинаковый разъём — радикально разная производительность.
Целостность при сбое питания
Энергонезависимость NAND не означает автоматическую защиту от потери данных при сбое. В момент записи данные проходят три стадии: попадают в DRAM-буфер контроллера SSD, затем записываются на flash-страницу, затем обновляется таблица маппинга. Если питание пропадёт между первой и третьей стадией, данные могут быть записаны частично, а таблица маппинга остаться в неконсистентном состоянии. Серверные SSD оснащены конденсаторами (power-loss protection), хранящими достаточно энергии, чтобы при потере внешнего питания контроллер успел сбросить DRAM-буфер на flash — 10–50 мс. Потребительские SSD такой защиты не имеют: на уровне операционной системы ответ на fsync возвращается, но сами данные ещё могут быть в volatile DRAM-буфере контроллера. Для базы на потребительском SSD это реальный риск повреждения при внезапном отключении.
Полная картина: иерархия задержек и выбор носителя
От регистра до HDD выстраивается единая иерархия, и именно она определяет, как конкретная система распределяет данные между уровнями.
Уровень Латентность Пропускная способность Ёмкость
------- ----------- ---------------------- -------
Регистры ~0.3 нс (1т) -- 128 Б
L1 кеш ~1 нс (3-4т) > 1 ТБ/с 32-48 КБ
L2 кеш ~3-4 нс ~500 ГБ/с 256 КБ-1 МБ
L3 кеш ~10-20 нс ~200 ГБ/с 8-64 МБ
DRAM ~60-100 нс 30-50 ГБ/с (DDR5) 16-512 ГБ
SSD (NVMe) ~75 мкс 3-7 ГБ/с 0.5-8 ТБ
SSD (SATA) ~75 мкс 0.55 ГБ/с 0.25-4 ТБ
HDD (7200) ~14 мс 0.15-0.2 ГБ/с (seq) 1-20 ТБ
Каждый переход вниз — латентность растёт на один-два порядка, ёмкость растёт, стоимость за гигабайт падает. DRAM → SSD — в 750 раз. SSD → HDD — около 200 раз. Суммарно регистр → HDD — около 50 000 000 раз. Стоимость за ГБ движется наоборот: DRAM 0.05–0.10, HDD $0.01–0.02. Каждый следующий уровень дешевле на порядок, и именно эта экономика определяет, почему иерархия существует: если бы SRAM стоил как HDD, никаких уровней не понадобилось бы.
В продакшене HDD и SSD чаще всего работают вместе. SSD держит горячие данные: индексы, активные таблицы, WAL-журнал, метаданные файловой системы — всё, где критичен random IOPS и низкая латентность. HDD обслуживает холодные: архивы, бэкапы, аналитические логи, которые читаются последовательно и редко — стоимость за терабайт у HDD в 5–10 раз ниже. Типичная сборка сервера БД: 2–4 NVMe SSD в RAID под активную базу, массив HDD под бэкапы и WAL-архивы. Распределённые системы строят hot/cold tier: последние 7 дней — на SSD, история за годы — на HDD.
Выбор носителя виден на числах. База получает 10 000 запросов в секунду, каждый порождает 5 случайных чтений (поиск по индексу + чтение страницы) — 50 000 random IOPS. На HDD 7200 RPM это 500 дисков только для чтения. На одном NVMe SSD с 500 000 IOPS — 10% нагрузки. Разница в инфраструктуре: стойка серверов с HDD-массивами против одного диска за 150 долларов. На практике буферный кеш базы и page cache ОС обслуживают 90–99% чтений из RAM, и до диска доходит лишь малая доля. Но даже оставшийся 1% при 10 000 QPS — это 500 random IOPS; на одном HDD это секунды ожидания в хвосте распределения. SSD обслуживает промахи кеша за микросекунды, делая хвост предсказуемым.
Практические следствия для настройки:
- Заполненность SSD критически влияет на запись. При 90%+ свободных стёртых блоков почти нет, write amplification растёт, производительность падает в 2–5 раз. Серверные SSD резервируют 10–28% ёмкости (over-provisioning) — недоступные ОС, но доступные контроллеру для фоновой уборки; это ключевая защита от деградации.
- Tail latency при
fsync. Средний ответ 75 мкс, но 99.9-й перцентиль может быть в 20–50 раз выше — если операция попала в момент стирания блока. Серверные SSD ограничивают длительность внутренних пауз и указывают 99.99-й перцентиль в спецификации (обычно ~500 мкс при среднем ~100 мкс). Для нагрузок, где tail важнее среднего, — обязательный параметр выбора. random_page_cost=1.1–1.5для SSD вместо дефолтного 4.0. Без этого планировщик ошибочно выбирает sequential scan.
HDD vs SSD: сравнительная таблица
Характеристика HDD (7200 RPM) SSD (NVMe) -------------------- ---------------- ---------------- Random read latency ~14 мс ~75 мкс Random read IOPS 75-100 500,000-1,000,000 Sequential read 150-200 МБ/с 3-7 ГБ/с Sequential write 150-200 МБ/с 2-5 ГБ/с Seq/random разрыв ~500x ~2-5x Энергопотребление 5-15 Вт 3-8 Вт Ударостойкость чувствителен устойчив Стоимость за ТБ $15-25 $50-100 Макс. ёмкость (диск) 20+ ТБ 8-16 ТБ Срок службы механ. износ P/E cyclesHDD превосходит SSD только в стоимости за терабайт и максимальной ёмкости одного устройства. Во всём остальном — латентность, IOPS, пропускная способность, энергопотребление, ударостойкость — SSD выигрывает от одного до четырёх порядков. HDD также уязвим к вибрации: удар во время работы может привести к контакту головки с поверхностью пластины (head crash) и необратимой потере данных.
Передача данных между устройством и RAM
NVMe SSD выдаёт 500 000 IOPS и 7 ГБ/с, но эти данные должны физически попасть с контроллера SSD в оперативную память. Если CPU копирует каждый байт сам, передача 4 КБ займёт сотни load/store инструкций, а при 500 000 IOPS целое ядро уходит только на перекладывание данных. Нужен механизм, позволяющий устройствам писать в RAM напрямую, без участия процессора. Он называется DMA (Direct Memory Access, прямой доступ к памяти) — по какому физическому пути идут при этом команды и данные, разбирается в следующей заметке.
Sources
- John L. Hennessy, David A. Patterson, 2017, Computer Architecture: A Quantitative Approach — 6th edition, Appendix D: Storage Systems
- Remzi H. Arpaci-Dusseau, Andrea C. Arpaci-Dusseau, Operating Systems: Three Easy Pieces — Chapter 37: Hard Disk Drives, Chapter 44: Flash-based SSDs (ostep.org)
- NVM Express, 2024, NVM Express Base Specification, Revision 2.1 — nvmexpress.org
smartctl -a /dev/sda— SMART-данные и wear level текущего диска