Управление ресурсами ядра
Эта страница переведена при помощи нейросети GigaChat.
PostgreSQL иногда может исчерпать различные ограничения ресурсов операционной системы, особенно когда несколько экземпляров сервера работают на одной и той же системе или в очень больших установках. В этом разделе объясняется использование ядерных ресурсов PostgreSQL и шаги, которые можно предпринять для решения проблем, связанных с потреблением ядерных ресурсов.
Общая память и семафоры
PostgreSQL требует от операционной системы предоставления функций межпроцессного взаимодействия (IPC), включая общую память и семафоры. Производные от Unix-систем обычно предоставляют «System V» IPC, «POSIX» IPC или оба варианта. Windows имеет свою собственную реализацию этих функций и здесь не обсуждается.
По умолчанию PostgreSQL выделяет небольшое количество общей памяти System V и гораздо большее количество анонимной общей памяти. В качестве альтернативы можно использовать один большой регион общей памяти System V (см. shared_memory_type). Кроме того, при запуске сервера создается значительное количество семафоров, которые могут быть либо типа System V, либо POSIX. В настоящее время используются POSIX-семафоры на системах Linux и FreeBSD, тогда как другие платформы используют семафоры System V.
Функции System V IPC обычно ограничены системными лимитами распределения. Когда PostgreSQL превышает одно из этих ограничений, сервер не запускается и оставляет информативное сообщение об ошибке, описывающее проблему и возможные действия. (См. также Раздел Ошибки запуска сервера.) Соответствующие параметры ядра называются последовательно на разных системах; таблица ниже дает обзор. Методы их настройки, однако, различаются. Предложения для некоторых платформ приведены ниже.
Системные параметры IPC версии System V
Имя | Описание | Значения, необходимые для запуска одного экземпляра PostgreSQL |
---|---|---|
SHMMAX | Максимальный размер сегмента общей памяти (байт) | не менее 1 КБ, но значение по умолчанию обычно намного выше |
SHMMIN | Минимальный размер сегмента общей памяти (байт) | 1 |
SHMALL | Общее количество доступной общей памяти (в байтах или страницах) | то же самое, что и SHMMAX если байты или ceil(SHMMAX/PAGE_SIZE) если страницы, плюс место для других приложений |
SHMSEG | Максимальное количество сегментов общей памяти на процесс | требуется только 1 сегмент, но значение по умолчанию намного выше |
SHMMNI | Максимальное количество сегментов общей памяти в системе | как SHMSEG плюс место для других приложений |
SEMMNI | Максимальное количество идентификаторов семафора (т.е. наборы) | не менее ceil((max_connections + autovacuum_max_workers + max_wal_senders + max_worker_processes + 7) / 19) плюс место для других приложений |
SEMMNS | Максимальное количество семафоров во всей системе | ceil((max_connections + autovacuum_max_workers + max_wal_senders + max_worker_processes + 7) / 19) * 20 плюс место для других приложений |
SEMMSL | Максимальное количество семафоров в наборе | как минимум 20 |
SEMMAP | Количество записей в карте семафоров | см. текст |
SEMVMX | Максимальное значение семафора | не менее 1000 (По умолчанию часто используется 32767; не изменяйте без необходимости) |
PostgreSQL требует несколько байт общей памяти System V (обычно 48 байт на платформах с 64-разрядной архитектурой) для каждой копии сервера. В большинстве современных операционных систем это количество может быть легко выделено. Однако при запуске множества копий сервера или при явной настройке сервера на использование больших объемов общей памяти System V (см. shared_memory_type и dynamic_shared_memory_type), может потребоваться увеличить SHMALL
, который является общим объемом общей памяти System V в системе. Обратите внимание, что SHMALL
измеряется в страницах, а не в байтах во многих системах.
Меньше вероятность возникновения проблем с минимальным размером сегментов общей памяти (SHMMIN
), который должен быть не более приблизительно 32 байт для PostgreSQL (обычно это всего лишь 1). Максимальное количество сегментов в системе (SHMMNI
) или на процесс (SHMSEG
) вряд ли вызовет проблему, если только система не установила их равными нулю.
При использовании семафоров System V PostgreSQL использует один семафор для каждого разрешенного соединения (max_connections), разрешенного процесса автоматического обслуживания (autovacuum_max_workers) и разрешенного фонового процесса (max_worker_processes), группами по 19. Каждая такая группа также будет содержать двадцатый семафор, содержащий «магическое число», чтобы обнаружить столкновение с наборами семафоров, используемых другими приложениями. Максимальное количество семафоров в системе устанавливается параметром SEMMNS
, который, следовательно, должен быть не менее высоким, чем max_connections
плюс autovacuum_max_workers
плюс max_wal_senders
, плюс max_worker_processes
, плюс еще один для каждых 19 разрешенных соединений плюс рабочих процессов (см. формулу в таблице «Системные параметры IPC версии System V»). Параметр SEMMNI
определяет ограничение на количество наборов семафоров, которые могут существовать в системе одновременно. Следовательно, этот параметр должен быть не менее ceil((max_connections + autovacuum_max_workers + max_wal_senders + max_worker_processes + 7) / 19)
. Временным обходным решением при сбоях, которые обычно запутанно формулируются как «На устройстве нет места», является уменьшение количества разрешенных подключений от функции semget
.
В некоторых случаях может потребоваться увеличить SEMMAP
до порядка SEMMNS
. Если у системы есть этот параметр (многие его не имеют), он определяет размер карты ресурсов семафора, в которой каждая непрерывная область доступных семафоров требует записи. Когда освобождается набор семафоров, он либо добавляется к существующей записи, которая примыкает к освобожденному блоку, либо регистрируется под новой записью карты. Если карта заполнена, освобожденные семафоры теряются (до перезагрузки). Фрагментация пространства семафоров со временем может привести к тому, что доступных семафоров станет меньше, чем должно быть.
Различные другие параметры, связанные с «отменой семафора», такие как SEMMNU
и SEMUME
, не влияют на PostgreSQL.
При использовании семафоров POSIX количество необходимых семафоров такое же, как для System V, то есть один семафор на разрешенное соединение (max_connections), разрешенный процесс рабочего процесса autovacuum (autovacuum_max_workers) и разрешенный фоновый процесс (max_worker_processes). На платформах, где предпочтителен этот вариант, нет конкретной ограничения ядра на количество семафоров POSIX.
FreeBSD
: Настройки общей памяти по умолчанию, как правило, являются достаточными, если параметр shared_memory_type
не установлен на sysv
. Семафоры System V на данной платформе не применяются.
Параметры IPC по умолчанию могут быть изменены с использованием интерфейсов sysctl
или loader
. Следующие параметры могут быть установлены с использованием sysctl
:
# sysctl kern.ipc.shmall=32768
# sysctl kern.ipc.shmmax=134217728
Для сохранения этих настроек после перезагрузки необходимо внести изменения в файл /etc/sysctl.conf
.
Если параметр shared_memory_type
установлен на sysv
, может потребоваться настройка ядра для блокировки общей памяти System V в оперативной памяти и предотвращения ее выгрузки на подкачку. Это можно сделать с помощью параметра sysctl
kern.ipc.shm_use_phys
.
Если запуск осуществляется в тюрьме FreeBSD, следует установить параметр sysvshm
на new
, чтобы у него было свое отдельное пространство имен общей памяти System V. (До версии FreeBSD 11.0 необходимо было включить общий доступ к пространству имен IPC хоста из тюрем и принять меры для предотвращения столкновений.)
NetBSD
: Настройки общей памяти по умолчанию, как правило, являются достаточными, если параметр shared_memory_type
не установлен на sysv
. В большинстве случаев потребуется увеличение значений kern.ipc.semmni
и kern.ipc.semmns
, поскольку их стандартные настройки в NetBSD являются слишком низкими.
Параметры IPC могут быть настроены с использованием sysctl
, например:
# sysctl -w kern.ipc.semmni=100
Для сохранения этих параметров после перезагрузки необходимо внести изменения в файл /etc/sysctl.conf
.
Если параметр shared_memory_type
установлен на sysv
, может потребоваться настройка ядра для блокировки общей памяти System V в оперативной памяти и предотвращения ее выгрузки на подкачку. Это можно сделать с помощью параметра sysctl
kern.ipc.shm_use_phys
.
OpenBSD
: Параметры разделяемой памяти по умолчанию, как правило, являются достаточными, если параметр shared_memory_type
не установлен на sysv
. В большинстве случаев потребуется увеличение значений kern.seminfo.semmni
и kern.seminfo.semmns
, поскольку их стандартные настройки в OpenBSD являются слишком низкими.
Параметры IPC могут быть настроены с использованием sysctl
, например:
# sysctl kern.seminfo.semmni=100
Для сохранения этих параметров после перезагрузки необходимо внести изменения в файл /etc/sysctl.conf
.
Linux
: Настройки общей памяти по умолчанию, как правило, являются достаточными, если параметр shared_memory_type
не установлен на sysv
, и даже в этом случае только на старых версиях ядра, которые поставлялись с низкими настройками по умолчанию. Системные семафоры System V на данной платформе не используются.
Параметры размера общей памяти могут быть изменены через интерфейс sysctl
. Например, чтобы разрешить 16 ГБ:
$ sysctl -w kernel.shmmax=17179869184
$ sysctl -w kernel.shmall=4194304
Для сохранения этих настроек после перезагрузки необходимо внести изменения в файл /etc/sysctl.conf
.
macOS
: Настройки общей памяти и семафора по умолчанию, как правило, являются достаточными, если параметр shared_memory_type
не установлен на sysv
.
Рекомендуемый метод настройки общей памяти в macOS заключается в создании файла с именем /etc/sysctl.conf
, содержащего назначения переменных, такие как:
kern.sysv.shmmax=4194304
kern.sysv.shmmin=1
kern.sysv.shmmni=32
kern.sysv.shmseg=8
kern.sysv.shmall=1024
Обратите внимание, что в некоторых версиях macOS все пять параметров общей памяти должны быть установлены в /etc/sysctl.conf
, иначе значения будут игнорироваться.
SHMMAX
может быть установлен только кратным 4096.
SHMALL
измеряется в страницах по 4 кБ на данной платформе.
Все параметры, кроме SHMMNI
, могут быть изменены на лету с помощью sysctl
. Однако предпочтительнее настроить требуемые значения через /etc/sysctl.conf
, чтобы они сохранялись при перезагрузках.
Solaris
Illumos
: Настройки общей памяти и семафора по умолчанию обычно являются достаточными для большинства приложений PostgreSQL. В Solaris по умолчанию используется значение, равное одной четверти системной оперативной памяти. Для дополнительной настройки этого значения используется настройка проекта, связанная с пользователем postgres
. Например, следующая команда, выполненная от имени root
, добавляет проект user.postgres
и устанавливает максимальную общую память для пользователя postgres
равной 8 ГБ:
projadd -c "PostgreSQL DB User" -K "project.max-shm-memory=(privileged,8GB,deny)" -U postgres -G postgres user.postgres
Эта команда вступает в силу при следующем входе пользователя в систему или при перезапуске PostgreSQL (не требуется перезагрузка). Предполагается, что PostgreSQL запускается пользователем postgres
в группе postgres
. Перезагрузка сервера не требуется.
Другие рекомендуемые изменения настроек ядра для серверов баз данных с большим количеством подключений включают:
project.max-shm-ids=(priv,32768,deny)
project.max-sem-ids=(priv,4096,deny)
project.max-msg-ids=(priv,4096,deny)
Если PostgreSQL запускается внутри зоны, может потребоваться также увеличить лимиты использования ресурсов зоны.
Удаление IPC
При использовании systemd необходимо соблюдать осторожность, чтобы ресурсы IPC (включая общую память) не были преждевременно удалены операционной системой. Это особенно важно при установке PostgreSQL из исходного кода. Пользователи пакетов PostgreSQL для дистрибутивов менее подвержены этому влиянию, поскольку пользователь postgres
обычно создается как системный пользователь.
Параметр RemoveIPC
в logind.conf
управляет тем, удаляются ли объекты IPC при полном выходе пользователя из системы. Системные пользователи освобождены от этого. Этот параметр по умолчанию включен в стандартный systemd, но некоторые операционные системы устанавливают его значение по умолчанию на выключенное состояние.
Типичный наблюдаемый эффект, когда этот параметр включен, заключается в том, что объекты общей памяти, используемые для параллельного выполнения запросов, удаляются в произвольные моменты времени, что приводит к ошибкам и предупреждениям при попытке их открытия и удаления, например:
WARNING: could not remove shared memory segment "/PostgreSQL.1450751626": No such file or directory
Различные типы объектов IPC (общая память против семафоров, System V против POSIX) обрабатываются системой systemd по-разному, что может привести к различиям в удалении этих ресурсов. Однако полагаться на эти различия не рекомендуется.
«Выход пользователя из системы» может произойти в рамках задачи обслуживания или вручную, когда администратор входит в систему как пользователь postgres
или что-то подобное, что затрудняет его предотвращение.
Определение «системного пользователя» осуществляется во время компиляции systemd на основе параметра SYS_UID_MAX
в /etc/login.defs
.
Сценарии упаковки и развертывания должны учитывать создание пользователя postgres
как системного пользователя с использованием useradd -r
, adduser --system
или аналогичных средств.
В качестве альтернативы, если учетная запись пользователя была создана неправильно или не может быть изменена, рекомендуется установить:
RemoveIPC=no
в /etc/systemd/logind.conf
или другом подходящем файле конфигурации.
Необходимо обеспечить выполнение хотя бы одного из этих двух условий, иначе сервер PostgreSQL будет крайне ненадежным.
Ограничения ресурсов
Операционные системы типа Unix применяют различные виды ограничений ресурсов, которые могут препятствовать нормальной работе сервера PostgreSQL. Особо важны ограничения на количество процессов для одного пользователя, количество открытых файлов для каждого процесса и объем памяти, доступной каждому процессу. У каждого из них есть «жесткий» и «мягкий» лимит. Мягкое ограничение действительно, но его может изменить пользователь до жесткого предела. Жесткий предел может быть изменен только пользователем root. Системный вызов setrlimit
отвечает за установку этих параметров. Встроенная команда оболочки ulimit
(оболочки Bourne) или limit
(csh) используется для управления ограничениями ресурсов из командной строки. В системах, производных от BSD, файл /etc/login.conf
управляет различными ограничениями ресурсов, установленными при входе в систему. См. документацию операционной системы для получения подробной информации. Соответствующие параметры - это maxproc
, openfiles
и datasize
. Например:
default:\
...
:datasize-cur=256M:\
:maxproc-cur=256:\
:openfiles-cur=256:\
...
((-cur
- это мягкий лимит. Добавьте -max
, чтобы установить жесткий лимит.)
Ядра также могут иметь системные ограничения на некоторые ресурсы.
В Linux параметр ядра fs.file-max
определяет максимальное количество открытых файлов, которые ядро будет поддерживать. Его можно изменить с помощью команды sysctl -w fs.file-max=
N
. Чтобы сделать настройку постоянной после перезагрузки, добавьте соответствующее назначение в файл /etc/sysctl.conf
. Максимальный предел файлов для процесса фиксируется во время компиляции ядра; дополнительную информацию можно найти в /usr/src/linux/Documentation/proc.txt
.
Сервер PostgreSQL использует один процесс на каждое соединение, поэтому необходимо предусмотреть не менее столько процессов, сколько разрешено соединений, в дополнение к тому, что требуется для остальной части системы. Обычно это не вызывает проблем, но если на одной машине запущено несколько серверов, ситуация может стать напряженной.
Заводской лимит по умолчанию на количество открытых файлов часто устанавливается на значения, которые позволяют многим пользователям сосуществовать на одном компьютере без использования непропорциональной доли системных ресурсов. Если на машине запущено много серверов, это может быть именно то, что требуется, но на выделенных серверах может потребоваться повышение этого предела.
С другой стороны, некоторые системы позволяют отдельным процессам открывать большое количество файлов; если более чем несколько процессов делают это, общий системный предел легко может быть превышен. Если это происходит, и нет желания изменять общесистемный предел, можно установить параметр конфигурации PostgreSQL max_files_per_process для ограничения потребления открытых файлов.
Еще одно ограничение ядра, которое может вызвать беспокойство при поддержке большого количества клиентских подключений, — это максимальная длина очереди подключения сокета. Если за очень короткий период поступает больше запросов на подключение, некоторые из них могут быть отклонены до того, как сервер PostgreSQL сможет обслужить запросы, и клиенты получат неинформативные сообщения об ошибках подключения, такие как «Ресурс временно недоступен» или «Соединение отказано». На многих платформах предел длины очереди по умолчанию составляет 128. Чтобы увеличить его, настройте соответствующий параметр ядра через sysctl, затем перезапустите сервер PostgreSQL. Этот параметр называется по-разному: net.core.somaxconn
в Linux, kern.ipc.soacceptqueue
в новой версии FreeBSD и kern.ipc.somaxconn
в macOS и других вариантах BSD.
Повреждение памяти Linux
Поведение виртуальной памяти по умолчанию в Linux не является оптимальным для PostgreSQL. Из-за способа реализации выделения памяти ядром ядро может завершить работу процесса PostgreSQL postmaster (процесс сервера-наблюдателя), если требования к памяти со стороны PostgreSQL или другого процесса приведут к нехватке виртуальной памяти в системе.
Если это произойдет, появится сообщение ядра, похожее на следующее (см. документацию и конфигурацию системы, чтобы узнать, где искать такое сообщение):
Out of Memory: Killed process 12345 (postgres).
Это указывает на то, что процесс postgres
был завершен из-за нехватки памяти. Хотя существующие подключения к базе данных будут продолжать функционировать нормально, новые подключения приниматься не будут. Для восстановления необходимо перезапустить PostgreSQL.
Один из способов избежать этой проблемы — запустить PostgreSQL на машине, где можно быть уверенным, что другие процессы не исчерпают память машины. Если памяти мало, увеличение пространства подкачки операционной системы может помочь избежать проблемы, поскольку убийца при нехватке памяти (OOM) вызывается только тогда, когда физическая память и пространство подкачки исчерпаны.
Если сама PostgreSQL является причиной того, что система исчерпывает память, можно избежать проблемы, изменив конфигурацию. В некоторых случаях может помочь снижение параметров конфигурации, связанных с памятью, особенно shared_buffers
, work_mem
и hash_mem_multiplier
. В других случаях проблема может быть вызвана тем, что разрешено слишком много подключений к самому серверу баз данных. Во многих случаях лучше уменьшить max_connections
и вместо этого использовать внешнее программное обеспечение для управления пулом подключений.
Можно изменить поведение ядра таким образом, чтобы оно не выделяло "перераспределение" памяти. Хотя этот параметр не предотвратит вызов OOM killer полностью, он значительно снизит вероятность его вызова и, следовательно, приведет к более устойчивому поведению системы. Это делается путем выбора строгого режима перераспределения через sysctl
:
sysctl -w vm.overcommit_memory=2
или поместив эквивалентную запись в /etc/sysctl.conf
. Также может потребоваться изменить связанную настройку vm.overcommit_ratio
. Подробности можно найти в документации ядра по адресу.
Другой подход, который можно использовать с изменением или без изменения vm.overcommit_memory
, заключается в установке значения корректировки оценки OOM для основного процесса, равного -1000
, что гарантирует, что он не будет атакован убийцей OOM. Самый простой способ сделать это — выполнить:
echo -1000 > /proc/self/oom_score_adj
в сценарии запуска PostgreSQL непосредственно перед вызовом postgres. Обратите внимание, что эти действия должны выполняться от имени root, иначе они не будут иметь никакого эффекта; поэтому сценарий запуска, принадлежащий root, является самым простым местом для этого. Если это сделано, также следует установить эти переменные окружения в сценарии запуска перед вызовом postgres:
export PG_OOM_ADJUST_FILE=/proc/self/oom_score_adj
export PG_OOM_ADJUST_VALUE=0
Эти настройки приведут к тому, что дочерние процессы postmaster будут работать с нормальной корректировкой оценки OOM, равной нулю, так что при необходимости убийца OOM все еще сможет нацеливаться на них. Можно использовать какое-то другое значение для PG_OOM_ADJUST_VALUE
, если требуется, чтобы дочерние процессы работали с какой-либо другой корректировкой оценки OOM. (PG_OOM_ADJUST_VALUE
также может быть опущен, в этом случае он по умолчанию равен нулю.) Если не установить PG_OOM_ADJUST_FILE
, дочерние процессы будут работать с той же корректировкой оценки OOM, что и основной процесс, что неразумно, поскольку вся суть в том, чтобы обеспечить предпочтительную настройку основного процесса.
Страницы большого размера в Linux
Использование страниц большого размера уменьшает накладные расходы при использовании больших непрерывных блоков памяти, как это делает PostgreSQL, особенно при использовании больших значений параметра shared_buffers. Для использования этой функции в PostgreSQL требуется ядро с поддержкой CONFIG_HUGETLBFS=y
и CONFIG_HUGETLB_PAGE=y
. Также необходимо настроить операционную систему для предоставления достаточного количества страниц большого размера желаемого размера. Чтобы определить необходимое количество страниц большого размера, используйте команду postgres
для просмотра значения параметра shared_memory_size_in_huge_pages. Обратите внимание, что сервер должен быть остановлен, чтобы просмотреть этот параметр, вычисляемый во время выполнения. Это может выглядеть так:
$ postgres -D $PGDATA -C shared_memory_size_in_huge_pages
3170
$ grep ^Hugepagesize /proc/meminfo
Hugepagesize: 2048 kB
$ ls /sys/kernel/mm/hugepages
hugepages-1048576kB hugepages-2048kB
В этом примере используется значение по умолчанию 2 МБ, но также можно явно запросить либо 2 МБ, либо 1 ГБ с помощью параметра huge_page_size для адаптации количества страниц, рассчитанного командой shared_memory_size_in_huge_pages
. Хотя необходимо не менее 3170
страниц большого размера в этом примере, более высокая настройка была бы уместной, если другие программы на машине также нуждаются в страницах большого размера. Это можно установить следующим образом:
# sysctl -w vm.nr_hugepages=3170
Добавьте эту настройку в /etc/sysctl.conf
, чтобы она применялась после перезагрузки. Для нестандартного размера страниц большого размера можно использовать:
# echo 3170 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
Также возможно предоставить эти настройки во время загрузки с использованием параметров ядра, таких как hugepagesz=2M hugepages=3170
.
Иногда ядро не может выделить желаемое количество огромных страниц сразу из-за фрагментации, поэтому может потребоваться повторить команду или перезагрузить компьютер. (Сразу после перезагрузки большая часть памяти машины должна быть доступна для преобразования в огромные страницы.) Чтобы проверить ситуацию с выделением огромных страниц для данного размера, используйте:
$ cat /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
Также может потребоваться предоставить пользователю операционной системы сервера баз данных разрешение на использование огромных страниц, установив vm.hugetlb_shm_group
через sysctl и/или предоставив разрешение на блокировку памяти с помощью ulimit -l
.
По умолчанию поведение огромных страниц в PostgreSQL заключается в их использовании при возможности, с размером огромной страницы по умолчанию в системе, и переходе к обычным страницам в случае сбоя. Чтобы принудительно использовать огромные страницы, можно установить huge_pages на on
в postgresql.conf
. Обратите внимание, что с этой настройкой PostgreSQL не запустится, если доступных огромных страниц недостаточно.
Для подробного описания функции огромных страниц Linux, обратитесь к https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt.