Многопроцессорная обработка Python 3.5.x: "Ошибка OSE: [Errno 12] Невозможно выделить память" в 74% свободной системе ОЗУ

Я написал приложение на Python 3.5, которое порождает несколько процессов, используя multiprocessing библиотека. Он работает на Ubuntu 16.04.3 LTS на выделенном сервере, который поставляется с 2-мя процессорами Intel Xeon E2690 v1 (по 8 ядер в каждой) и 96 ГБ оперативной памяти.

Эта система запускает экземпляр PostgreSQL, который настроен на использование максимум 32 ГБ ОЗУ (effective_cache_size установлен в 32GB), но это только напоминание для целей моего вопроса (я пробовал несколько комбинаций effective_cache_size, work_mem, shared_buffers, так далее.).

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

Вот упрощенная часть кода, которая показывает, как я порождаю новый процесс:

from multiprocessing import Process
import time

process = Process(target=start_algorithm, args=(arg1, arg2))
process.start()

def start_algorithm():
    while True :
        time.sleep(1)
    return True

После порождения более 200 процессов (точное число не всегда совпадает) приложение выдает исключение при попытке создать новый процесс:

OSError: [Errno 12] Cannot allocate memory

ulimit -a вывод:

$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 384500
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 524288
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 384500
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

В /etc/sysctl.conf Я установил следующие параметры, которые хорошо работают для mdadm и PostgreSQL:

# Allows for 84GB shared_buffers in PostgreSQL
kernel.shmmax = 90914313216
kernel.shmall = 22020096

# Various PostgreSQL optimizations
vm.overcommit_memory = 2
vm.overcommit_ratio = 90
vm.swappiness = 4
vm.zone_reclaim_mode = 0
vm.dirty_ratio = 15
vm.dirty_background_ratio = 3

# mdadm optimizations
vm.min_free_kbytes=262144
kernel.sched_migration_cost_ns = 5000000
kernel.sched_autogroup_enabled = 0
dev.raid.speed_limit_max=1000000
dev.raid.speed_limit_min=1000000

Я пытался также установить и сбросить vm.nr_hugepages но это не избавило от проблемы.

Перед запуском моего приложения на Python использование оперативной памяти составляет около 500 MB над 96 GB, так что я вижу, что общая оперативная память довольно пуста. После порождения этих 200+ процессов ОЗУ начинает заполняться и достигает максимума примерно при 20 GB (оставшийся 74 GB все еще свободны), а затем бросает Cannot allocate memory исключение.

Вопрос в том, почему?

Я попытался измерить след общих процессов и нашел memory_profiler библиотека / инструмент для Python. Я смог получить этот график:

Память занимает 287 процессов

Если я не ошибаюсь, это о 47500 MiB памяти, так о 50 GB из "занятой" оперативной памяти. Каждый след процесса должен быть около 170 MB, Проблема в том, что я нигде не вижу такого количества занятой оперативной памяти. Вот некоторые выводы:

$ free -h
              total        used        free      shared  buff/cache   available
Mem:            94G         18G         74G        570M        1,6G         73G
Swap:           15G          0B         15G

$ vmstat -S M
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0  75879     81   1518    0    0     3    40  229  157 12  1 86  0  0

$ top
Tasks: 1457 total,   2 running, 1455 sleeping,   0 stopped,   0 zombie
%Cpu(s):  3,1 us,  0,9 sy,  0,0 ni, 95,8 id,  0,0 wa,  0,0 hi,  0,2 si,  0,0 st
KiB Mem : 98847552 total, 77698752 free, 19509612 used,  1639188 buff/cache
KiB Swap: 15825916 total, 15825916 free,        0 used. 77580104 avail Mem 

Я смог запустить 287 процессов, уменьшив объем памяти, требуемый PostgreSQL, но это всегда приводит к МНОГО свободного ОЗУ (74GB). Вот мой файл конфигурации для PostgreSQL 9.6 (postgresql.conf):

max_connections=2000
listen_addresses = '127.0.0.1,192.168.2.90'
shared_buffers = 1GB
work_mem = 42MB
port=5433
maintenance_work_mem = 256MB
checkpoint_completion_target = 0.9
effective_cache_size = 32GB
default_statistics_target = 1000
random_page_cost=1.2
seq_page_cost=1.0
max_files_per_process = 500 # default 1000
huge_pages = off

РЕДАКТИРОВАТЬ

Я нашел этот ответ на SO и нашел способ измерить общее использование памяти.

Python (порождено 288 процессов):

$ ps aux | grep python3 | awk '{sum=sum+$6}; END {print sum/1024 " MB"}'
53488.1 MB

PostgreSQL:

$ ps aux | grep postgres | awk '{sum=sum+$6}; END {print sum/1024 " MB"}'
20653.4 MB

Я до сих пор не понимаю, почему обычные инструменты (vmstat, free, top, glances) показывает другой объем используемой оперативной памяти.

0 ответов

Другие вопросы по тегам