Linux: Недостаток памяти и много памяти, которая не используется процессами и не доступна.

Вопрос или проблема

В наших производственных системах мы используем Linux (ядро 5.10.55-051055-generic) на Intel NUCs (4 ГБ ОЗУ, 2 ГБ подкачки) вместе с нашими сервисами, которые работают в контейнерах Docker. Эти сервисы в основном являются небольшими службами, которые взаимодействуют с zmq (по tcp), а также службой, работающей с CNN, используя OpenVino на интегрированном графическом процессоре Intel.

Со временем (системы, где мы проверяли память, работали около 30 дней) мы как-то “теряем” память, что означает, что много памяти (более 1 ГБ) не отображается как используемая процессом и не доступна. Итак, вопрос в том, что использует эту память или почему она недоступна?

Что мы проверили:

  • использование памяти в docker stats (так как мы запускаем только контейнеры docker в среде командной строки Ubuntu): однако эти значения не слишком полезны для расследования этой проблемы)
  • использование памяти контейнера docker, отображаемое в /sys/fs/cgroup/memory/docker/<container_id>/memory.usage_in_bytes и …memory.stats: существует существенный разрыв между памятью, используемой контейнером docker, и доступной памятью
  • Вывод журнала oom killer: суммирование использования памяти по процессу в выводе составляет всего около 2,5 ГБ, что означает, что более 1 ГБ каким-то образом утеряно
  • Данные из /proc/<process_id>/smaps (вычисление самостоятельно и с использованием procrank): суммируется всего до 2-2,5 ГБ, когда доступно только несколько сотен МБ (снова пропущено более 1 ГБ)
  • pidstat -trl: снова пропущено более 1 ГБ
  • echo m > /proc/sysrq-trigger: снова пропущено более 1 ГБ

Вывод команды free и краткий обзор procrank (созданный за 2 секунды):

                          Pss       Uss
                          1880676K  1855268K  Итого

RAM: 3672156K всего, 136388K свободно, 17756K буферов, 417332K кэша, 249268K shmem, 229920K slab

              всего        использовано        свободно      совместно  buff/cache   доступно
Mem:        3672156     3002328      138476      249268      531352      175376
Swap:       1951740     1951740           0

Вывод echo m > /proc/sysrq-trigger:

[2948794.936393] sysrq: Показать память
[2948794.936404] Mem-Info:
[2948794.936412] active_anon:196971 inactive_anon:206372 isolated_anon:0
                  active_file:109642 inactive_file:83546 isolated_file:0
                  unevictable:36 dirty:369 writeback:0
                  slab_reclaimable:27505 slab_unreclaimable:37597
                  mapped:84417 shmem:222 pagetables:6893 bounce:0
                  free:61015 free_pcp:1514 free_cma:0
[2948794.936417] Узел 0 active_anon:787884kB inactive_anon:825488kB active_file:438568kB inactive_file:334184kB unevictable:144kB isolated(anon):0kB isolated(file):0kB mapped:337668kB dirty:1476kB writeback:0kB shmem:888kB shmem_thp: 0kB shmem_pmdmapped: 0kB anon_thp: 0kB writeback_tmp:0kB kernel_stack:22176kB всего ли невосстанавливаемо? нет
[2948794.936419] Узел 0 DMA free:14340kB min:296kB low:368kB high:440kB reserved_highatomic:0KB active_anon:68kB inactive_anon:144kB active_file:68kB inactive_file:140kB unevictable:0kB writepending:0kB present:15992kB managed:15904kB mlocked:0kB pagetables:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB
[2948794.936425] lowmem_reserve[]: 0 772 3487 3487 3487
[2948794.936431] Узел 0 DMA32 free:96236kB min:14912kB low:18640kB high:22368kB reserved_highatomic:0KB active_anon:134108kB inactive_anon:163616kB active_file:40544kB inactive_file:80604kB unevictable:0kB writepending:20kB present:902612kB managed:837040kB mlocked:0kB pagetables:4820kB bounce:0kB free_pcp:1896kB local_pcp:444kB free_cma:0kB
[2948794.936439] lowmem_reserve[]: 0 0 2714 2714 2714
[2948794.936448] Узел 0 Normal free:133484kB min:52368kB low:65460kB high:78552kB reserved_highatomic:2048KB active_anon:653708kB inactive_anon:661728kB active_file:397956kB inactive_file:253440kB unevictable:144kB writepending:1456kB present:2891776kB managed:2786464kB mlocked:48kB pagetables:22752kB bounce:0kB free_pcp:4160kB local_pcp:856kB free_cma:0kB
[2948794.936455] lowmem_reserve[]: 0 0 0 0 0
[2948794.936460] Узел 0 DMA: 7*4kB (UME) 3*8kB (UE) 15*16kB (UME) 7*32kB (ME) 4*64kB (UM) 4*128kB (UME) 3*256kB (UME) 2*512kB (ME) 1*1024kB (E) 1*2048kB (E) 2*4096kB (M) = 14340kB
[2948794.936482] Узел 0 DMA32: 3295*4kB (UME) 4936*8kB (UME) 1099*16kB (UME) 154*32kB (UME) 53*64kB (UME) 16*128kB (ME) 9*256kB (ME) 6*512kB (UM) 6*1024kB (ME) 2*2048kB (M) 0*4096kB = 96236kB
[2948794.936505] Узел 0 Normal: 3621*4kB (MEH) 1357*8kB (MEH) 2857*16kB (UMEH) 693*32kB (UMEH) 259*64kB (UMEH) 41*128kB (ME) 22*256kB (ME) 11*512kB (ME) 7*1024kB (M) 0*2048kB 0*4096kB = 133484kB
[2948794.936526] Узел 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=1048576kB
[2948794.936528] Узел 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB
[2948794.936529] 184470 всего страниц кэша
[2948794.936532] 10069 страниц в кэше подкачки
[2948794.936534] Статистика кэша подкачки: добавлено 1891574, удалено 1881493, найдено 2324524/2691454
[2948794.936535] Свободный подкачка  = 832060kB
[2948794.936536] Всего подкачки = 1951740kB
[2948794.936537] 952595 страниц ОЗУ
[2948794.936539] 0 страниц HighMem/MovableOnly
[2948794.936541] 42743 страниц зарезервировано
[2948794.936542] 0 страниц hwpoisoned

