Назад | Перейти на главную страницу

Войти через FIFO, а затем перенаправить в файл?

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

Мы пришли к следующему:

То есть то, что обычно было:

app --logfile logfile.txt

сейчас:

mkfifo logfifo
cat logfifo &> logfile.txt &
app --logfile logfifo

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

(У нас нет исходного кода приложения, поэтому о решениях для программирования не может быть и речи. Кроме того, приложение не будет писать в stdout, поэтому о прямом подключении к другой команде не может быть и речи. Так syslog это невозможно.)


Обновить: Я добавил награду. Принятый ответ будет не вовлекать logger по той простой причине, что logger является не о чем я спрашивал. Как говорится в исходном вопросе, я ищу только подводные камни при использовании FIFO.

Обратите внимание, что FIFO обычно требуется при программировании, когда записанная сумма может превышать считываемую.

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

Есть три возможных предостережения.

  1. Запись в fifo блокируется на неопределенный срок, если при инициализации ничто не читает другой конец.
  2. FIFO имеет фиксированную ширину 64 КБ, на которую, если буфер будет заполнен к этой точке, дальнейшие записи будут блокироваться до тех пор, пока устройство чтения не догонит его.
  3. Канальный писатель будет убит с помощью SIGPIPE, если читатель умрет или завершит работу.

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

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

Еще один момент, о котором следует упомянуть, - если сервер паникует и ядро ​​перестает отвечать, вы можете потерять до 64 КБ данных, которые были в этом буфере.

Другой способ исправить это - записать журналы в tmpfs (/ dev / shm в Linux) и привязать вывод к фиксированному месту на диске. Для этого существуют менее строгие ограничения на выделение памяти (не 64 КБ, обычно 2 ГБ!), Но они могут не сработать для вас, если писатель не имеет динамического способа повторно открывать файлы журнала (вам придется периодически очищать журналы из tmpfs). Если сервер паникует в этом методе, вы можете потерять НАМНОГО больше данных.

mkfifo logfifo
cat logfifo &> logfile.txt &
app --logfile logfifo

Что происходит, когда ваш cat logfifo процесс умирает, кто-то случайно его убивает, или кто-то случайно указывает не на то место?

Мой опыт показывает, что app быстро заблокируется и зависнет. Я пробовал это с Tomcat, Apache и несколькими небольшими домашними приложениями и столкнулся с той же проблемой. Я никогда не исследовал очень далеко, потому что logger или простое перенаправление ввода-вывода сделало то, что я хочу. Обычно мне не нужна полнота ведения журнала, к которой вы стремитесь. И, как вы говорите, вам не нужен регистратор.

Обсуждение этой проблемы есть на Linux неблокирующий fifo (ведение журнала по запросу).

Ваши возможности довольно ограничены приложением, но то, что вы тестировали, будет работать.

Нечто подобное мы делаем с лаком и лаком, чтобы добыть полезные журналы. У нас есть фифо, мы просто читаем его с помощью syslog-ng и отправляем туда, где нам нужно. Мы обрабатываем около 50 ГБ и пока не сталкивались с проблемой такого подхода.

Среда - CentOS, и приложение записывает в файл ...

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

Вы должны иметь возможность использовать такой сценарий оболочки:

logger -p daemon.notice -t app < fifo

Вы также можете принять участие (в logger) из cat или из tail -f в трубу:

tail -f fifo | logger ...
cat fifo | logger ...

Единственная проблема заключается в том, что он не различается в зависимости от важности сообщения журнала (все УВЕДОМЛЕНИЕ), но по крайней мере он регистрируется и также отправляется за пределы хоста на центральный сервер.

Настройка системного журнала зависит от того, какой сервер вы используете. Там есть rsyslog и syslog-ng (обе очень способный).

РЕДАКТИРОВАТЬ: Изменено после получения дополнительной информации с плаката.

Ты пишешь:

Также приложение не будет писать на stdout...

Вы пробовали зайти в "файл" /dev/stdout? Это может позволить вам сделать что-то вроде:

app --logfile /dev/stdout | logger -t app

Нет смысла записывать в FIFO, а затем заставлять другой процесс записывать его в файл. Просто напишите прямо в файл, как только write() возвращается, это в руках ядра; он все равно будет записывать его на диск, если приложение выйдет из строя.