---
title: "Flash и SSD"
description: "У жёсткого диска главная беда — механика: seek и вращение стоят миллисекунды, поэтому случайный доступ в сотни раз медленнее последовательного. SSD (solid state drive…"
canonical: https://graphlms.ru/os/book/ssd
course: "Операционные системы"
updated: 2026-10-12
lang: ru
publisher: GraphLMS
---

# Flash и SSD

> Источник: https://graphlms.ru/os/book/ssd — курс «Операционные системы», GraphLMS.

## Другое железо, другие правила

У [жёсткого диска](/os/book/hdd) главная беда — механика: seek и вращение
стоят миллисекунды, поэтому случайный доступ в сотни раз медленнее
последовательного. **SSD** (solid state drive, твердотельный накопитель) состоит
только из микросхем флеш-памяти и контроллера. Головки нет, вращения нет, и
прочитать любую страницу можно примерно за одно и то же время: десятки
микросекунд вместо десяти миллисекунд.

Если бы на этом всё заканчивалось, глава была бы на один абзац. Но у
флеш-памяти свои странные правила записи, и из-за них SSD внутри устроен
сложнее HDD. Эти правила объясняют, почему SSD тормозит, когда почти заполнен,
почему он изнашивается и почему дешёвый SSD под базой данных может оказаться
медленнее, чем ожидалось.

## Страницы, блоки и стирание

Память в SSD — это **NAND flash**. Её единицы:

- **страница** (page), обычно 4–16 КБ — единица чтения и записи;
- **блок** (block, erase block), сотни страниц, то есть несколько мегабайт — единица
  стирания.

И три правила:

1. Читать можно любую страницу в любом порядке.
2. Писать можно только в **чистую** (стёртую) страницу. Записать поверх старых
   данных нельзя.
3. Стереть можно только **целый блок**, отдельную страницу — нельзя.

Порядок времён (для распространённой TLC-памяти, по паспортам производителей):

```text
   чтение страницы     ~50–100 мкс
   запись страницы     ~0,5–1 мс
   стирание блока      ~3–5 мс
```

Так что у страницы три состояния: чистая (готова к записи), записанная
(валидные данные) и невалидная (данные устарели, но место занято до стирания
всего блока). Мелкая запись и крупное стирание — это несоответствие масштабов,
из которого растут все остальные сложности.

## Нельзя перезаписать на месте

На HDD изменить 4 КБ в середине файла просто: головка встаёт над сектором и
пишет поверх. На флеше, чтобы изменить одну страницу в заполненном блоке,
наивно пришлось бы:

```text
   1. прочитать все 256 страниц блока в память
   2. изменить одну
   3. стереть блок                          ~3–5 мс
   4. записать обратно 256 страниц
   → ради 4 КБ переписали мегабайт
```

Отношение «сколько байт физически записано во флеш» к «сколько байт попросил
записать хост» называется **write amplification** (усиление записи, WA). У
наивной схемы выше оно равно 256. Чем WA больше, тем медленнее запись и тем
быстрее изнашивается память.

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

## FTL: слой, который всё прячет

Операционная система работает с SSD как с обычным блочным устройством:
«прочитай логический блок 12345», «запиши в логический блок 12345». Этот адрес
называется **LBA** (logical block address). Чтобы файловым системам не нужно было
знать про страницы, блоки и стирание, в контроллере SSD работает прошивка
**FTL** (flash translation layer, слой трансляции флеша). Она ведёт таблицу
«логический адрес → физическая страница» и сама решает, куда класть данные.

```text
   ОС: «запиши LBA 100»
          │
          ▼
   ┌────────────────────────────────┐
   │ FTL (прошивка контроллера SSD) │
   │   LBA 100 → блок 7, страница 5 │
   │   LBA 101 → блок 2, страница 0 │
   │   + сборка мусора              │
   │   + выравнивание износа        │
   └────────────────────────────────┘
          │
          ▼
   NAND: блоки и страницы
```

Запись в FTL устроена как журнал: новые данные кладутся в следующую чистую
страницу открытого блока, а в таблице меняется указатель.

```text
   Записали X в LBA 100:        LBA 100 → p5          p5 [X  валидна]
   Перезаписали X' в LBA 100:   LBA 100 → p6          p5 [X  невалидна]
                                                      p6 [X' валидна]
```

Запись всегда идёт в чистое место и всегда последовательно внутри блока —
быстро. Таблица отображения занимает около 1 байта на килобайт ёмкости
(примерно 1 ГБ на 1 ТБ диска), поэтому у хороших SSD есть своя DRAM, где эта
таблица живёт. Дешёвые модели без DRAM держат её часть в памяти хоста или
кэшируют кусками, и на случайных нагрузках это заметно.

