Есть класс жалоб, которые в форумах про домашние серверы повторяются годами: «SD-карта в одноплатнике сдохла за полгода», «journal отъел четыре гигабайта на VPS с диском на двадцать», «после отключения питания журнал битый и ничего не прочитать». Выглядит как три разные проблемы, а корень у них общий — устройство журнального файла systemd.
Поводом вернуться к теме стал свежий отчёт в трекере systemd (issue #40262 от 13 августа): виртуалка на Debian 13 выдаёт порядка 50 IOPS на две строки лога в секунду. Мейнтейнеры пока не ответили, независимо цифру никто не перепроверял, так что считаем её одним замером на одной конфигурации, а не доказанным фактом.
Ниже — четыре симптома, механика за каждым и конкретные значения, которые стоит поменять. Все дефолты взяты из man journald.conf, устройство файла — из официального описания формата.
Симптом 1. Диск постоянно что-то пишет, хотя логов почти нет
Что происходит. Журнал systemd — не текстовый файл, куда дописывается строка. Это индексированная база с хеш-таблицами и массивами смещений, спроектированная под быстрый journalctl -u nginx --since ... по любому полю.
При записи одной строки обновляются: заголовок файла (счётчики записей и объектов, смещение хвоста, sequence number), по объекту DATA на каждую уникальную пару «поле=значение» (а их к вашему сообщению systemd добавляет с десяток: _PID, _UID, _SYSTEMD_UNIT, _BOOT_ID, _HOSTNAME, _MACHINE_ID, PRIORITY и так далее), объекты FIELD на новые имена полей, цепочки в двух хеш-таблицах и массивы ENTRY_ARRAY.
Сверху на это ложится порядок записи, прямо описанный в спецификации формата: сначала все новые объекты дописываются в конец файла, и только потом проставляются ссылки в уже существующие структуры. То есть файл трогается как минимум дважды, в разных местах.
❗ Главное
Это не баг, а осознанный размен: журнал платит записью на диск за то, чтобы поиск по полям был быстрым и не требовал grep по гигабайтам текста. Вопрос только в том, нужен ли вам этот размен на устройстве, где ресурс записи ограничен.
Что делать. Если машина — домашний сервер, где логи нужны «на случай разбора полётов», а не для аналитики, разумно уменьшить объём того, что вообще попадает в журнал: убрать debug-уровни у болтливых юнитов, а для контейнеров переключить драйвер логов Docker с journald на local или json-file с ротацией — иначе всё, что печатают контейнеры, дублируется в системный журнал.
Симптом 2. Журнал занимает гигабайты
Что происходит. По умолчанию SystemMaxUse — это 10% размера файловой системы, но не больше 4 ГБ; SystemKeepFree — 15% свободного места; SystemMaxFileSize — одна восьмая от SystemMaxUse, но не больше 128 МБ; SystemMaxFiles — 100 файлов. То есть на диске в 40 ГБ журнал имеет полное право занять 4 ГБ, и это штатное поведение, а не утечка.
Постоянное ограничение — в /etc/systemd/journald.conf.d/00-limits.conf (отдельный drop-in лучше правки основного файла: он переживёт обновление пакета):
После правки — sudo systemctl restart systemd-journald.
Симптом 3. SD-карта или дешёвый SSD деградируют
Что происходит. Именно здесь механика из первого симптома превращается в деньги. Постоянный поток мелких записей в разные участки файла — худший из сценариев для флеш-памяти без нормального контроллера, а SD-карта в одноплатнике это ровно такой случай.
⚠️ Осторожно
Мигрировать на Storage=volatile бездумно не стоит: в этом режиме журнал живёт только в /run и полностью исчезает при перезагрузке. Если сервер упал ночью, утром вы не узнаете почему.
✅ Как правильно
Рабочая схема для одноплатника:
Storage=volatile в journald — журнал в RAM, ограниченный RuntimeMaxUse;
параллельно ForwardToSyslog=yes и лёгкий syslog-демон, который пишет обычный текстовый файл с ротацией — либо сразу отправка логов на другую машину;
если внешнего приёмника нет — компромисс: оставить Storage=persistent, но зажать SystemMaxUse=50M и поднять SyncIntervalSec, чтобы сократить число сбросов на диск.
Симптом 4. После жёсткой перезагрузки журнал битый
Что происходит.SyncIntervalSec по умолчанию — 5 минут. Это таймаут принудительной синхронизации журнальных файлов на диск. Исключение сделано для приоритетов CRIT, ALERT и EMERG: после такого сообщения синхронизация выполняется немедленно.
Отсюда две вещи сразу. Во-первых, при внезапном пропадании питания вы теряете до пяти минут логов — тех самых, которые обычно и интересны. Во-вторых, отсюда же растут жалобы на повреждённые файлы журнала: незакрытый файл после жёсткого ребута приходится восстанавливать.
📌 Заметка
Уменьшение SyncIntervalSec спасает логи, но увеличивает число операций записи — то есть прямо противоречит лечению симптома 3. Выбирать приходится осознанно: либо ресурс носителя, либо полнота логов при аварии. Третий вариант — отправлять логи на другую машину и не решать эту дилемму локально.
Ещё две настройки, о которых редко вспоминают
Compress включён по умолчанию, порог — 512 байт: всё, что крупнее, сжимается. Для типичных однострочных сообщений это означает, что сжатие не срабатывает вообще.
Seal (Forward Secure Sealing, HMAC-SHA-256 поверх журнала для защиты от подделки задним числом) в man описан как включённый по умолчанию, но реально печать появляется только после того, как вы сгенерируете ключи через journalctl --setup-keys. Без этого шага TAG-объекты в файл не пишутся, и «включено по умолчанию» на практике не означает «работает».
Что проверить прямо сейчас
journalctl --disk-usage # сколько занято
systemd-analyze cat-config systemd/journald.conf # какие значения реально применились
journalctl --verify # цел ли журнал
Если --disk-usage показывает сотни мегабайт на машине, где вы никогда не читали логи старше недели, — это и есть ответ на вопрос, куда девался ресурс диска.
Кто как решил вопрос с логами на одноплатниках: log2ram, вынос журнала в RAM, отправка на отдельную машину или просто «поставил SSD и не думаю»? И сталкивался ли кто-нибудь с реально битым журналом после отключения питания?
Вы можете написать сейчас и зарегистрироваться позже.
Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.
Есть класс жалоб, которые в форумах про домашние серверы повторяются годами: «SD-карта в одноплатнике сдохла за полгода», «journal отъел четыре гигабайта на VPS с диском на двадцать», «после отключения питания журнал битый и ничего не прочитать». Выглядит как три разные проблемы, а корень у них общий — устройство журнального файла systemd.
Поводом вернуться к теме стал свежий отчёт в трекере systemd (issue #40262 от 13 августа): виртуалка на Debian 13 выдаёт порядка 50 IOPS на две строки лога в секунду. Мейнтейнеры пока не ответили, независимо цифру никто не перепроверял, так что считаем её одним замером на одной конфигурации, а не доказанным фактом.
Ниже — четыре симптома, механика за каждым и конкретные значения, которые стоит поменять. Все дефолты взяты из man journald.conf, устройство файла — из официального описания формата.
Симптом 1. Диск постоянно что-то пишет, хотя логов почти нет
Что происходит. Журнал systemd — не текстовый файл, куда дописывается строка. Это индексированная база с хеш-таблицами и массивами смещений, спроектированная под быстрый
journalctl -u nginx --since ...по любому полю.При записи одной строки обновляются: заголовок файла (счётчики записей и объектов, смещение хвоста, sequence number), по объекту DATA на каждую уникальную пару «поле=значение» (а их к вашему сообщению systemd добавляет с десяток:
_PID,_UID,_SYSTEMD_UNIT,_BOOT_ID,_HOSTNAME,_MACHINE_ID,PRIORITYи так далее), объекты FIELD на новые имена полей, цепочки в двух хеш-таблицах и массивы ENTRY_ARRAY.Сверху на это ложится порядок записи, прямо описанный в спецификации формата: сначала все новые объекты дописываются в конец файла, и только потом проставляются ссылки в уже существующие структуры. То есть файл трогается как минимум дважды, в разных местах.
❗ Главное
Это не баг, а осознанный размен: журнал платит записью на диск за то, чтобы поиск по полям был быстрым и не требовал grep по гигабайтам текста. Вопрос только в том, нужен ли вам этот размен на устройстве, где ресурс записи ограничен.
Что делать. Если машина — домашний сервер, где логи нужны «на случай разбора полётов», а не для аналитики, разумно уменьшить объём того, что вообще попадает в журнал: убрать debug-уровни у болтливых юнитов, а для контейнеров переключить драйвер логов Docker с
journaldнаlocalилиjson-fileс ротацией — иначе всё, что печатают контейнеры, дублируется в системный журнал.Симптом 2. Журнал занимает гигабайты
Что происходит. По умолчанию
SystemMaxUse— это 10% размера файловой системы, но не больше 4 ГБ;SystemKeepFree— 15% свободного места;SystemMaxFileSize— одна восьмая отSystemMaxUse, но не больше 128 МБ;SystemMaxFiles— 100 файлов. То есть на диске в 40 ГБ журнал имеет полное право занять 4 ГБ, и это штатное поведение, а не утечка.Что делать. Разовая уборка:
Постоянное ограничение — в
/etc/systemd/journald.conf.d/00-limits.conf(отдельный drop-in лучше правки основного файла: он переживёт обновление пакета):После правки —
sudo systemctl restart systemd-journald.Симптом 3. SD-карта или дешёвый SSD деградируют
Что происходит. Именно здесь механика из первого симптома превращается в деньги. Постоянный поток мелких записей в разные участки файла — худший из сценариев для флеш-памяти без нормального контроллера, а SD-карта в одноплатнике это ровно такой случай.
⚠️ Осторожно
Мигрировать на
Storage=volatileбездумно не стоит: в этом режиме журнал живёт только в/runи полностью исчезает при перезагрузке. Если сервер упал ночью, утром вы не узнаете почему.✅ Как правильно
Рабочая схема для одноплатника:
Storage=volatileв journald — журнал в RAM, ограниченныйRuntimeMaxUse;ForwardToSyslog=yesи лёгкий syslog-демон, который пишет обычный текстовый файл с ротацией — либо сразу отправка логов на другую машину;Storage=persistent, но зажатьSystemMaxUse=50Mи поднятьSyncIntervalSec, чтобы сократить число сбросов на диск.Симптом 4. После жёсткой перезагрузки журнал битый
Что происходит.
SyncIntervalSecпо умолчанию — 5 минут. Это таймаут принудительной синхронизации журнальных файлов на диск. Исключение сделано для приоритетов CRIT, ALERT и EMERG: после такого сообщения синхронизация выполняется немедленно.Отсюда две вещи сразу. Во-первых, при внезапном пропадании питания вы теряете до пяти минут логов — тех самых, которые обычно и интересны. Во-вторых, отсюда же растут жалобы на повреждённые файлы журнала: незакрытый файл после жёсткого ребута приходится восстанавливать.
📌 Заметка
Уменьшение
SyncIntervalSecспасает логи, но увеличивает число операций записи — то есть прямо противоречит лечению симптома 3. Выбирать приходится осознанно: либо ресурс носителя, либо полнота логов при аварии. Третий вариант — отправлять логи на другую машину и не решать эту дилемму локально.Ещё две настройки, о которых редко вспоминают
Compressвключён по умолчанию, порог — 512 байт: всё, что крупнее, сжимается. Для типичных однострочных сообщений это означает, что сжатие не срабатывает вообще.Seal(Forward Secure Sealing, HMAC-SHA-256 поверх журнала для защиты от подделки задним числом) в man описан как включённый по умолчанию, но реально печать появляется только после того, как вы сгенерируете ключи черезjournalctl --setup-keys. Без этого шага TAG-объекты в файл не пишутся, и «включено по умолчанию» на практике не означает «работает».Что проверить прямо сейчас
Если
--disk-usageпоказывает сотни мегабайт на машине, где вы никогда не читали логи старше недели, — это и есть ответ на вопрос, куда девался ресурс диска.Источники
💬 Вопрос к сообществу
Кто как решил вопрос с логами на одноплатниках: log2ram, вынос журнала в RAM, отправка на отдельную машину или просто «поставил SSD и не думаю»? И сталкивался ли кто-нибудь с реально битым журналом после отключения питания?
TOP HOSTERS: KAMATERA (30 дней бесплатного теста!)
Универсальный хостер №1 - 4VPS.su (2Гб\с сервера) - 10% скидка на первый заказ или 15% бонус на первое пополнение