вывод df -h | grep -e tmpfs -e Filesystem

Файловая система Размер Использовано Доступно Использование% Смонтировано на 
tmpfs 359M 4.2M 355M 2% /run 
tmpfs 1.8G 0 1.8G 0% /dev/shm 
tmpfs 5.0M 0 5.0M 0% /run/lock 
tmpfs 1.8G 0 1.8G 0% /sys/fs/cgroup 
tmpfs 359M 0 359M 0% /run/user/0 
tmpfs 359M 0 359M 0% /run/user/1000

Правка: вывод htop (только родительские процессы, отсортированные по использованию памяти)
введите описание изображения здесь

Я предполагаю, что это связано с тем, что ОЗУ используется самим docker для поддержания сетевого стека и т. д. Также некоторая память просто используется как кэш. Вы можете отличить это, используя команды, такие как htop, чтобы указать, где используется “недостающая” память.

Правка:
Используя htop и установку с помощью F2 вы можете сделать это, добавив столбец для указания конкретного использования памяти процессом в процентах:

настройка htop

Мы нашли нашу проблему:
Мы используем zmq по TCP для связи между различными службами, работающими на нашем устройстве.
zmq имеет особенность:

  • сокет zmq pub принимает сообщения подписки и отписки, поэтому он знает, куда отправлять данные
  • сокет zmq pub обрабатывает эти сообщения подписки и отписки только если он публикует данные

Таким образом, если сокет pub не публикует никаких данных в течение некоторого времени, и есть много других сокетов, подписывающихся и отписывающихся, буфер TCP заполняется этими сообщениями. Буфер TCP не отображается в обычной статистике памяти (ни по процессу, ни как память ядра), что объясняет “потерянную” память.

Ответ или решение

Ситуация, с которой вы столкнулись, действительно может вызывать беспокойство. Вы наблюдаете потерю памяти в системах на базе Linux, и это может быть связано с несколькими факторами. Давайте рассмотрим возможные причины "потерянной" памяти и предложим некоторые решения.

Возможные причины потери памяти

  1. TCP-буферы: Как вы уже заметили, использование ZeroMQ (zmq) с сокетами публикации (pub) может привести к заполнению TCP-буферов, особенно если сокеты активно подписываются и отписываются, но сам сокет не публикует данные. Эти буферы могут не отображаться в обычных статистиках использования памяти, так как они являются частью сетевой подложки и могут рассматриваться как "потерянная" память.

  2. Кэширование: В Linux система управления памятью активно использует доступную оперативную память для кэширования файлов и других ресурсов. Это может создать иллюзию "потерянной" памяти, но на самом деле эта память доступна для перераспределения при необходимости. Команды, такие как free и vmstat, могут давать нестабильные данные, если кэширование используется активно.

  3. Слабое использование Docker: Docker и связанные с ним библиотеки также могут использовать память для своих внутренних нужд, таких как управление контекстами и сетевыми стеком. Это может дополнительно увеличивать восприятие "потерянной" памяти.

  4. Утечки памяти: Хотя вы не упомянули этот пункт, утечки памяти в исправном коде приложений также могут быть причиной. Если ваше приложение не освобождает память должным образом, это может привести к так называемым "потерянным" ресурсам.

Решения и рекомендации

  1. Настройка ZeroMQ: Проверьте настройки ваших сокетов zmq. Чтобы предотвратить переполнение TCP-буферов, необходимо изменить параметры, такие как ZMQ_RCVHWM (ограничение на максимальное количество сообщений в очереди на получение).

  2. Мониторинг TCP-Буферов: Для явной проверки использования TCP-буферов выполните команду:

    ss -s

    Это покажет, сколько памяти используется для буферов.

  3. Настройка Кэширования: Если общее использование памяти чрезмерно включает кэш, возможно, вы захотите увеличить количество свободной памяти для процессов, изменив настройки кэширования в ядре.

  4. Использование инструментов мониторинга: Рассмотрите возможность использования инструментов мониторинга, таких как nmon, htop и atop, которые могут дать более детальную информацию о памяти и использовании ресурсов в вашей системе.

  5. Проверка на утечки памяти: Используйте инструменты для профилирования памяти, такие как valgrind или memwatch, чтобы выявить возможные утечки.

  6. Обновление системы: Убедитесь, что ваша система и библиотеки (включая Docker и ZeroMQ) обновлены до последних стабильных версий. Иногда такие проблемы могут быть решены в более поздних версиях.

Заключение

Потеря памяти в Linux-системах может быть вызвана множеством факторов. Ваша ситуация с ZeroMQ — это хорошее напоминание о том, как важно учитывать сетевые протоколы и их настройки. Применив описанные выше меры, вы сможете лучше контролировать использование памяти и устранить проблему с "потерянной" памятью. Удачи в вашей работе и дальнейших успешных разработках!

Оцените материал
Добавить комментарий

Капча загружается...