Та же идея «никогда не писать на место, писать в конец лога, потом убирать
мусор» встретится ещё дважды: в [лог-структурированных ФС](/os/book/lfs) и в
LSM-деревьях баз данных.

## Сборка мусора и откуда берётся усиление записи

Чистые страницы когда-нибудь кончаются. Тогда работает **сборка мусора**
(garbage collection, GC) внутри FTL: выбрать блок с большим числом невалидных
страниц, скопировать из него ещё валидные страницы в другой блок, стереть
освободившийся блок.

Посчитаем на примере. Блок из 128 страниц, в нём 96 валидных и 32 невалидных.
Чтобы получить 32 чистые страницы под новые данные, GC переписывает 96 валидных
страниц и стирает блок.

```text
   хост хочет записать:   32 страницы
   флеш реально пишет:    96 (перенос валидных) + 32 (новые данные) = 128 страниц
   write amplification:   128 / 32 = 4
```

Если бы в блоке была всего одна валидная страница, WA было бы около 1. Поэтому
GC выбирает блоки «погрязнее», и поэтому так важно, сколько на диске свободного
места: чем полнее SSD, тем больше валидных страниц в каждом блоке, тем больше
копирования ради каждой записи. Отсюда два практических следствия.

- **Запись на почти заполненном SSD медленнее.** Под длительной записью
  накопитель, заполненный на 95%, может писать в разы медленнее, чем пустой.
- **Over-provisioning** (резерв ёмкости). Производитель ставит флеш больше
  объявленного объёма (диск на 960 ГБ физически содержит 1024 ГБ и больше) и
  прячет разницу от ОС. Этот запас всегда свободен, GC есть где развернуться. У
  серверных моделей резерв больше, отсюда «странные» объёмы вроде 800 ГБ или
  3,84 ТБ. Можно увеличить резерв и самому: оставить часть диска неразмеченной.

## Износ и выравнивание

Каждая ячейка выдерживает ограниченное число циклов «стереть-записать» (P/E
cycles). Чем больше бит хранит ячейка, тем дешевле гигабайт и тем меньше ресурс:

| Тип ячейки | Бит на ячейку | Порядок ресурса, циклов P/E |
|---|---|---|
| SLC | 1 | ~100 000 |
| MLC | 2 | ~3 000–10 000 |
| TLC | 3 | ~1 000–3 000 |
| QLC | 4 | ~1 000 и меньше |

Если бы часто меняемые данные всегда попадали в одни и те же физические блоки,
эти блоки умерли бы быстро, а остальные остались бы новыми. **Wear leveling**
(выравнивание износа) размазывает запись по всем блокам: FTL выбирает для
записи менее изношенные блоки и время от времени переносит «холодные» данные,
которые годами не меняются, чтобы их малоизношенные блоки тоже поработали.

В паспорте SSD ресурс указывают как **TBW** (сколько терабайт можно записать за
гарантийный срок) или **DWPD** (сколько полных объёмов диска в день можно
перезаписывать). Например, диск 3,84 ТБ с 1 DWPD на 5 лет выдержит около 7 ПБ
записи. Текущий износ на Linux видно через `nvme smart-log /dev/nvme0`: поле
`percentage_used` показывает, какая доля ресурса израсходована. Write
amplification тратит этот ресурс напрямую: при WA = 4 диск изнашивается вчетверо
быстрее, чем выглядит по записи приложения.

## TRIM: сказать диску, что данные больше не нужны

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

Команда **TRIM** (в NVMe она называется Deallocate) сообщает диску: «логические
блоки с такими-то адресами больше не содержат нужных данных». FTL помечает
соответствующие страницы невалидными, и GC их не копирует.

В Linux TRIM отправляют двумя способами: опция монтирования `discard` (сразу
при удалении) или периодически утилитой `fstrim` (во многих дистрибутивах
включён `fstrim.timer`, раз в неделю). Периодический вариант обычно
предпочтительнее: немедленный discard на некоторых дисках сам по себе тормозит
удаление.

## Интерфейс: SATA против NVMe

SSD сначала подключали так же, как HDD, — через SATA. Протокол SATA (AHCI)
рассчитан на механический диск: одна очередь команд глубиной 32 и потолок
около 550 МБ/с. Для флеша это узкое горлышко.

**NVMe** — протокол, сделанный под флеш. Диск подключён прямо к PCIe,
очередей может быть до 65 535, в каждой до 65 536 команд. Linux заводит по паре
очередей (отправки и завершения) на каждое ядро процессора, поэтому ядра не
дерутся за общую очередь. Работает это через механизм из
[главы про устройства](/os/book/io-devices): драйвер кладёт команду в очередь в
памяти, звонит в doorbell, диск забирает команду и отвечает через DMA и
прерывание.

