Memory leaks, сервер перестает отвечать

snark13

Member
День добрый

Сервер, текущая версия (5.2.972-6a1e986e860c9cdbf882675701f97c97660d99ed).
Виртуальная машина в Google Cloud - 8 CPU Cores, 32 GB RAM.
Сервер работает в режиме трансляции RTSP потоков с камер клиентам по WebRTC, в это же время он пишет потоки в файлы (TS сегменты)
Сервер обрабатывает порядка 15-17 камер, с каждой камеры по два потока, 360/480p и 720p. В файлы пишутся потоки 720p.
В процессе работы постепенно растет объем памяти используемый сервером и в какой-то момент сервер перестает отвечать на внешние команды и или сам падает или (если мы это обнаруживаем раньше) - перестартуется нами (с переводом камер на резервный сервер).
В этот момент в логах GC видно что вся память выделенная сервису аллокирована и сборщик мусора не может ничего высвободить -

Code:
[2021-06-29T14:43:03.723+0000] GC(4851) Min Capacity: 20480M(100%)
[2021-06-29T14:43:03.723+0000] GC(4851) Max Capacity: 20480M(100%)
[2021-06-29T14:43:03.723+0000] GC(4851) Soft Max Capacity: 20480M(100%)
[2021-06-29T14:43:03.723+0000] GC(4851)                Mark Start          Mark End        Relocate Start      Relocate End           High               Low
[2021-06-29T14:43:03.723+0000] GC(4851)  Capacity:    20480M (100%)      20480M (100%)      20480M (100%)      20480M (100%)      20480M (100%)      20480M (100%)
[2021-06-29T14:43:03.723+0000] GC(4851)   Reserve:       42M (0%)           42M (0%)           42M (0%)           42M (0%)           42M (0%)           34M (0%)
[2021-06-29T14:43:03.723+0000] GC(4851)      Free:        0M (0%)            0M (0%)            0M (0%)            0M (0%)            2M (0%)            0M (0%)
[2021-06-29T14:43:03.723+0000] GC(4851)      Used:    20438M (100%)      20438M (100%)      20438M (100%)      20438M (100%)      20446M (100%)      20436M (100%)
[2021-06-29T14:43:03.723+0000] GC(4851)      Live:         -             19514M (95%)       19514M (95%)       19514M (95%)            -                  -
[2021-06-29T14:43:03.723+0000] GC(4851) Allocated:         -                 4M (0%)           10M (0%)           42M (0%)             -                  -
[2021-06-29T14:43:03.723+0000] GC(4851)   Garbage:         -               919M (4%)          917M (4%)          907M (4%)             -                  -
[2021-06-29T14:43:03.723+0000] GC(4851) Reclaimed:         -                  -                 2M (0%)           12M (0%)             -                  -
[2021-06-29T14:43:03.723+0000] GC(4851) Garbage Collection (Allocation Stall) 20438M(100%)->20438M(100%)
Под hugepages в системе отведено 24 GB, для WCS выставленно 20 GB -

-XX:+UnlockExperimentalVMOptions -XX:+UseZGC -Xms20g -Xmx20g
-XX:+UseLargePages -XX:ZPath=/hugepages

Java -
java 14.0.2 2020-07-14
Java(TM) SE Runtime Environment (build 14.0.2+12-46)
Java HotSpot(TM) 64-Bit Server VM (build 14.0.2+12-46, mixed mode, sharing)

от Oracle.
система - Ubuntu 20.4

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

Max

Administrator
Staff member
Здравствуйте.
Пришлите пожалуйста SSH доступ к серверу. К этому или другому.
Мы скопируем туда дебаговую сборку 5.2.972-debug.
После этого можно будет запуститься и снять Heap Dump через некоторое время работы сервера.
Мы добавим инструкции к дебаговой сборке.
Проблему с утечкой памяти можно будет обнаружить только в таком дампе.
Другой способ - нам повторить настройки и попытаться воспроизвести у себя.
Пришлите полные настройки сервера (всю папку conf) и дополнительные инструкции по воспроизведению, которые считаете важными.
 

