Я хочу знать, какой оптимальный способ входа на 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?