На фото SSD Samsung PM1733
Твердотельные накопители (Solid-State Drives, SSD) на основе флэш-памяти уже заменили многие магнитные диски в качестве стандартных накопителей. С точки зрения программиста SSD и диски очень похожи: и те, и другие являются устройствами постоянного хранения, обеспечивающими страничный доступ через файловые системы и системные вызовы, и имеющими большой объём.
Однако у них есть и важные различия, которые становятся существенными, если нужно достичь оптимальной производительности SSD. Как мы увидим, SSD устроены сложнее и если воспринимать их просто как быстрые диски, то их производительность может вести себя довольно загадочным образом. Цель этого поста — показать, почему SSD так себя ведут, что поможет вам создавать ПО, способное использовать их особенности. (Стоит заметить, что я буду говорить о NAND-памяти, а не о памяти Intel Optane, имеющей другие характеристики.)
Приводы, а не диски
SSD часто называют дисками, но это неверно, потому что они хранят данные в полупроводниковых устройствах, а не на механическом диске. Для чтения или записи в произвольный блок диск механически перемещает головку в нужное место, что занимает порядка 10 мс. Однако операция произвольного чтения с SSD занимает около 100 мкс — в 100 раз быстрее. Благодаря такой низкой задержке загрузка системы с SSD намного быстрее, чем загрузка с диска.
Ещё одно важное отличие дисков от SSD заключается в том, что диски имеют одну дисковую головку и имеют хорошие показатели только при последовательном доступе. В отличие от них, SSD состоят из десятков или даже сотен флэш-чипов («параллельных блоков»), доступ к которым может выполняться параллельно.
SSD прозрачным образом разделяет большие файлы по флэш-чипам на части размером со страницу, а аппаратное устройство предвыборки гарантирует, что последовательное сканирование использует все доступные флэш-чипы. Однако на уровне флэш-памяти особой разницы между последовательным и произвольным чтением нет. Большинство SSD способно достигать полной полосы пропускания и при считывании произвольных страниц. Для этого необходимо запланировать сотни параллельных запросов произвольного ввода-вывода, чтобы одновременно работали все флэш-чипы. Это можно реализовать запуском множества потоков или при помощи асинхронных интерфейсов ввода-вывода, например, libaio или io_uring.
Запись
Всё становится ещё интереснее, когда дело касается записи. Например, если изучать задержки записи, то можно замерить результаты от 10 мкс — в 10 раз быстрее, чем считывание. Однако задержки кажутся такими низкими только потому, что SSD кэшируют операции записи на энергозависимую ОЗУ. Истинная задержка записи NAND-памяти примерно равна 1 мс — в 10 медленнее, чем чтение. На SSD потребительского уровня её можно измерить, отдав после записи команду синхронизации/сброса, чтобы гарантировать, что данные сохранились во флэш-память. В большинстве SSD серверов задержку записи невозможно замерить напрямую: синхронизация/сброс завершаются мгновенно, поскольку батарея гарантирует сохранность кэша операций записи даже в случае отключения электропитания.
Чтобы достичь высокой полосы пропускания записи, несмотря на достаточно высокую задержку записи, SSD используют тот же трюк, что и при чтении: они обеспечивают параллельный доступ к нескольким чипам. Так как кэш операций записи может записывать страницы асинхронно, для получения хорошей производительности записи даже необязательно планировать очень много параллельных операций записи. Однако задержку операций записи не всегда можно скрыть полностью: например, поскольку запись в 10 раз больше занимает флэш-чип, чем считывание, операции записи вызывают значительные «хвостовые задержки» для считывания с того же флэш-чипа.
Операции записи вне порядка
Мы упускаем один важный факт: страницы NAND-памяти невозможно перезаписывать. Записи страниц могут выполняться только последовательно, в пределах блоков, которые были заранее стёрты. Эти стираемые блоки имеют размеры в несколько мегабайт, а потому состоят из сотен страниц. На новом SSD все блоки стёрты и пользователь может напрямую начинать добавлять новые данные.
Однако обновление страниц — это не такой простой процесс. Было бы слишком затратно стирать весь блок просто для того, чтобы перезаписать единственную страницу. Поэтому SSD выполняют обновления страниц, записывая новую версию страницы в новое место. Это означает, что логические и физические адреса страниц разделены. Хранящаяся в SSD таблица отображения преобразует логические (программные) адреса в физические (аппаратные) местоположения. Этот компонент также называют Flash Translation Layer (FTL). Например, давайте представим, что у нас есть SSD с тремя стираемыми блоками, в каждом из которых по четыре страницы. Последовательность записей страниц P1, P2, P0, P3, P5, P1 может привести к следующему физическому состоянию SSD:
Блок 0 | P1 (старая) | P2 | P0 | P3 |
Блок 1 | P5 | P1 | → | |
Блок 2 |
Сборка мусора
При использовании таблицы отображения и непоследовательной записи всё работает хорошо, пока в SSD не заканчиваются свободные блоки. Старую версию перезаписанных страниц рано или поздно нужно восстановить. Если мы продолжим предыдущий пример, выполнив запись страниц P3, P4, P7, P1, P6, P2, то получим следующую ситуацию:
Блок 0 | P1 (старая) | P2 (старая) | P0 | P3 (старая) |
Блок 1 | P5 | P1 (старая) | P3 | P4 |
Блок 2 | P7 | P1 | P6 | P2 |
На этом этапе у нас больше нет свободных стираемых блоков (хотя с точки зрения логики пространство может и оставаться). Прежде чем записать ещё одну страницу, SSD должен сначала стереть блок. В нашем примере сборщику мусора лучше всего будет стереть блок 0, потому что используется только одна из его страниц. После стирания блока 0 мы освобождаем место для трёх операций записи, а SSD выглядит так:
Блок 0 | P0 | → |
||
Блок 1 | P5 | P1 (старая) | P3 | P4 |
Блок 2 | P7 | P1 | P6 | P2 |
Write Amplification и Overprovisioning
Для сборки мусора блока 0 нам нужно физически переместить страницу P0, хотя с точки зрения логики с этой страницей ничего не происходит. Другими словами, у SSD на флэш-памяти количество физических операций записи (во флэш) обычно выше, чем количество логических (программных) операций записи. Соотношение между этими двумя параметрами называется write amplification (усиление записи). В нашем примере, чтобы освободить место под 3 новых страницы в блоке 0, нам пришлось переместить 1 страницу. У нас получилось 4 физических операций записи на 3 логические операции записи, т.е. коэффициент усиления записи равен 1,33.
Высокие коэффициенты усиления записи снижают производительность и срок жизни флэш-памяти. Величина коэффициента зависит от паттерна доступа и заполненности SSD. Объёмные последовательные операции записи имеют низкий коэффициент write amplification, а наихудшим случаем являются произвольные операции записи.
Предположим, наш SSD заполнен на 50% и мы выполняем произвольные операции записи. Когда мы стираем блок, то в среднем примерно половина страниц блока по-прежнему используется и должна быть перемещена. То есть коэффициент write amplification при коэффициенте заполнения накопителя 50% равен 2. Обычно наихудший коэффициент write amplification, получаемый при коэффициенте заполнения f, равен 1/(1-f):
f | 0,1 | 0,2 | 0,3 | 0,4 | 0,5 | 0,6 | 0,7 | 0,8 | 0,9 | 0,95 | 0,99 |
WA | 1,11 | 1,25 | 1,43 | 1,67 | 2,00 | 2,50 | 3,33 | 5 | 10 | 20 | 100 |
Так как при близких к 1 коэффициентах заполнения коэффициенты write amplification становятся чрезвычайно высокими, у большинства SSD есть скрытый запасной объём (overprovisioning). Этот объём обычно равен 10-20% от общего объёма. Разумеется, также можно добавить больше overprovisioning, создав пустой раздел и ничего туда не записывая.
Вывод и дополнительные источники
SSD стали довольно дешёвыми и они имеют очень высокую производительность. Например, серверный SSD Samsung PM1733 стоит примерно 200 евро за терабайт и обеспечивает полосу пропускания почти 7 ГБ/с для чтения и 4 ГБ/с для записи. Для достижения такой высокой производительности нужно понимать, как работает SSD, поэтому в этом посте я описал самые важные внутренние механизмы SSD на флэш-памяти. Я стремился к лаконичности, поэтому кое-что упрощал. Чтобы узнать больше, можно начать с этого туториала, в котором даются ссылки на полезные статьи. Нужно также заметить, что из-за высокой скорости SSD часто узким местом производительности становится стек ввода-вывода ОС. Экспериментальные результаты по Linux можно найти в нашей статье для конференции CIDR 2020.
На правах рекламы
Наши облачные серверы используют only NVMe сетевое хранилище с тройной репликацией данных. Вы можете использовать арендовать сервер для любых задач — разработки, размещения сайтов, использования под VPN и даже получить удалённую машину на Windows! Идей может быть много и любую из них поможем воплотить в реальность!
Подписывайтесь на наш чат в Telegram.