Max

Administrator
Staff member
Уточните также, выставляли ли Вы параметр file_recorder_thread_pool_max_size? Этот параметр отвечает за то, сколько процессорных потоков будут заниматься записью каждого файла. Данные для записи хранятся в Java heap, и если производительности диска не хватает для того, чтобы своевременно сбросить на диск эти данные, они начинают копиться в памяти, что и может приводить к утечкам. Для Вашей конфигурации сервера рекомендуется настройка
Code:
file_recorder_thread_pool_max_size=8
(по одному процессорному потоку на каждое ядро CPU) или
Code:
file_recorder_thread_pool_max_size=16
(по два процессорных потока)
 

snark13

Member
Доступ по SSH предоставили.
Как будет дебаг версия работать - поставим его в работу со стримами (после рестарта он скорее всего будет помечен как проблемный и переведен в резерв, надо будет вернуть в активный пул)
по поводу file_recorder_thread_pool_max_size - сейчас стоит значение 32 (что бы хватало на все рекордеры), но поведение одинаковое и с таким значением и со значением по умолчанию.
 

Max

Administrator
Staff member
Скопировали дебаговую сборку на сервер, необходимо его рестартовать.
После этого необходимо мониторить потребление памяти на сервере, либо просто снять дамп через сутки после старта. Дамп снимается командой:
Code:
cd /usr/local/FlashphonerWebCallServer/tools
sudo ./report.sh --sysinfo --conf --stats --dump --tar
Кроме дампа, эта же команда собирает логи за последние 3 часа и статистику работы. Собранный архив нужно отправить нам через эту форму. Если размер архива превышает 30 Мб, необходимо выгрузить его в облачное хранилище и в поле Comment формы указать ссылку на архив.
 

snark13

Member
Сервер перезапустил, стримы поднял, поставил каждый час собирать логи/статистику (что бы не пропустить момента с максимальным потреблением памяти)
Что не очень нравится - в холостом режиме (просто запись потоков) потребление CPU порядка 50-60% на все ядра (на версии 714 было порядка 30-35% но все те же проблемы с памятью так же были) и это без транскодирования потоков.
 

Max

Administrator
Staff member
Что не очень нравится - в холостом режиме (просто запись потоков)
Запись потоков - это не холостой режим. Судя по статистике, на сервере есть транскодинг аудио, он требует ресурсов CPU, хотя и меньше, чем транскодинг видео. Кроме того, Вы выставили по четыре процессорных потока на каждое ядро при записи файла, этого может быть много для системы. Рекомендуем уменьшить до 16 (2 потока на ядро CPU):
Code:
file_recorder_thread_pool_max_size=16
Также у Вас даже при отсутствии подписчиков работает нарезка HLS
Code:
hls_auto_start=true
Поэтому сервер в принципе не работает в холостом режиме.
 

snark13

Member
То что не совсем холостой режим (и даже совсем не холостой) - я согласен.
Транскодинг Аудио нужен насколько я понимаю для WebRTC клиентов... от Камер мы попробуем получить потоки в AAC (что бы для HLS можно было не перекодировать)
Непонятно правда почему идет транскодинг аудио в таких количествах (на 32-34 потока имеем по 40-50 перекодировщиков аудио).

1625052725597.png

Еще вопрос - можно ли выключить ресемплинг аудио ? а то перевод аудио от камер с семплин рейт 8 кГц в 44.1/48 кГц - тоже не самая легкая задача
 

snark13

Member
Еще вопрос - возможно ли такое что в то время когда создается дамп сервер перестает отвечать на REST запросы ?
Похоже что такая ситуация произошла - пока создавался дамп сервис мониторинга обнаружил что WCS не ответил на REST запрос и решил перестартовать WCS сервис (пока отключу проверку серверов на стороне собственного мониторинга)
 

Max

Administrator
Staff member
Транскодинг Аудио нужен насколько я понимаю для WebRTC клиентов... от Камер мы попробуем получить потоки в AAC (что бы для HLS можно было не перекодировать)
Судя по sampling rate 8000 Hz, камеры отдают видео H.264 и аудио PCMA/PCMU 8000 Hz.
Это можно уточнить на стороне камер или на метриках стрима.

