Устранение вымывания памяти Linux Page Cache и аварий OOM при 24/7 записи видео
Одна из самых коварных и трудноотлаживаемых проблем при круглосуточной записи десятков видеопотоков на Linux — вымывание памяти системным кэшем (Page Cache Thrashing) и падения по Out-Of-Memory (OOM Killer).
🔍 Первопричина: почему в Linux "утекает" память при записи видео
Когда программа непрерывно пишет видеопотоки (например, 50 камер с суммарным потоком 500 МБ/с) через стандартные функции ввода-вывода (os.File.Write в Go или write() в C), ядро Linux не сбрасывает данные на диск моментально.
Вместо этого:
- Linux кэширует каждый записанный байт: Ядро складывает видеоблоки в оперативную память (Page Cache) и помечает их как "грязные страницы" (dirty pages).
- Отложенная запись: Фоновые потоки ядра (
kswapd/pdflush) с задержкой сбрасывают эти страницы на физический диск. - Кризис вытеснения страниц: При непрерывном потоке с 50–100 камер ядро успевает забить кэшем 90%+ всей физической памяти сервера.
- Удар OOM Killer: Когда соседнему процессу (Go GC, WebRTC буферу, СУБД) срочно требуется оперативная память, Linux замораживает дисковый ввод-вывод или аварийно убивает процесс через OOM Killer.
🛑 Почему классические методы не работают
O_DIRECT: Обходит кэш, но требует строгого выравнивания по границе 4 КБ секторов в памяти. Аллокатор Go и сборщик мусора не гарантируют выравнивание слайсов без опасной магииunsafe.Pointerи ручного паддинга неровных видеокадров.mmap: Требует постоянного изменения размера (ftruncate) и переотображения памяти по мере роста файла, создавая огромные накладные расходы на Page Faults.- Глобальный
/proc/sys/vm/dirty_ratio: Изменение глобальных настроек ОС ухудшает производительность баз данных и системных служб всего сервера.
✅ Решение RUSEON Core: POSIX_FADV_DONTNEED
В RUSEON Core эта проблема решена на уровне системных вызовов ядра без unsafe и без изменения глобальных настроек ОС:
- Запись дискретными fMP4 сегментами: Видео пишется короткими чанками через стандартный
os.File. - Принудительное освобождение кэша: Сразу после завершения и синхронизации сегмента на диск, RUSEON вызывает системный вызов
POSIX_FADV_DONTNEED:
go
// Сбросить чанк на физический накопитель
chunkFile.Sync()
// Указать ядру Linux немедленно выгрузить видеоблоки из ОЗУ
syscall.Fadvise(int(chunkFile.Fd()), 0, int64(chunkSize), syscall.FADV_DONTNEED)📈 Результат:
- Память строго стабильна: RAM удерживается на уровне ~180MB независимо от того, идет запись 1 час или 365 дней подряд.
- Никаких фризов диска: Полностью устраняются задержки I/O wait.
- Не требуются права root: Работает в обычных Docker-контейнерах и Kubernetes-подах.