C — Как записать журналы приложений на диск даже в случае внезапного отключения питания

#c #logging #memory #flush

#c #ведение журнала #память #флеш

Вопрос:

Краткая справочная информация:

Я разрабатываю встроенное приложение Linux на беспилотнике. В последнем полевом тесте, который у нас был, заряд батареи закончился без какого-либо предупреждения во время полета. У дрона была грубая посадка. Когда я перезапустил его в лаборатории, из 20 файлов журналов (* CSV и * TXT разных прикладных модулей) только в 3 были данные, а остальные были полностью пустыми, но, очевидно, они были! чтобы иметь данные, и их много. (14 минут полета = 840 секунд, и при частоте 50 Гц ожидается, что в наших журналах будет 10 тысяч строк данных).

Итак, у меня есть 2 вопроса:

  1. Возможно ли, что, хотя некоторые журналы сбрасываются каждые несколько секунд (или реже — возможно, при каждой команде записи), другие журналы хранятся в большом буфере, который сбрасывается в память только при чистом отключении питания или при исчерпании буфера?
  2. Учитывая, что мы используем C , как лучше всего сделать так, чтобы все журналы чаще сбрасывались на диск (чтобы в случае внезапного отключения питания у меня все еще оставалось несколько журналов для проверки) и при этом как можно меньше влияли на производительность?

Спасибо

Комментарии:

1. Просто используйте flush и sync периодически и надейтесь на лучшее.

2. что вы используете для ведения журнала? Если вы параноик и регистрируетесь не слишком часто, просто сбрасывайте после каждого сообщения

3. Дело не в том, чтобы быть параноиком. Мне требуется сохранять 50 строк журнала в секунду, но есть компромисс с производительностью, когда каждая команда «write» должна быть сброшена. следовательно — вопрос № 2

4. Действительно ли произошла запись файла, но запись в каталоге (содержащая размер файла) не обновлялась?

Ответ №1:

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

У вас ДЕЙСТВИТЕЛЬНО возникают проблемы с производительностью при сбросе каждой записи? Или это только теоретически?

Используйте одну или несколько из следующих рекомендаций в зависимости от вашей ситуации.

  1. Оптимизируйте ведение журнала. Вам действительно нужно так много записывать? Удалите отладочные материалы, которые должны быть там только тогда, когда вы занимаетесь разработкой, а не при тестировании или производстве. Подождите, пока процессор не будет занят, чтобы очистить журналы в очереди. Используйте отдельный поток для ведения журнала (потоки добавляют слишком много хлопот, чтобы стоить затраченных усилий, если только нет другого способа обойти проблему). Может быть, вместо этого записать в системный журнал? (Я не знаю, обладает ли syslog потрясающими возможностями очистки журнала или нет). Поскольку беспилотник находится в контакте с базовой станцией или контроллером, можете ли вы просто войти в систему по беспроводному соединению, и фактическое хранение журналов на диске даже не выполняется в беспилотнике?
  2. Если вы действительно пытались удалять каждую запись (или время от времени), и это слишком сильно замедлило работу вашего приложения, убедитесь, что в вашей среде Linux не работает какой-либо другой мусор, который крадет процессор или добавляет чтение / запись с диска, и который вы даже не используете.
  3. Всегда записывайте полную запись (или несколько объединенных записей) с помощью одного вызова функции. Не записывайте отдельные части записи с отдельными функциями. Если что-то выйдет из строя, вы получите частично записанную запись. Сначала объедините все элементы вашей записи в памяти, затем запишите все целиком, бум, готово. Записи Linux кажутся атомарными. После запуска они будут полностью выполнены, и никто другой не будет их прерывать, НО убедитесь, что вы открываете файлы в режиме добавления, чтобы избежать путаницы в отношении того, где будут происходить записи. В режиме добавления запись всегда будет в конце файла, даже если кто-то другой вставит запись до того, как вы это сделаете. Несколько авторов не похоже на проблему, с которой вам приходится иметь дело.
  4. Не создавайте буфер в своем приложении для ускорения (у вас могут быть другие причины). Это старомодное дерьмо, которому вас, вероятно, научил профессор, чьи знания устарели. Вероятно, в вашей операционной системе уже есть буфер записи. Вам не нужно делать это самостоятельно, и на самом деле это вызовет много проблем, если нескольким процессам потребуется общий доступ к файлу.
  5. Не используйте 50-летние функции C 1970-х годов, такие как fwrite или iostreams>> мерзости (это просто доказательства концепции, которые каким-то образом были адаптированы в качестве стандарта). Они могут выполнять свою собственную внутреннюю буферизацию. Используйте функцию write() операционной системы. Если ваша ОС Linux, выполните «man 2 write». Конечно, вам также нужно открывать и закрывать файлы с помощью других функций уровня ОС. Сделайте «man 2 open». Существуют всевозможные опции для управления кэшированием диска и т. Д. Вы можете открыть файл с атрибутом O_DIRECT, означающим «попросите операционную систему минимизировать кэширование» и O_DSYNC, что означает, что ваша запись не вернется, пока она не будет полностью сброшена на диск. Это позволит максимально обойти буфер записи на уровне ОС. Это зависит от вас и от того, что вам требуется.
  6. Иногда доступны «асинхронные» функции (do «man aio»), где вам не нужно ждать завершения записи. Операционная система справится с ними за вас и, по крайней мере, сделает все возможное. Даже если он отстает, пока вы записываете полную запись за раз, это сведет к минимуму повреждение, если что-то пойдет не так.
  7. Вы хотите использовать файловую систему с журналом, такую как Linux ext4, которая фактически не добавляет записи в файл, пока не будет подтверждено, что они были полностью записаны на диск. И если что-то пойдет не так, когда диск будет перемонтирован, он восстановит себя (насколько это возможно).

Мне пришлось написать приложение с сохранением целостности файла, и мне нужно было буферизировать записи (потому что событие во время обработки может сообщить приложению «не записывайте эти записи в очередь, мы передумали»). Чтобы избежать осложнений, все объединяется в одну строку, а затем записывается с помощью одной функции write(), когда приходит время. У меня никогда не было поврежденного файла, даже когда приложение было выключено, это приведет к уничтожению -9. ОДНАКО у него никогда не было сбоев питания. (Резервное копирование ИБП).

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