Как вы правильно заметили, HLS требует AAC (mpeg4-generic), поэтому все 15-17 камер транскодируются по аудио PCMA 8000 Hz >> AAC 48000 Hz.

Если потоки смотрят зрители по WebRTC, то происходит дополнительно транскодинг PCMA >> Opus 48000 Hz.

Если потоки записываются, то происходит дополнительно транскодинг PCMA >> AAC 44100 Hz.

Таким образом получаем следующий калькулятор:

15-17 камер
С каждой по 2 потока, итого 30-34 потоков
Все камеры нарезаются в HLS, итого 30-34 сессий аудио энкодинга в AAC
15-17 потоков 720p записываются в файл, при записи также происходит энкодинг в AAC

Итого:
30-34
+
15-17
=
45 - 51

Получаем 51 энкодер для 17 камер с двумя потоками. Т.е. почти сходится с вашей цифрой 54, которая в статистике. Где-то потеряли еще 3 кодека. Но это несущественно.

И в точности совпадает с количеством ресемплеров: 51.

По вопросу ресемплеров. Ресемплеры создаются корректно. Т. к. произвести транскодирование звука из 8 khz в 48 khz невозможно без ресемплинга. Избавиться от ресемпленга можно двумя способами:

1. Выставить на стороне камер 48000 Hz для звука.

2. Попытаться на стороне WCS настроить 8000 Hz для HLS


Однако по некоторым нашим тестам, были проблемы при воспроизведении HLS стримов на Apple устройствах с семплингом 8 kHz. Поэтому не факт, что результат будет хорошим.

3. Настроить сэмплинг рейт для записи

record_audio_codec_sample_rate=8000 (по умолчанию 44100)

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

Т.е. настройками hls.sdp и record_audio_codec_sample_rate либо настройкой самих камер, можно избавиться от ресемплингов и привести все к 8000 Hz или 48000 Hz, но надо смотреть на качество HLS и записи. От транскодинга можно избавиться только если отдавать с камер AAC.

Еще вопрос - возможно ли такое что в то время когда создается дамп сервер перестает отвечать на REST запросы ?
Создание дампа памяти - тяжелая процедура, которая требует внутренней остановки стейта сервера. Поэтому все внутренние треды могут быть остановлены на момент снятия дампа. Размер дампа обычно равен текущему размеру Heap, например 20 GB в случае утечки. Поэтому да, сервер может "виснуть" до полного окончания снятия дампа. Снятие дампов проходит быстрее если есть дополнительные ресурсы CPU и свободный Heap.
 
Last edited:

snark13

Member
При сборе дампа сервер разрывает соединения к камерам и похоже память высвобождается (разрывать соединения к камерам решением существующей проблемы не является). Убрал сбор дампа ежечасно, поставил на сбор дампа через 16 часов - будем надеяться что за ночь сервер не крашнется и не перестартует.
 

Max

Administrator
Staff member
Скорее всего, в дампе будут очереди данных на запись. Поэтому рекомендуем следующее:
1. Снизить нагрузку на CPU. Этого можно добиться, если избавиться от транскодинга звука, в этом случае Ваши камеры должны отдавать H264 + AAC 48 кГц. Если это невозможно, то взять инстанс с более мощным процессором (например, 24 CPU cores). Кроме того, количество процессорных потоков для записи на диск не должно превышать количество CPU более чем в два раза.
2. Повысить производительность диска, подключив высокоскоростной storage для записи. Например, в AWS EC2 по умолчанию предлагаются диски с низким IOPS, более быстрый диск нужно подключать отдельно. Вероятно, в Google Cloud так же.
3. Снизить нагрузку на дик от записи сегментов HLS. Для этого нужно взять инстанс с большим объемом RAM, создать RAM-диск и подключить его в качестве каталога для HLS сегментов, например
Code:
hls_dir=/ramdrive
Мы создали тикет WCS-3226 по добавлению расширенной статистики записи на страницу статистики, что должно помочь выявлять узкое место в таких случаях.
 