Зачем столько очередей? Внутри SSD десятки микросхем флеша, каждая с несколькими
независимыми плоскостями. Одна команда занимает одну из них, остальные
простаивают. Максимальную скорость диск показывает, только когда ему дают много
команд одновременно — говорят, при большой **глубине очереди** (queue depth,
QD).

```text
   NVMe-диск (PCIe 4.0, TLC), чтение блоками по 4 КБ, порядок величин:

   QD = 1:   задержка ~80 мкс → ~12 000 IOPS → ~50 МБ/с
   QD = 32+: задержка растёт,  но ~500 000–1 000 000 IOPS → 2–4 ГБ/с
   последовательное чтение крупными блоками: ~5–7 ГБ/с
```

Отсюда важное уточнение к частой фразе «у SSD случайное чтение такое же быстрое,
как последовательное». По **задержке** одной операции — почти да: нет механики,
и адрес не важен. По **пропускной способности** — только если запросов много
одновременно. Сервис, который читает с SSD строго по одному блоку и ждёт ответа
перед следующим, получит десятки мегабайт в секунду, а не гигабайты. В Go это
означает, что параллельные чтения из нескольких горутин (или большие блоки)
ускоряют работу с диском, а последовательный цикл по мелким случайным чтениям —
нет.

Планировщик ввода-вывода ОС для NVMe обычно `none`: переупорядочивать запросы
ради экономии seek незачем, а лишняя сортировка добавляет задержку.

## Почему запись ведёт себя рывками

Соберём всё, что влияет на запись.

- **Кэш записи.** У многих потребительских SSD часть TLC/QLC-памяти работает в
  быстром режиме SLC как буфер. Пока он не заполнен, запись идёт на гигабайтах в
  секунду; после десятков гигабайт подряд скорость падает в несколько раз.
- **Сборка мусора.** Когда свободных блоков мало, GC работает прямо во время
  записи, и задержка отдельных операций прыгает.
- **Заполненность.** Чем меньше свободного места, тем больше копирования на
  каждую запись.
- **Размер и выравнивание.** Мелкая случайная запись тяжелее крупной
  последовательной: больше работы таблице отображения и GC.

Для базы данных важен ещё один пункт: как диск отрабатывает команду «сбрось кэш
на флеш», которую ОС отправляет при `fsync`. У серверных SSD есть **защита от
потери питания** (power loss protection, PLP) — конденсаторы, которых хватает,
чтобы дописать содержимое DRAM-кэша во флеш. Такой диск может подтвердить
`fsync` сразу из кэша, за десятки микросекунд. Потребительский диск без PLP
обязан реально записать данные во флеш, и `fsync` стоит миллисекунды. Разница в
скорости коммитов базы — на порядок. Подробности в главе про
[fsync](/os/book/fsync-durability).

## HDD и SSD рядом

| Параметр | HDD | SSD (NVMe) |
|---|---|---|
| Устройство | пластины и головка | флеш-память и контроллер |
| Задержка случайного чтения | ~10 мс | ~50–100 мкс |
| Случайных IOPS | 100–200 | сотни тысяч при большой глубине очереди |
| Последовательное чтение | 150–250 МБ/с | единицы ГБ/с |
| Перезапись на месте | да | нет, только через FTL и GC |
| Износ | механический | ограниченное число циклов записи |
| Что ухудшает скорость | случайный доступ | заполненность, мелкая запись, нет параллелизма |
| Планировщик в Linux | mq-deadline, bfq | none |
| Цена за ГБ | ниже в несколько раз | выше |

> Квиз по разделу: см. вопросы в конце документа или на https://graphlms.ru/os/book/ssd

## Частые ошибки

- Повторять, что у SSD случайное чтение «как последовательное», не уточняя про глубину очереди.
- Заполнять SSD под базу данных до 95%: сборка мусора резко замедлит запись и ускорит износ.
- Ставить потребительский SSD без защиты от потери питания под базу с частыми `fsync`.
- Забывать про TRIM (`fstrim.timer`, опция `discard`).
- Читать с NVMe мелкими блоками строго по одному запросу и удивляться десяткам мегабайт в секунду.

## Проверьте себя

1. Почему SSD не перезаписывает страницу на месте?
2. Зачем производитель прячет часть флеш-памяти от ОС?
3. Почему серверный SSD с PLP подтверждает `fsync` быстрее потребительского?
4. SSD заполнен так, что в среднем в блоке, который выбирает сборщик мусора, 80% страниц валидны. Чему примерно равна write amplification? Что станет с ней, если удалить половину данных, но не делать TRIM?

