Я хочу знать, каков оптимальный способ входа на SSD. Подумайте о чем-то вроде журнала базы данных, где вы пишете только для добавления, но вы также должны использовать fsync () для каждой транзакции или нескольких транзакций, чтобы обеспечить долговечность данных на уровне приложения.
Я собираюсь рассказать о том, как работают твердотельные накопители, поэтому, если вы уже знаете все это, пожалуйста, в любом случае, просмотрите их, если я что-то не так. Некоторые хорошие вещи для дальнейшего чтения Эммануэль Гусаерт, руководство из 6 частей по кодированию для твердотельных накопителей и бумага Не складывайте свой журнал в мой журнал [pdf].
SSD пишут и читают только на целых страницах. Где размер страницы отличается от SSD к SSD, но обычно кратен 4 КБ. Мой Samsung EVO 840 использует размер страницы 8 КБ (что, кстати, Линус называет «непригодным дерьмом» в его обычной красочной манере.) SSD не могут изменять данные на месте, они могут записывать только на свободные страницы. Таким образом, объединяя эти два ограничения, обновление одного байта в моем EVO требует чтения страницы 8 КБ, изменения байта и записи его на новую страницу 8 КБ, а также обновления отображения страницы FTL (структура данных ssd), так что логический адрес этой страницы как понимает ОС, теперь указывает на новую физическую страницу. Поскольку данные файла также больше не являются смежными в одном и том же блоке стирания (наименьшей группе страниц, которые можно стереть), мы также создаем форму долга фрагментации, которая будет стоить нам в будущем при сборе мусора в SSD. Ужасно неэффективно.
Как пример, глядя на мою файловую систему ПК:
C:\WINDOWS\system32>fsutil
Он имеет размер сектора 512 байт и выделение 4 КБ.
fsinfo ntfsinfo c:
(размер кластера. Ни одна из которых не соответствует размеру страницы SSD — вероятно,
не очень эффективно.
Есть некоторые проблемы с написанием, например, с помощью pwrite()
в кеш страницы ядра и позволяя ОС обрабатывать записи. Прежде всего, вам нужно оформить дополнительный sync_file_range()
звонить после звонка pwrite()
на самом деле сбросить IO, иначе все будет ждать, пока вы не позвоните fsync()
и развязать шторм IO. во-вторых fsync()
кажется заблокировать будущие звонки write()
в том же файле. Наконец, у вас нет контроля над тем, как ядро записывает данные на SSD, что оно может делать хорошо или плохо, вызывая значительное усиление записи.
По указанным выше причинам, и потому что мне все равно нужен AIO для чтения журнала, я выбираю запись в журнал с помощью O_DIRECT и O_DSYNC и полный контроль над ним.
Насколько я понимаю, O_DIRECT требует, чтобы все записи были выровнены по размеру сектора и по целому числу секторов. Поэтому каждый раз, когда я решаю добавить приложение в журнал, мне нужно добавить в конец некоторые отступы, чтобы поднять его до целого числа секторов (если все записи всегда представляют собой целое число секторов, они также будут правильно выровнены по крайней мере, в моем коде.) Хорошо, это не так плохо. Но мой вопрос: не лучше ли округлить до целого числа страниц SSD вместо секторов? Предположительно, что бы устранить усиление записи?
Это может сжечь огромное количество места, особенно если записывать небольшие объемы данных в журнал за раз (например, пару сотен байт). Это также может быть ненужным. SSD, такие как Samsung EVO, имеют кэш записи, и они не сбрасывают его в fsync (). Вместо этого они полагаются на конденсаторы для записи кеша на SSD в случае потери питания. В этом случае, может быть, SSD делает правильную вещь с журналом добавления только для записей, записываемых за один раз — он может не записать последнюю частичную страницу до тех пор, пока не появится следующее добавление (я) и не завершит его (или пока оно не будет вытеснено кэша из-за большого количества несвязанных операций ввода-вывода.) Поскольку ответ на этот вопрос, вероятно, зависит от устройства и, возможно, от файловой системы, есть ли способ, которым я могу кодировать две возможности и проверить свою теорию? Какой-нибудь способ измерить усиление записи или количество обновленных / RMW страниц в Linux?
Я постараюсь ответить на ваш вопрос, так как у меня была та же задача, но на SD-картах, которые все еще являются флэш-памятью.
Вы можете записать во флэш-память только полную страницу размером 512 байт. Учитывая, что флэш-память имеет плохое количество записей, ядро буферизует, чтобы увеличить время жизни вашего накопителя.
Чтобы записать немного во флэш-память, вы должны стереть всю страницу, где она находится в первую очередь. Поэтому, если вы хотите добавить или изменить 1 байт к уже записанной странице размером 400 байт, ядро в основном сделает:
Сектор (страницы) в основном относится к самому аппаратному обеспечению реализации флэш-памяти и физическому драйверу флэш-памяти, в которой вы не можете управлять. Эти страницы должны быть очищены и переписаны каждый раз, когда вы что-то меняете.
Как вы, вероятно, уже знаете, вы не можете переписать один бит на странице без очистки и перезаписи всего 512 байт. Теперь флэш-накопители имеют цикл записи около 100 000, прежде чем сектор может быть поврежден. Чтобы увеличить время жизни, обычно физический драйвер, а иногда и система будут иметь алгоритм рандомизации записи, чтобы всегда не писать один и тот же сектор.
Что касается кластера, это обрабатывается на более высоком уровне, который связан с файловой системой, и это у вас есть контроль. Обычно, когда вы форматируете новый жесткий диск, вы можете выбрать размер кластера, который в Windows относится к размеру распределительной единицы окна форматирования.
Насколько я знаю, большинство файловых систем работают с индексом, который находится в начале диска. Этот индекс будет отслеживать каждый кластер и то, что ему назначено. Это означает, что файл будет занимать как минимум 1 сектор, даже если он намного меньше.
Теперь компромисс меньше — размер вашего сектора, больше будет ваша таблица индексов и займет много места. Но если у вас много маленьких файлов, у вас будет больше места для работы.
С другой стороны, если вы храните только большие файлы и хотите выбрать самый большой размер сектора, чуть больше, чем ваш размер файла.
Поскольку ваша задача заключается в ведении журнала, я бы порекомендовал войти в один большой файл с большим размером сектора. После экспериментов с этим типом журнала наличие большого количества файлов в одной папке может вызвать проблемы, особенно если вы используете встроенные устройства.
Теперь, если у вас есть сырой доступ к диску и вы хотите по-настоящему оптимизировать, вы можете напрямую записывать на диск без использования файловой системы.
На верху
* Сэкономит вам достаточно места на диске
* Сделает диск терпимым в случае сбоя, если ваш дизайн достаточно умен
* потребует гораздо меньше ресурсов, если вы находитесь в ограниченной системе
С другой стороны
* Гораздо больше работы и отладки
* Диск не будет распознаваться системой.
Если вы только регистрируетесь, вам не нужна файловая система, вам просто нужна точка входа на страницу, где вы будете записывать свои данные, которая будет постоянно увеличиваться.
Реализация, которую я сделал на SD-карте, заключалась в том, чтобы при начале флэш-памяти сохранять 100 страниц для хранения информации о месте записи и чтения. Это было на одной странице, но чтобы избежать проблемы с циклом памяти, я бы последовательно писал циклическим методом на 100 страницах, а затем имел алгоритм проверки, который был последним, который содержал самую последнюю информацию.
Запись положения была сделана каждые 5 минут или около того, что означает, что в случае отключения электроэнергии я потерял бы только 5 минут журнала. Также возможно из последнего местоположения записи проверить дальнейший сектор, если они содержат действительные данные, прежде чем продолжить запись.
Это обеспечило очень надежное решение, поскольку вероятность повреждения таблицы очень мала.
Я бы также предложил буферизовать 512 байт и записывать страницу за страницей.
Вы также можете проверить некоторые журналы конкретной файловой системы, они могут просто сделать работу за вас: Лог-структурированная файловая система
Других решений пока нет …