snark13

Member
Перевел запись в архивы без ресемплирования
Перевел всю работу с записью (в архивы и для HLS) на ramdrive.
Пока уменьшил память для сервера с 20 до 16 гигабайт
Перевести весь сервер на более производительный диск пока не представляется возможным (по умолчанию диск они выдают SSD но есть опция более производительного)
Теперь вроде в обычном режиме CPU загружен на 25-35% - уже значительно лучше (но большая часть выигрыша получена отключением ресемплирования)
Попытка получить дамп когда сервер перестал отвечать не увенчалась успехом (место на диске закончилось). Поставил опять на ожидание - на выходных думаю получим эту ситуацию и дампы.
Если проблема именно с очередью данных на запись может можно ограничить размер очереди и скипать старые сегменты если новые не помещаются ? конечно с записью в статистику (да - вроде задержки по HLS данным для клиентов нету - даже когда мы приближаемся к лимитам по памяти HLS потоки воспроизводятся примерно так же как и когда сервер только стартовал)
 

snark13

Member
К сожалению даже с полным переводом всей записи сегментов (и для HLS клиентов и для архивов) на рамдиск не удалось избежать проблемы с нехваткой памяти
В 07:03 (UTC) сегодня в логи сборщика мусора посыпались записи вида -

Code:
gc-core-2021-07-02_21-43.log.4:[2021-07-03T07:03:48.613+0000] Out Of Memory (pool-43-thread-1)
gc-core-2021-07-02_21-43.log.4:[2021-07-03T07:03:48.613+0000] Out Of Memory (pool-91-thread-1)
gc-core-2021-07-02_21-43.log.4:[2021-07-03T07:03:48.613+0000] Out Of Memory (pool-81-thread-1)
gc-core-2021-07-02_21-43.log.4:[2021-07-03T07:03:48.700+0000] Out Of Memory (pool-99-thread-1)
gc-core-2021-07-02_21-43.log.4:[2021-07-03T07:03:48.786+0000] Out Of Memory (pool-81-thread-1)
gc-core-2021-07-02_21-43.log.4:[2021-07-03T07:03:48.786+0000] Out Of Memory (pool-43-thread-1)
gc-core-2021-07-02_21-43.log.4:[2021-07-03T07:03:48.786+0000] Out Of Memory (pool-91-thread-1)
gc-core-2021-07-02_21-43.log.4:[2021-07-03T07:03:48.885+0000] Out Of Memory (pool-99-thread-1)
gc-core-2021-07-02_21-43.log.4:[2021-07-03T07:03:48.993+0000] Out Of Memory (pool-91-thread-1)
и так продолжалось порядка двух минут.
нагрузка на CPU в это время увеличилась с 30% до 65%.
сделать дамп сервера в этот момент не удалось.
так что похоже ускорением диска эту проблему не решить.

также в какой-то момент на странице статистики появились записи о ресемплере из 8000 в 8000 -
Code:
94001977365616,RESAMPLER:8000/8000,0;
94001955420704,mpeg4-generic,-808643584;
139894415631024,RESAMPLER:8000/8000,0;
139894540258592,mpeg4-generic,-808544938;
139894433269568,mpeg4-generic,-633962497;
139894433683520,mpeg4-generic,-808638464;
94001986249984,mpeg4-generic,-321024;
139894551319984,RESAMPLER:8000/8000,0;
139894560095792,RESAMPLER:8000/48000,4851824640;
139895061295056,RESAMPLER:8000/8000,0;
94001941814944,mpeg4-generic,-808612522;
139894421915872,mpeg4-generic,-808639829;
 

Max