Ответы. (1) Писать можно только в стёртую страницу, а стирать — только целый блок. (2) Это резерв (over-provisioning): у сборки мусора всегда есть свободное место, меньше копирования и ниже write amplification. (3) Конденсаторы позволяют дописать кэш во флеш без внешнего питания, поэтому сброс кэша можно подтвердить сразу. (4) Чтобы освободить 20% блока, нужно переписать 80%: на каждую страницу новых данных пишется 1 / 0,2 = 5 страниц, WA ≈ 5. Без TRIM диск не знает об удалении, считает данные валидными, и WA не изменится.

## Что спрашивают на собесе

- **Почему во флеше нельзя перезаписать страницу?** Писать можно только в
  стёртую страницу, а стирать — только блок целиком.
- **Что такое write amplification и как её уменьшают?** Отношение физически
  записанного к запрошенному. Растёт от сборки мусора на заполненном диске.
  Уменьшают TRIM, резерв ёмкости (over-provisioning) и крупной
  последовательной записью.
- **Что делает FTL?** Отображает логические адреса на физические страницы,
  пишет как журнал, собирает мусор, выравнивает износ.
- **Зачем wear leveling?** Ячейки выдерживают ограниченное число циклов; запись
  размазывают, чтобы блоки изнашивались равномерно.
- **Что делает TRIM?** Сообщает SSD, какие логические блоки свободны, чтобы GC
  не копировал мёртвые данные.
- **Правда ли, что у SSD случайное чтение как последовательное?** По задержке
  почти да. По пропускной — только при большой глубине очереди: NVMe раскрывается
  на десятках параллельных запросов.
- **Почему серверный SSD быстрее на fsync?** PLP позволяет подтверждать сброс из
  DRAM-кэша, не дожидаясь записи во флеш.

## Вопросы для самопроверки

**Квиз «Flash и SSD»**

1. Какая операция во flash-памяти возможна только на уровне целого блока, а не отдельной страницы?
   - Чтение
   - Запись
   - Стирание (erase) (верно)
   - Все три операции
   - Пояснение: Читать и писать можно по страницам, а вот стереть (вернуть в чистое состояние) можно только весь блок целиком — сотни страниц сразу. Именно отсюда растут write amplification и сложность записи.
2. Что такое write amplification?
   - Ускорение записи за счёт кэша
   - Когда ради записи малого объёма данных физически записывается/копируется гораздо больше (верно)
   - Дублирование данных для надёжности
   - Сжатие данных перед записью
   - Пояснение: Поскольку нельзя перезаписать страницу на месте, контроллер копирует живые страницы и стирает блоки. В итоге на флеш физически пишется больше, чем просил хост — это и есть усиление записи.
3. Что делает FTL (Flash Translation Layer)?
   - Шифрует все данные на лету
   - Заменяет файловую систему ОС
   - Притворяется обычным блочным диском, ведёт отображение логических адресов в физические и делает сборку мусора (верно)
   - Ускоряет вращение пластин
   - Пояснение: FTL — прошивка контроллера SSD. Снаружи это обычный блочный диск, а внутри он держит таблицу логический→физический адрес, пишет журналом и сам убирает мусор и выравнивает износ.
4. Зачем нужен wear leveling?
   - Чтобы случайное чтение было быстрым
   - Чтобы сжимать данные
   - Чтобы ускорить стирание
   - Чтобы равномерно распределять запись по всем блокам и не убить отдельные ячейки раньше срока (верно)
   - Пояснение: Ячейки флеша выдерживают ограниченное число циклов перезаписи. Wear leveling размазывает запись по всем блокам, чтобы они изнашивались равномерно и весь SSD прожил дольше.
5. Что сообщает SSD команда TRIM?
   - Что блок повреждён
   - Что указанные логические блоки больше не содержат нужных данных (верно)
   - Что надо ускорить чтение
   - Что нужно немедленно стереть весь диск
   - Пояснение: При удалении файла ФС обычно не говорит SSD, что блоки освободились. TRIM явно помечает их ненужными, чтобы FTL не копировал этот мусор при сборке мусора — это снижает write amplification и износ.
6. Почему у SSD случайное чтение почти такое же быстрое, как последовательное?
   - Потому что данные всегда лежат подряд
   - Из-за большого кэша
   - Нет механической головки и вращения — любая страница доступна напрямую за примерно одинаковое время (верно)
   - Из-за wear leveling
   - Пояснение: В отличие от HDD, у SSD нет seek и rotation. Доступ к любой странице идёт напрямую через адрес, поэтому случайный доступ почти не проигрывает последовательному при чтении.
