Оптимальный способ записи файлов только для добавления на SSD

Я хочу знать, какой оптимальный способ входа на SSD. Подумайте о чем-то вроде журнала базы данных, где вы записываете только добавление, но вам также нужно выполнять fsync() каждую транзакцию или несколько транзакций, чтобы обеспечить надежность данных на уровне приложения.

Я собираюсь рассказать о том, как работают твердотельные накопители, поэтому, если вы уже все это знаете, все равно пролистайте, если я в чем-то ошибаюсь. Некоторые полезные материалы для дальнейшего чтения: Руководство Эммануэля Гуссарта из 6 частей по программированию для твердотельных накопителей и статья Не размещайте свой журнал в моем журнале [pdf].

SSD записывают и читают только целые страницы. Где размер страницы отличается от SSD к SSD, но обычно кратен 4 КБ. Мой Samsung EVO 840 использует размер страницы 8 КБ (который, кстати, Линус называет "непригодным дерьмом" в своей обычной красочной манере.) SSD не могут изменять данные на месте, они могут только записывать на свободные страницы. Таким образом, объединение этих двух ограничений, обновление одного байта на моем EVO требует чтения страницы 8 КБ, изменения байта и записи его на новую страницу 8 КБ и обновления сопоставления страницы FTL (структура данных ssd), поэтому логический адрес этой страницы как понимает ОС, теперь указывает на новую физическую страницу. Поскольку данные файла также больше не являются непрерывными в одном и том же блоке стирания (наименьшая группа страниц, которые можно стереть), мы также создаем форму долга фрагментации, который будет стоить нам будущей сборки мусора на SSD. Ужасно неэффективно.

В качестве отступления, глядя на файловую систему моего ПК: C:\WINDOWS\system32>fsutil fsinfo ntfsinfo c: Она имеет размер сектора 512 байт и размер распределения (кластера) 4 КБ. Ни одна из них не соответствует размеру страницы SSD - вероятно, не очень эффективно.

Есть некоторые проблемы с простым написанием, например. pwrite() в кеш страниц ядра и позволяя ОС обрабатывать записи. Во-первых, вам нужно будет выполнить дополнительный вызов sync_file_range() после вызова pwrite(), чтобы фактически начать ввод-вывод, иначе все будет ждать, пока вы не вызовете fsync() и не развяжете бурю ввода-вывода. Во-вторых, fsync() кажется, блокирует будущие вызовы write() в том же файле. . Наконец, у вас нет контроля над тем, как ядро ​​записывает данные на SSD, что может быть хорошо, а может плохо, что приводит к увеличению записи.

По вышеуказанным причинам, а также потому, что мне все равно нужен AIO для чтения журнала, я выбираю запись в журнал с помощью O_DIRECT и O_DSYNC и имею полный контроль.

Насколько я понимаю, O_DIRECT требует, чтобы все записи были выровнены по размеру сектора и в целых числах секторов. Поэтому каждый раз, когда я решаю добавить запись в журнал, мне нужно добавить в конец отступ, чтобы довести его до целого числа секторов (если все записи всегда представляют собой целое число секторов, они также будут правильно выровнены). , по крайней мере, в моем коде.) Хорошо, это не так уж плохо. Но мой вопрос: не лучше ли округлить до целого числа страниц SSD вместо секторов? Предположительно, это устранит усиление записи?

Это может сжечь огромное количество места, особенно если за один раз в журнал записываются небольшие объемы данных (например, пара сотен байтов). Это также может быть ненужным. У твердотельных накопителей, таких как Samsung EVO, есть кеш записи, и они не очищают его при fsync(). Вместо этого они полагаются на конденсаторы для записи кеша на SSD в случае потери питания. В этом случае, возможно, SSD делает правильную вещь, когда журнал добавления только записывает секторы за раз - он может не записывать последнюю неполную страницу до тех пор, пока не прибудет следующее добавление (я) и не завершит его (или если он не будет вытеснен кэша из-за большого количества несвязанных операций ввода-вывода.) Поскольку ответ на этот вопрос, вероятно, зависит от устройства и, возможно, от файловой системы, есть ли способ, которым я могу закодировать две возможности и проверить свою теорию? Какой-то способ измерить усиление записи или количество обновленных / RMW-страниц в Linux?


person Eloff    schedule 23.04.2016    source источник
comment
Меня интересует тот же вопрос, но применительно к iOS устройствам.   -  person Colin    schedule 01.05.2017
comment
Ваш вопрос не ясен, что вас беспокоит, экономия места и максимизация журнала? У вас есть root-доступ к SSD?   -  person Damien    schedule 13.07.2017


Ответы (1)


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

Краткий ответ

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

Чтобы записать бит во флэш-память, вы должны стереть всю страницу (512 байт), где она находится первой. Поэтому, если вы хотите где-то добавить или изменить 1 байт, сначала он должен стереть всю страницу, на которой он находится.

Процесс можно обобщить следующим образом:

  • Прочитать всю страницу в буфер
  • Измените буфер с вашим добавленным контентом
  • Стереть всю страницу
  • Переписать всю страницу с измененным буфером

Длинный ответ

Сектор (страницы) в основном зависит от самого аппаратного обеспечения реализации флэш-памяти и физического драйвера флэш-памяти, в котором вы не имеете никакого контроля. Эту страницу нужно очищать и переписывать каждый раз, когда вы что-то меняете.

Как вы, наверное, уже знаете, вы не можете переписать ни одного бита на странице, не очистив и не перезаписав все 512 байтов. Теперь флэш-накопители имеют срок службы около 100 000 циклов записи, прежде чем сектор может быть поврежден. Чтобы увеличить срок службы, обычно физический драйвер, а иногда и система, имеют алгоритм рандомизации записи, чтобы избежать постоянной записи одного и того же сектора. (Кстати, никогда не делайте дефрагментацию на SSD, это бесполезно и в лучшем случае сокращает срок службы).

Что касается кластера, это обрабатывается на более высоком уровне, связанном с файловой системой, и вы можете это контролировать. Обычно, когда вы форматируете новый жесткий диск, вы можете выбрать размер кластера, который в Windows относится к размеру единицы размещения в окне форматирования.

Формат FAT 32

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

FAT32

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

С другой стороны, если вы храните только большие файлы и хотите выбрать самый большой размер сектора, немного превышающий размер вашего файла.

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


Реализация

Теперь, если у вас есть необработанный доступ к диску и вы хотите действительно оптимизировать, вы можете напрямую записывать на диск, не используя файловую систему.

С другой стороны * Сэкономит вам довольно много места на диске * Сделает диск устойчивым в случае сбоя, если ваш дизайн достаточно умен * потребует гораздо меньше ресурсов, если вы работаете в ограниченной системе

С другой стороны * Намного больше работы и отладки * Диск не будет изначально распознан системой.

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

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

Сохранение позиции было записано каждые 5 минут или около того, что означает, что в случае отключения электроэнергии я потеряю только 5 минут журнала. Также возможно из последнего места записи проверить следующий сектор, содержат ли они действительные данные, прежде чем продолжить запись.

Это обеспечило очень надежное решение, поскольку вероятность повреждения таблицы очень мала.

Я бы также предложил буферизовать 512 байт и писать страницу за страницей.


Другие

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

person Damien    schedule 13.07.2017