Administrator
Staff member
Пока уменьшил память для сервера с 20 до 16 гигабайт
Мы не рекомендовали уменьшать объем Java heap.
Если проблема именно с очередью данных на запись может можно ограничить размер очереди и скипать старые сегменты если новые не помещаются ?
В этом случае запись невозможно будет воспроизвести.
и так продолжалось порядка двух минут.
нагрузка на CPU в это время увеличилась с 30% до 65%.
Скорее всего, OutOfMemory Вы получили потому, что уменьшили Java heap. Получается, что при ускорении записи узким местом стал процессор. Рекомендуем взять инстанс с более мощным CPU и выставить file_recorder_thread_pool_max_size в значение, не превышающего CPU cores * 2б как уже рекомендовали здесь и здесь.
Мы создали тикет WCS-3227 по оптимизации записи, но его реализация может занять длительное время.
 

snark13

Member
при текущей загрузке CPU в обычном состоянии порядка 25% смысла в инстансе с более мощным CPU наверное нету. если не будет хватать - попробуем увеличить, но не уверен что сейчас узким местом стал процессор (процессор становится узким местом когда перестает хватать памяти - но в этот момент нехватает и большего CPU - каким бы он не был мощным - выжирается почти все.
file_recorder_thread_pool_max_size уже выставлен в 16 (8 cores, 16-17 сессий для записи).

размер heap-а уменьшал на 4гига поскольку отвел эти четыре гига под ram drive (но посмотрел - типичная картина на рамдрайве - занято порядка 100-200 мбайт - можно спокойно уменьшить размер рамдрайва до 2 гиг и вернуть обратно для WCS 20 гигабайт
сейчас снял дамп сервиса когда выделенная память израсходована почти полностью (урл на архив пошлю в репорте, во время снятия дампа запрос stat к серверу подвис, пришлось его снять вручную, потому архив без этого файла)

p.s. откуда-то опять берутся ресемплеры из 8000 в 44100 - нет ни одной webrtc сессии... для HLS как я понимаю идет ресемплинг в 48000, для архива ресемплинг выставлен в конфиге в 8000 (выключен)
p.p. на рабочих серверах я пока приостанавливаю тестирование, постараюсь сегодня создать отдельный сервер для проверок проблем с памятью (где я смогу менять количество подключенных камер, типы записываемого видео и прочие параметры)
 

Max

Administrator
Staff member
при текущей загрузке CPU в обычном состоянии порядка 25% смысла в инстансе с более мощным CPU наверное нету. если не будет хватать - попробуем увеличить, но не уверен что сейчас узким местом стал процессор (процессор становится узким местом когда перестает хватать памяти - но в этот момент нехватает и большего CPU - каким бы он не был мощным - выжирается почти все.
Последовательность такая:
1) сначала нагружается процессор
2) не успевает обработать сегменты для записи, треды, которые занимаются записью, держат ссылки на фреймы в памяти
3) при активных ссылках объекты не вычищаются сборщиком мусора
4) растет потребление памяти
Поэтому сейчас узким местом является именно процессор. В тикете WCS-3227 мы оптимизируем запись таким образом, чтобы по возможности не держать ссылку на каждый фрейм, но реализация может занять длительное время.
Рекомендуем взять инстанс с большим количеством ядер (16 cores и более)
p.s. откуда-то опять берутся ресемплеры из 8000 в 44100 - нет ни одной webrtc сессии...
Это происходит при выставленной настройке
Code:
record_audio_codec_sample_rate=8000
или нет? Если да, проверим у себя. Если нет, то при записи это нормальное поведение, по умолчанию при записи включается ресемплинг в 44100
Что касается WebRTC сессий, для них будет транскодинг в Opus с ресемплингом в 48000 Гц.
 

snark13

Member
Да - это при выставленном параметре
record_audio_codec_sample_rate=8000
видел появление ресемплеров из 8000 в 44100

