- Вопрос или проблема
- 1. Хранилище на основе флэш-памяти
- 2. Вращающиеся жесткие диски
- 2.1 Если вы не знаете, что такое контракт fsync()
- Ответ или решение
- Принцип работы файловых систем в Linux
- Кэширование и задержки записи
- Проблемы с отключением питания
- Использование fsync()
- Разные типы накопителей
- Рекомендации
- Заключение
Вопрос или проблема
Ранее я думал, что изменения в файлах сохраняются напрямую на диск, то есть, как только я закрываю файл и решаю нажать/выбрать “Сохранить”. Однако в недавнем разговоре друг сказал мне, что это обычно не так; операционная система (в частности, мы говорили о системах Linux) сохраняет изменения в памяти и имеет демона, который фактически записывает содержимое из памяти на диск.
Он даже привел пример внешних флеш-накопителей: они монтируются в систему (копируются в память), и иногда происходит потеря данных, потому что демон еще не сохранил содержимое во флеш-память; вот почему мы размонтируем флеш-накопители.
Я не разбираюсь в функционировании операционных систем, и поэтому у меня совершенно нет представления, истинно ли это и при каких обстоятельствах. Мой основной вопрос: происходит ли это, как описано, в системах Linux/Unix (и, возможно, других ОС)? Например, значит ли это, что если я выключу компьютер немедленно после редактирования и сохранения файла, мои изменения, скорее всего, будут потеряны? Возможно, это зависит от типа диска — традиционные жесткие диски против твердотельных накопителей?
Вопрос касается в частности файловых систем, которые имеют диск для хранения информации, хотя любые уточнения или сравнения приветствуются.
если я выключу компьютер немедленно после редактирования и сохранения файла, мои изменения, скорее всего, будут потеряны?
Возможно, так и будет. Я бы не сказал “скорее всего”, но вероятность зависит от множества факторов.
Простой способ увеличить скорость записи файлов — это то, что ОС просто кэширует данные, говорит (лжет) приложению, что запись прошла успешно, а затем фактически производит запись позже. Это особенно полезно, если в это же время происходит другая активность с диском: ОС может приоритизировать чтение и сделать запись позже. Это также может полностью устранить необходимость в фактической записи, например, в случае, когда временный файл быстро удаляется после этого.
Проблема кэширования более выражена, если хранилище медленное. Копирование файлов с быстрого SSD на медленную USB-флешку, вероятно, будет сопряжено с большим количеством кэширования записи, поскольку USB-флешка просто не может справиться с нагрузкой. Но ваша команда cp
завершится быстрее, так что вы можете продолжать работать, возможно, редактируя файлы, которые только что были скопированы.
Конечно, такое кэширование имеет негативные стороны, которые вы отмечаете: некоторые данные могут быть потеряны до того, как они фактически будут сохранены. Пользователь будет недоволен, если его редактор скажет ему, что запись прошла успешно, но файл на самом деле не был на диске. Поэтому существует fsync()
системный вызов, который должен возвращаться только после того, как файл действительно попадет на диск. Ваш редактор может использовать это, чтобы убедиться, что данные в порядке, прежде чем сообщить пользователю, что запись прошла успешно.
Я сказал “должен”, поскольку сам диск может рассказывать одни и те же сказки ОС и говорить, что запись завершена, в то время как файл на самом деле существует только в временном кэше записи внутри диска. В зависимости от диска, может не быть возможности избежать этого.
В дополнение к fsync()
, существуют также системные вызовы sync()
и syncfs()
, которые просят систему убедиться, что все записи на уровне системы или все записи в определенной файловой системе попали на диск. Утилиту sync
можно использовать для вызова этих функций.
Существует также O_DIRECT
флаг для open()
, который должен “попробовать минимизировать эффекты кэширования ввода-вывода для этого файла”. Устранение кэширования снижает производительность, поэтому этим в основном пользуются приложения (базы данных), которые делают свое собственное кэширование и хотят контролировать его. (O_DIRECT
не лишен своих проблем, комментарии к нему в справочной странице несколько забавны.)
Что происходит при отключении питания, также зависит от файловой системы. Вы должны беспокоиться не только о данных файла, но и о метаданных файловой системы. Наличие данных файла на диске не имеет большого смысла, если вы не можете их найти. Просто увеличение размера файла потребует выделения новых блоков данных, и их нужно будет где-то отметить.
Как файловая система обрабатывает изменения метаданных и порядок между записями метаданных и данных очень варьируется. Например, с ext4
, если вы установите флаг монтирования data=journal
, то все записи — даже записи данных — проходят через журнал и должны быть довольно безопасными. Это также означает, что их записывают дважды, так что производительность падает. По умолчанию параметры пытаются упорядочить записи так, чтобы данные были на диске до обновления метаданных. Другие параметры или другие файловые системы могут быть лучше или хуже; я даже не попытаюсь провести всестороннее исследование.
На практике, в системе с небольшой нагрузкой, файл должен попасть на диск в течение нескольких секунд. Если вы работаете с съемным хранилищем, размонтируйте файловую систему перед тем, как извлекать носитель, чтобы убедиться, что данные на самом деле отправлены на диск, и больше нет активности. (Или позвольте вашему GUI окружению сделать это за вас.)
Существует очень простой способ доказать, что не может быть правдой, что исправления файлов всегда напрямую сохраняются на диск, а именно тот факт, что есть файловые системы, которые в первую очередь не поддерживаются диском. Если файловая система не имеет диска в первую очередь, то она никогда не сможет записать изменения на диск, никогда.
Некоторые примеры:
tmpfs
, файловая система, которая существует только в ОП (или, точнее, в кэше буфера)ramfs
, файловая система, которая существует только в ОП- любая сетевая файловая система (NFS, CIFS/SMB, AFS, AFP и т.д.)
- любой виртуальный файловая система (
sysfs
,procfs
,devfs
,shmfs
и т.д.)
Но даже для файловых систем, поддерживаемых дисками, это обычно не правда. Страница Как испортить базу данных SQLite имеет главу, называемую Отказ в синхронизации, которая описывает множество различных способов, при помощи которых записи (в данном случае подтверждения в базу данных SQLite) могут не попасть на диск. SQLite также имеет белую книгу, в которой объясняются многочисленные условия, которые необходимо выполнить, чтобы гарантировать Атомарную Коммит в SQLite. (Обратите внимание, что Атомарная Запись — это гораздо более сложная проблема, чем просто Запись, но, конечно, запись на диск является подзадачей атомарной записи, и вы также можете многому научиться об этой проблеме из этой книги.) В этой книге есть раздел о Вещах, которые могут пойти не так, который содержит подраздел о Неполных сбросах на диск, который дает некоторые примеры тонких тонкостей, которые могут помешать записи на диск (например, контроллер HDD может сообщать, что он записал на диск, когда на самом деле этого не произошло — да, есть производители HDD, которые делают это, и это может даже быть законным в соответствии со спецификацией ATA, поскольку она неоднозначно сформулирована в этом отношении).
Верно, что большинство операционных систем, включая Unix, Linux и Windows используют кэш записи для ускорения операций. Это означает, что выключение компьютера без его завершения — плохая идея и может привести к потере данных. То же самое верно, если вы извлечете USB-накопитель, прежде чем он будет готов к извлечению.
Большинство систем также предлагают возможность делать записи синхронными. Это означает, что данные будут на диске до того, как приложение получит подтверждение успеха, ценой снижения скорости.
Коротко говоря, есть причина, по которой вы должны правильно завершать работу на своем компьютере и правильно подготавливать USB-накопители к извлечению.
1. Хранилище на основе флэш-памяти
Зависит ли это от типа диска (традиционные жесткие диски против твердотельных накопителей) или от каких-либо других переменных, о которых я, возможно, не знаю? Происходит ли это (если да) только в Linux или присутствует в других ОС?
Когда у вас есть выбор, вы не должны допускать, чтобы хранилище на основе флеш-памяти теряло питание без чистого завершения работы.
На недорогих носителях, таких как SD-карты, вы можете ожидать потерю целых блоков стирания (в несколько раз больше 4 КБ), теряя данные, которые могут принадлежать разным файлам или важным структурам файловой системы.
Некоторые дорогие SSD могут заявлять о предоставлении лучших гарантий в случае сбоя питания. Однако сторонние тесты показывают, что многие дорогие SSD не выполняют этого. Уровень, который перебрасывает блоки для “равномерного износа”, сложен и является собственностью. Возможные сбои включают потерю всех данных на диске.
Применяя нашу тестовую платформу, мы тестируем 17 недорогих SSD от шести различных производителей, используя более трех тысяч циклов инъекции ошибок в целом. Наши экспериментальные результаты показывают, что 14 из 17 протестированных устройств SSD демонстрируют удивительное поведение сбоев при сбоях питания, включая повреждение битов, обрезанные записи, несериализуемые записи, повреждение метаданных и полный сбой устройства.
2017: https://dl.acm.org/citation.cfm?id=2992782&preflayout=flat
2. Вращающиеся жесткие диски
Вращающиеся HDD имеют разные характеристики. Для безопасности и простоты я рекомендую предполагать, что у них такая же практическая неопределенность, как и у флеш-хранилищ.
Если у вас нет конкретных данных, чего у вас явно нет. У меня нет сравнительных данных для вращающихся HDD.
Жесткий диск может оставить один неполностью записанный сектор с ошибочной контрольной суммой, что приведет к сбою чтения позже. В широком смысле, этот режим сбоя HDD вполне ожидаем; родные файловые системы Linux разрабатываются с учетом этого. Они стремятся сохранить контракт fsync()
перед этим типом отключения питания. (Мы бы действительно хотели увидеть это, гарантированное на SSD).
Тем не менее, я не уверен, достигают ли файловые системы Linux этого во всех случаях, или это вообще возможно.
Следующая загрузка после этого типа сбоя может потребовать ремонта файловой системы. Так как это Linux, возможно, что ремонт файловой системы задаст вам вопросы, которые вы не поймете, и вам придется просто нажать Y и надеяться, что все разрешится.
2.1 Если вы не знаете, что такое контракт fsync()
Контракт fsync() — это источник как хороших, так и плохих новостей. Сначала вы должны понять хорошие новости.
Хорошие новости: fsync()
хорошо задокументировано как правильный способ записи данных файла, например, когда вы нажимаете “сохранить”. И широко воспринимается, что, например, текстовые редакторы должны заменять существующие файлы атомарно с использованием rename()
. Это должно гарантировать, что вы всегда либо сохраняете старый файл, либо получаете новый файл (который был fsync()
ed до переименования). Вы не хотите остаться с неполной версией нового файла.
Плохие новости: в течение многих лет вызов fsync() на самой популярной файловой системе Linux мог фактически оставить всю систему в состоянии зависания на десятки секунд. Поскольку приложения ничего с этим не могут сделать, было очень распространено оптимистично использовать rename() без fsync(), что казалось достаточно надежным на этой файловой системе.
Следовательно, существуют приложения, которые не используют fsync() корректно.
Следующая версия этой файловой системы, как правило, избегала зависания fsync() – одновременно с тем, как она начала полагаться на правильное использование fsync().
Все это довольно плохо. Понимание этой истории, вероятно, не помогло бы и пренебрежительное отношение и интриги, использованные многими конфликтующими разработчиками ядра.
Текущая резолюция такова, что самая популярная файловая система Linux по умолчанию поддерживает паттерн rename() без необходимости в fsync() реализует “совместимость по багам” с предыдущей версией. Это можно отключить с помощью параметра монтирования noauto_da_alloc
.
Это не полная защита. В основном это сбрасывает ожидающую подачу ввода-вывода на момент rename(), но не ждет завершения ввода-вывода до переименования. Это гораздо лучше, чем, например, 60-секундный риск! Смотрите также ответ на Какие файловые системы требуют fsync() для защиты от сбоев при замене существующего файла с помощью rename()?
Некоторые менее популярные файловые системы не предоставляют защиту. XFS отказывается это делать. И UBIFS тоже этого не реализовал, очевидно, это можно было бы принять, но это требует много работы для реализации. Эта же страница указывает, что у UBIFS есть несколько других проблем “TODO” для целостности данных, включая потерю питания. UBIFS — это файловая система, используемая непосредственно на флэш-памяти. Я предполагаю, что некоторые из сложностей, упомянутых UBIFS с флэш-памятью, могут быть актуальными и для ошибок SSD.
В системе с небольшой загрузкой ядро позволит написанным данным файла оставаться в кэше страниц, возможно, в течение 30 секунд после write()
, прежде чем сбросить их на диск, чтобы оптимизировать случай, когда файл будет удален или изменен снова в ближайшее время.
По умолчанию dirty_expire_centisecs
в Linux равен 3000 (30 секунд), и он контролирует, как долго новые данные “истекают”. (См. https://lwn.net/Articles/322823/).
Смотрите https://www.kernel.org/doc/Documentation/sysctl/vm.txt для получения дополнительной информации о связанных тонкостях и гуглите для получения множества другой информации. (например, гуглите по dirty_writeback_centisecs
).
По умолчанию для /proc/sys/vm/dirty_writeback_centisecs
в Linux значение 500 (5 секунд), и PowerTop рекомендует установить его на 1500 (15 секунд), чтобы снизить потребление электроэнергии.
Отложенная запись также дает время для ядра, чтобы увидеть, насколько большой будет файл, прежде чем начинать записывать его на диск. Файловые системы с отложенным выделением (такие как XFS, и, вероятно, другие на данный момент) даже не выбирают, где на диске разместить данные новозаписанного файла, пока это не станет необходимым, отдельно от выделения пространства для самого inode. Это снижает фрагментацию, позволяя избежать размещения начала большого файла в 1-мегабайтовом пробеле между другими файлами, например.
Если записывается много данных, то сброс на диск может быть запущен при достижении порога того, сколько грязных (еще не синхронизированных с диском) данных может быть в кэше страниц.
Однако если вы не делаете ничего другого, индикатор активности вашего жесткого диска не загорится в течение 5 (или 15) секунд после нажатия “Сохранить” в маленьком файле.
Если ваш редактор использовал fsync()
после записи файла, ядро запишет его на диск без задержки. (И fsync
не вернется, пока данные действительно не будут отправлены на диск).
Кэширование записи внутри диска также может иметь место, но диски обычно стараются как можно скорее сохранить свое кэширование записи в постоянное хранилище, в отличие от алгоритмов кэша страниц Linux. Кэши записи диска больше служат для хранения буфера для поглощения малых всплесков записи, но также могут задерживать записи в пользу чтений и давать прошивке диска место для оптимизации шаблона поиска (например, выполнять две близкие записи или чтения вместо выполнения одной, а затем долго искать, а затем возвращаться назад).
На вращающемся (магнитном) диске вы можете увидеть несколько задержек доступа от 7 до 10 мс каждое, прежде чем данные от команды записи SATA будут фактически безопасны от отключения питания, если перед вашей записью были ожидающие чтения/записи. (Некоторые другие ответы на этот вопрос содержат более подробную информацию о кэшах записи диска и барьерах записи, которые могут использовать журнальные файловые системы для избежания повреждений.)
Linux (как и другие системы UNIX) использует слоистую архитектуру ввода-вывода. Это означает, что если ваш процесс приложения (редактор) закрывает файл, то операционная система берет на себя данные и ответственность за их сохранение.
В зависимости от флагов, таких как “прямой ввод-вывод” (см. системный вызов open
), операционная система может задерживать запись данных на следующем уровне по причинам производительности (например, для упорядочивания блоков, которые должны быть записаны).
Также следующий уровень может быть диском, или это может быть логический том, RAID, NAS или SAN-хранилище. Такие хранилища могут дополнительно задерживать фактическую запись на диск, и даже если конечный уровень считает, что данные записаны на диск, сам диск может иметь кэш записи для задержки фактических записей на диске.
Так что, если вы хотите быть уверены, закройте свое приложение и правильно завершите работу операционной системы, подождите несколько секунд, а затем отключите питание (если диски и компьютер раздельны, сначала выключите компьютер, а затем диск).
Но на самом деле мне интересно: Почему этот вопрос важен?
Вы хотите сохранить файл в редакторе и немедленно выключить компьютер после этого, или вы беспокоитесь о потере данных из-за внезапного отключения питания? В последнем случае, ИБП (бесперебойное питание) может быть тем, что вам действительно нужно.
Ответ или решение
Вопрос о том, сохраняются ли изменения файлов в Linux напрямую на диск, представляет собой важный аспект работы операционных систем, и особенно Linux. Давайте подробно разберемся в этом вопросе.
Принцип работы файловых систем в Linux
Когда вы редактируете файл и сохраняете изменения, операционная система (ОС) не обязательно записывает данные прямо на диск сразу. Вместо этого, для повышения производительности, система использует кэширование. Изменения могут сохраняться в памяти (в оперативной памяти) и не немедленно записываться на диск. Это связано с особенностями работы файловых систем и управлением данными. То есть, при нажатии "сохранить" программа может сразу сообщить, что операция завершена успешно, но данные на самом деле еще могут находиться в кэше.
Кэширование и задержки записи
Linux использует концепцию кэширования записей, чтобы ускорить операции ввода-вывода. Например, новые данные могут оставаться в "страницах кэша" в течение 30 секунд, прежде чем они будут записаны на диск. Это делается для оптимизации записи, особенно если файл будет изменен или удален вскоре после сохранения. По умолчанию задержка перед записью составляет 3000 центисекунд (30 секунд).
cat /proc/sys/vm/dirty_expire_centisecs # Проверка времени хранения данных в кэше
В определенных ситуациях, когда система нагружена, записи могут быть выполнены неблагоприятным образом (например, при переборе определенных операций ввода-вывода), что может привести к потере данных, если пользователь выключит компьютер до завершения всех операций.
Проблемы с отключением питания
Если компьютер отключить до того, как данные будут записаны на диск, пользователи могут столкнуться с потерей данных. Это особенно актуально для флеш-накопителей: файлы могут не быть написаны на устройство, и, если их извлечь без правильной размонтировки, это может привести к потере данных.
Использование fsync()
Чтобы гарантировать, что данные действительно сохранены на диск, программное обеспечение может использовать системный вызов fsync()
. Этот вызов заставляет ОС завершить операции записи в диск и возвращает управление только после того, как данные будут записаны в постоянное хранилище. Однако и здесь могут возникнуть проблемы. Например, некоторые накопители могут сообщить ОС, что запись завершена, когда на самом деле данные все еще находятся в кеше на уровне устройства.
Разные типы накопителей
Различия в поведении могут быть также связаны с типом накопителей:
-
Традиционные жесткие диски (HDD) – данные могут быть потеряны, если происходят сбои в процессе записи из-за временной записи сектора или проблемы с кэшированием.
-
Твердотельные накопители (SSD) – некоторые SSD могут предложить улучшенные гарантии сохранности, но, как показывают исследования, они также могут не выполнять эти гарантии. Некоторые накопители демонстрировали потерю данных в результате внезапного отключения питания.
Рекомендации
- Синхронные записи: Используйте синхронные записи (с помощью
fsync()
) для приложений, где важна надежность данных. - Правильное выключение: Никогда не выключайте компьютер сразу после редактирования файла. Лучше дать системе время для записи данных на диск, дождитесь завершения всех операций записи.
- Использование UPS: Для защиты оборудования и данных в случае отключения питания можно использовать бесперебойное питание (UPS).
Заключение
Таким образом, действительно, изменения файла в Linux не всегда сохраняются сразу на диск, а могут оставаться в памяти. Чтобы защитить свои данные, рекомендуется уважать принципы безопасного доступа к данным и правильно завершать работу системы. Понимание этой концепции поможет вам избегать потерь данных и обеспечит надежность обработки ваших файлов.