Провожу эксперименты (на другом инстансе - 4 cores, 16Gb) - обрабатываю 6 камер - всего 12 потоков (6 - 720p, 6 - 360p).
Выключил hls_auto_start=true (закоментировал)
Что с включенным архивированием видео (запись 6-ти потоков 720p в архивы), что с выключенным архивированием видео - средняя загрузка CPU - 5-6% - запись видео не нагружает сервер. Но на каждую запись все таки создается ресемплер из 8000 в 8000
Включаю архивирование ВСЕХ 12 видеопотоков (и 720p и 360p) - загрузка не меняется.
Выключаю архивирование видео
Включил hls_auto_start=true (кстати - без перезапуска сервера изменение этого параметра не работает - по доке же - need restart - false) - сразу после этого - CPU подскакивает до 25-30%
Получается - генерация TS сегментов для HLS (с ресемплингом) приводит к значительно большей нагрузке чем генерация таких же TS сегментов только для архива (без ресемплинга)
Примерно такая же нагрузка (25-30%) возникала при комментировании record_audio_codec_sample_rate.
То есть - основная нагрузка - resample/reencoding
Далее - пробую уменьшать нагрузку ресемплерами
Прописываю в hls.sdp семплрейт в 8000 - получаю загрузку CPU при одновременной записи и hls в пределах 7-10%, но да - при таком звуке в HLS возникают проблемы с плеерами (как и описано в доке)
Поднимаю семплрейт до 32000/1 в HLS и выставляю
record_audio_codec_sample_rate=32000
audio_mixer_output_channels=1
Разрешаю hls_auto_start и включаю запись потоков от камеры в 720p.
Получаю постоянную нагрузку на CPU в районе 15% - что в принципе должно быть достаточно немного. И это значительно меньше чем только один hls_auto_start в 44100/2.
Но в архивы звук все равно пишется стерео (и потому похоже ресемплеры между HLS броадкастером и архивами не могут реюзаться - получаю на 12 потоков 18 ресемплеров - 12 на HLS и 6 на архивацию видео в 720p... но может они не могут реюзаться вообще)
Вопрос - можно ли заставить в архивы звук так же писаться в моно ? ресемплер/реенкодер в моно занимает значительно меньше CPU чем в стерео (проверено практикой на вашем сервере)

Оставляю сервер на ночь - к утру получаю порядка 3+ гигабайт неосвобождаемой памяти -
Garbage Collection (Proactive) 4310M(42%)->3280M(32%)
После потери коннекта к камерам память высвободилась практически вся
Garbage Collection (Proactive) 3502M(34%)->74M(1%)
после реконнекта к камерам - потребление памяти вернулось к 300М и постепенно выросло до 600М
Garbage Collection (Proactive) 1616M(16%)->594M(6%)
Послежу за сервером дальше.
 

Max

Administrator
Staff member
Да - это при выставленном параметре
record_audio_codec_sample_rate=8000
видел появление ресемплеров из 8000 в 44100
Проверим в своем окружении, сообщим о результате.
Получается - генерация TS сегментов для HLS (с ресемплингом) приводит к значительно большей нагрузке чем генерация таких же TS сегментов только для архива (без ресемплинга)
Запись HLS сегментов, действительно, может нагружать больше обычной записи, поскольку в данном случае ротация по сегментам работает чаще.
Но в архивы звук все равно пишется стерео (и потому похоже ресемплеры между HLS броадкастером и архивами не могут реюзаться - получаю на 12 потоков 18 ресемплеров - 12 на HLS и 6 на архивацию видео в 720p... но может они не могут реюзаться вообще)
Вопрос - можно ли заставить в архивы звук так же писаться в моно ? ресемплер/реенкодер в моно занимает значительно меньше CPU чем в стерео (проверено практикой на вашем сервере)
Да, можно, и это снизит нагрузку:
Code:
record_audio_codec_channels=1
Запись стерео звука нагружает больше, чем запись моно, это отмечено в документации (п. 5).
 

Max

Administrator
Staff member
Да - это при выставленном параметре
record_audio_codec_sample_rate=8000
видел появление ресемплеров из 8000 в 44100
Провели тесты с Вашими настройками. Если камеры отдают AAC 8000 Hz, в hls.sdp оставлен только mpeg4-generic с 8000 Hz, и для записи выставлено
Code:
record_audio_codec_sample_rate=8000
то при этих условиях в наших тестах проблема не воспроизводится, дополнительные ресемплеры 8000->44100 не появляются.
Если проблема продолжает воспроизводиться, соберите отчет в момент, когда она воспроизводится (без heap dump, только логи, настройки и статистика) и отправьте через эту форму.
 
Top