16.5. Gerência dos recursos do núcleo

Uma instalação grande do PostgreSQL pode exaurir, rapidamente, vários limites de recurso do sistema operacional (Em alguns sistemas o padrão de distribuição é tão baixo que, na verdade, nem há realmente necessidade de uma instalação "grande"). Caso tenha deparado com este tipo de problema, prossiga a leitura.

16.5.1. Memória compartilhada e semáforos

A memória compartilhada e os semáforos são referenciados coletivamente como "System V IPC" [1] (junto com as filas de mensagens, que não são relevantes para o PostgreSQL). Quase todo sistema operacional moderno fornece estas funcionalidades, mas nem todos as têm ativas ou com tamanho suficiente por padrão, especialmente os sistemas herdados do BSD (Para os ports para o QNX e para o BeOS, o PostgreSQL fornece sua própria implementação de substituição destas funcionalidades).

A completa falta destas funcionalidades é geralmente manifestada por um erro de "Chamada de sistema ilegal" na inicialização do servidor. Neste caso, não existe nada a ser feito além de reconfigurar o núcleo. O PostgreSQL não funciona sem estas funcionalidades.

Quando o PostgreSQL excede um dos vários limites rígidos de IPC, o servidor se recusa a inicializar, e deve deixar uma mensagem de erro instrutiva descrevendo o problema encontrado e o que fazer sobre o mesmo (Também deve ser vista a Seção 16.3.1 .) Os parâmetros relevantes do núcleo possuem nomes consistentes entre sistemas diferentes; A Tabela 16-2 mostra uma visão geral. Entretanto, os métodos para defini-los variam. Abaixo são fornecidas sugestões para algumas plataformas. Não se deve esquecer que geralmente é necessário reinicializar o computador e até, possivelmente, recompilar o núcleo para alterar estas definições.

Tabela 16-2. Parâmetros do IPC do System V

Nome Descrição Valores razoáveis
SHMMAX Tamanho máximo de um segmento de memória compartilhada (bytes) [a] 250 kB + 8.2 kB * shared_buffers + 14.2 kB * max_connections até o infinito
SHMMIN Tamanho mínimo de um segmento de memória compartilhada (bytes) 1
SHMALL Quantidade total de memória compartilhada disponível (bytes ou páginas) se em bytes, o mesmo que SHMMAX; se em páginas, ceil(SHMMAX/PAGE_SIZE)
SHMSEG Número máximo de segmentos de memória compartilhada por processo somente 1 segmento é necessário, mas o padrão é muito maior
SHMMNI Número máximo de segmentos de memória compartilhada para todo o sistema como SHMSEG mais espaço para outras aplicações
SEMMNI Número máximo de identificadores de semáforos (ou seja, conjuntos) pelo menos ceil(max_connections / 16)
SEMMNS Número máximo de semáforos para todo o sistema ceil(max_connections / 16) * 17 mais espaço para outras aplicações
SEMMSL Número máximo de semáforos por conjunto pelo menos 17
SEMMAP Número de entradas no mapa de semáforos [b] veja o texto
SEMVMX Valor máximo de um semáforo pelo menos 1000 (O padrão é geralmente 32767; não mude a não ser quando for obrigado a fazê-lo)
Notas:
a. A função shmget() é utilizada para obter acesso a um segmento de memória compartilhada. Esta função falha se o valor do tamanho for menor que SHMMIN ou maior do que SHMMAX. Sun Product Documentation (N. do T.)
b. SEMMAP deve ser definido como o produto de SEMMNI e SEMMSL: (SEMMAP = SEMMNI * SEMMSL). Setting our sights on semaphores (N. do T.)

O parâmetro de memória compartilhada mais importante é SHMMAX, o tamanho máximo, em bytes, de um segmento de memória compartilhada. Se for recebida uma mensagem de erro da função shmget como "Argumento inválido", é provável que este limite tenha sido excedido. O tamanho do segmento de memória compartilhada requerido varia tanto com o número de buffers requisitados (opção -B) quanto com o número de conexões permitidas (opção -N), embora esta última seja mais significativa (É possível, como uma solução temporária, diminuir estas definições para eliminar o problema). Como uma aproximação grosseira, o tamanho de segmento requerido pode ser estimado conforme sugerido em Tabela 16-2 . Toda mensagem de erro que vier a ser recebida conterá o tamanho da alocação requerida que falhou.

Alguns sistemas também possuem um limite para a quantidade total de memória compartilhada do sistema (SHMALL). Deve-se ter certeza que é grande o suficiente para o PostgreSQL mais as outras aplicações que utilizam segmentos de memória compartilhada. (Cuidado: em muitos sistemas SHMALL é medido em páginas, e não em bytes).

Menos provável de causar problema é o tamanho mínimo para os segmentos de memória compartilhada (SHMMIN), que deve ser no máximo aproximadamente 256 kB para o PostgreSQL (geralmente é apenas 1). O número máximo de segmentos para todo o sistema (SHMMNI) ou por processo (SHMSEG) não devem causar problema a menos que o sistema os tenha definido como zero.

O PostgreSQL utiliza um semáforo por conexão permitida (opção -N), em conjuntos de 16. Cada um destes conjuntos também contém um 17º semáforo contendo um "número mágico", para detectar colisões com conjuntos de semáforos utilizados por outras aplicações. O número máximo de semáforos no sistema é definido por SEMMNS que, conseqüentemente, deve ser pelo menos tão alto quanto max_connections mais um adicional para cada 16 conexões permitidas (veja a fórmula na Tabela 16-2 ). O parâmetro SEMMNI determina o limite do número de conjuntos de semáforos que podem existir no sistema de uma vez. Portanto, este parâmetro deve ser pelo menos igual a ceil(max_connections / 16). Diminuir o número de conexões permitidas é um recurso temporário para evitar falhas, geralmente informadas pela mensagem "Nenhum espaço disponível na unidade" emitida pela função semget, que confunde.

Em alguns casos também pode haver necessidade de aumentar SEMMAP para que fique pelo menos na ordem de grandeza de SEMMNS. Este parâmetro define o tamanho do mapa de recursos de semáforos, no qual cada bloco contíguo de semáforos disponíveis precisa de uma entrada. Quando um conjunto de semáforos é liberado, este conjunto é adicionado a uma entrada existente adjacente ao bloco liberado, ou é registrado sob uma nova entrada no mapa. Se o mapa estiver cheio, os semáforos liberados serão perdidos (até a reinicialização do servidor). A fragmentação do espaço de semáforos pode, ao longo do tempo, fazer com que haja menos semáforos disponíveis do que deveria haver.

O parâmetro SEMMSL, que determina quantos semáforos podem existir em um conjunto, deve ser pelo menos igual a 17 para o PostgreSQL.

Várias outras definições relacionadas com "desfazer semáforo", como SEMMNU e SEMUME, não são de interesse do PostgreSQL.

BSD/OS
Memória compartilhada. Por padrão, são suportados somente 4 MB de memória compartilhada. Deve-se ter em mente que a memória compartilhada não é paginável; fica bloqueada na RAM. Para aumentar a quantidade de memória compartilhada suportada pelo sistema, deve ser adicionado algo parecido com as linhas mostradas abaixo ao arquivo de configuração do núcleo.
options "SHMALL=8192"
options "SHMMAX=\(SHMALL*PAGE_SIZE\)"
SHMALL é medido em páginas de 4KB, portanto um valor igual a 1024 representa 4 MB de memória compartilhada. Desta forma, as linhas acima aumentam para 32 MB o máximo de área de memória compartilhada. Para os usuários da versão 4.3 ou posterior, provavelmente será necessário aumentar KERNEL_VIRTUAL_MB para um valor acima do valor padrão de 248. Uma vez que as alterações tenham sido efetuadas, o núcleo deve ser recompilado e o sistema reinicializado.
Os usuários da versão 4.0, ou anterior, devem utilizar bpatch para descobrir o valor de sysptsize do núcleo corrente. Este valor é computado dinamicamente durante a inicialização do sistema operacional.
$ bpatch -r sysptsize
0x9 = 9
Em seguida, deve ser adicionado SYSPTSIZE com um valor fixo no arquivo de configuração do núcleo. O valor encontrado utilizando bpatch deve ser aumentado; deve ser adicionado 1 para cada 4 MB adicionais de memória compartilhada desejada.
options "SYSPTSIZE=16"
sysptsize não pode ser mudado por sysctl.
Semáforos. Provavelmente vai ser necessário aumentar o número de semáforos também. Por padrão, o PostgreSQL aloca 34 semáforos, que é mais da metade do valor total padrão do sistema de 60. Os valores desejados devem ser definidos no arquivo de configuração do núcleo como, por exemplo:
options "SEMMNI=40"
options "SEMMNS=240"
FreeBSD
NetBSD
OpenBSD
As opções SYSVSHM e SYSVSEM precisam estar habilitadas quando o núcleo é compilado (Estão por padrão). O tamanho máximo da memória compartilhada é determinado pela opção SHMMAXPGS (em páginas). A seguir está mostrado um exemplo de como definir os vários parâmetros:
options         SYSVSHM
options         SHMMAXPGS=4096
options         SHMSEG=256

options         SYSVSEM
options         SEMMNI=256
options         SEMMNS=512
options         SEMMNU=256
options         SEMMAP=256
(No NetBSD e no OpenBSD a palavra chave é, na verdade, option, no singular). Também pode-se querer configurar o núcleo para que bloqueie a memória compartilhada na RAM, impedindo que seja paginada para a área de troca (swap). Deve ser utilizada a definição kern.ipc.shm_use_phys do sysctl.
HP-UX
A definição padrão costuma ser suficiente para as instalações normais. No HP-UX 10, o padrão de fábrica para SEMMNS é 128, que pode ser muito baixo para servidores de banco de dados grandes. Os parâmetros do IPC podem ser definidos no System Administration Manager (SAM), sob Kernel Configuration->Configurable Parameters. Quando tiver acabado clique em Create A New Kernel.
Linux
O limite padrão de memória compartilhada (tanto SHMMAX quanto SHMALL) é de 32 MB nos núcleos 2.2, mas pode ser modificado no arquivo de sistema proc (sem reinicializar o Linux). Por exemplo, para permitir 128 MB:
$ echo 134217728 >/proc/sys/kernel/shmall
$ echo 134217728 >/proc/sys/kernel/shmmax
Estes comandos podem ser colocados em um script executado durante a inicialização. Como alternativa, pode ser utilizado sysctl, se estiver disponível, para controlar estes parâmetros. Deve-se procurar pelo arquivo chamado /etc/sysctl.conf e adicionar linhas como as mostradas abaixo ao arquivo:
kernel.shmall = 134217728
kernel.shmmax = 134217728
Este arquivo geralmente é processado durante a inicialização, mas sysctl também pode ser chamada explicitamente posteriormente. Os outros parâmetros possuem tamanho suficiente para qualquer aplicação. Se quiser ver por si próprio, olhe em /usr/src/linux/include/asm-xxx/shmparam.h e /usr/src/linux/include/linux/sem.h.
MacOS X
No OS X 10.2, e anteriores, deve ser editado o arquivo /System/Library/StartupItems/SystemTuning/SystemTuning e modificados os valores nos seguintes comandos:
sysctl -w kern.sysv.shmmax
sysctl -w kern.sysv.shmmin
sysctl -w kern.sysv.shmmni
sysctl -w kern.sysv.shmseg
sysctl -w kern.sysv.shmall
No OS X 10.3 estes comandos foram movidos para /etc/rc devendo ser editados neste local.
SCO OpenServer
Na configuração padrão, somente são permitidos 512 kB de memória compartilhada por segmento, suficiente para cerca de -B 24 -N 12. Para aumentar esta definição, primeiro deve-se tornar o diretório /etc/conf/cf.d o diretório corrente. Para exibir o valor corrente de SHMMAX deve ser executado:
./configure -y SHMMAX
Para definir um novo valor para SHMMAX deve ser executado
./configure SHMMAX=valor
onde valor é o novo valor que se deseja utilizar (em bytes). Após definir SHMMAX o núcleo deve ser reconstruído
./link_unix
e o sistema reinicializado.
Solaris
Pelo menos na versão 2.6 o tamanho máximo padrão dos segmentos de memória compartilhada é muito baixo para o PostgreSQL. As definições relevantes podem ser mudadas em /etc/system como, por exemplo:
set shmsys:shminfo_shmmax=0x2000000
set shmsys:shminfo_shmmin=1
set shmsys:shminfo_shmmni=256
set shmsys:shminfo_shmseg=256

set semsys:seminfo_semmap=256
set semsys:seminfo_semmni=512
set semsys:seminfo_semmns=512
set semsys:seminfo_semmsl=32
O computador deve ser reinicializado para as modificações terem efeito. Também deve ser vista a página Shared memory uncovered para obter informações sobre memória compartilhada sob o Solaris.
UnixWare
No UnixWare 7 o tamanho máximo para os segmentos de memória compartilhada é de 512 kB na configuração padrão. É suficiente para cerca de -B 24 -N 12. Para obter o valor corrente de SHMMAX, deve ser executado
/etc/conf/bin/idtune -g SHMMAX
que mostra os valores corrente, padrão, mínimo e máximo. Para definir um novo valor para SHMMAX, deve ser executado
/etc/conf/bin/idtune SHMMAX valor
onde valor é o novo valor que se deseja utilizar (em bytes). Após definir SHMMAX, o núcleo deve ser reconstruído:
/etc/conf/bin/idbuild -B
e o sistema reinicializado.

16.5.2. Limites de recursos

Os sistemas operacionais da família Unix obrigam respeitar vários tipos de limite de recursos que podem interferir com a operação do servidor PostgreSQL. São de particular importância os limites do número de processos por usuário, de número de arquivos abertos por processo, e a quantidade de memória disponível para cada processo. Cada um destes possui um limite "rígido" e um "flexível". O limite flexível é o que realmente conta, mas pode ser alterado pelo usuário até o limite rígido. O limite rígido somente pode ser alterado pelo usuário root. A chamada de sistema setrlimit é responsável pela definição destes parâmetros. São utilizados o comando interno do interpretador de comandos ulimit (interpretadores de comandos Bourne) ou limit (csh) para controlar os limites de recursos a partir da linha de comandos. Nos sistemas derivados do BSD o arquivo /etc/login.conf controla os limites dos vários recursos definidos durante a autenticação. Para obter detalhes deve ser vista a documentação do sistema operacional. Os parâmetros relevantes são maxproc, openfiles e datasize. Por exemplo:

default:\
...
        :datasize-cur=256M:\
        :maxproc-cur=256:\
        :openfiles-cur=256:\
...

(-cur é o limite flexível. Deve ser anexado -max para definir o limite rígido).

Os núcleos também podem ter limites para alguns recursos para todo o sistema.

O servidor PostgreSQL utiliza um processo por conexão e, portanto, deve ser especificado pelo menos tantos processos quantas forem as conexões permitidas, em adição ao que for necessário para o restante do sistema. Normalmente não é um problema, mas se forem executados vários servidores na mesma máquina pode ficar apertado.

O limite padrão original para o número de arquivos abertos geralmente é definido como um valor "socialmente amigável", para permitir a coexistência de muitos usuários em uma mesma máquina sem utilizar uma fração não apropriada dos recursos do sistema. Se forem executados vários servidores na mesma máquina provavelmente é o que se deseja, mas para servidores dedicados pode ser necessário aumentar este limite.

Por outro lado, alguns sistemas podem permitir que cada processo abra um grande número de arquivos; se mais que uns poucos processos o fizerem, então o limite global para todo o sistema pode ser facilmente excedido. Se isto estiver acontecendo, e não for desejado alterar o limite para todo o sistema, pode ser definido o parâmetro de configuração max_files_per_process do PostgreSQL para limitar a quantidade de arquivos abertos.

16.5.3. Sobre-alocação de memória no Linux

No Linux 2.4 e posteriores, o comportamento padrão de memória virtual não é o ótimo para o PostgreSQL. Devido à maneira como o núcleo implementa a sobre-alocação (overcommit) de memória, o núcleo pode fechar o servidor PostgreSQL (o processo postmaster), se a demanda por memória de um outro processo fizer com que o sistema fique sem memória virtual. [2]

Caso aconteça, será recebida uma mensagem do núcleo parecida com esta (deve ser consultada a documentação e configuração do sistema para achar onde este tipo de mensagem pode ser vista):

Out of Memory: Killed process 12345 (postmaster).

Esta mensagem indica que o processo postmaster foi fechado devido à falta de memória. Embora as conexões com os bancos de dados existentes continuem funcionando normalmente, não é aceita nenhuma nova conexão. Para voltar ao normal é necessário reinicializar o PostgreSQL.

Uma forma de evitar este problema é executar o PostgreSQL em uma máquina onde se tenha certeza que outros processos não vão deixar a máquina sem memória.

No Linux 2.6 e posteriores, uma solução melhor é modificar o comportamento do núcleo para que não haja "sobre-alocação" de memória. Isto é feito selecionando um modo estrito de sobre-alocação através do comando sysctl:

sysctl -w vm.overcommit_memory=2

ou colocando uma entrada equivalente em /etc/sysctl.conf. Também pode-se querer modificar a definição relacionada vm.overcommit_ratio. Para obter detalhes deve ser visto o arquivo de documentação do núcleo Documentation/vm/overcommit-accounting.

É relatado que algumas distribuições do núcleo 2.4 do Linux possuem uma versão inicial do parâmetro overcommit do comando sysctl da versão 2.6. Entretanto, definir vm.overcommit_memory como 2 em um núcleo que não possui o código relevante torna as coisas piores, e não melhores. Recomenda-se a inspeção do código fonte do núcleo utilizado (deve ser vista a função vm_enough_memory no arquivo mm/mmap.c), para verificar o que é suportado na versão utilizada antes de tentar utilizar numa instalação 2.4. A presença do arquivo de documentação overcommit-accounting não deve ser assumida como um evidência que a funcionalidade está presente. Em caso de dúvida deve ser consultado um especialista no núcleo ou o distribuidor do núcleo utilizado.

Notas

[1]

Com o System V a AT&T introduziu três novas formas de facilidade de comunicação entre processos (IPC) (filas de mensagens, semáforos e memória compartilhada). Embora o comitê POSIX ainda não tenha completado a padronização destas facilidades, a maioria das implementações dão suporte as mesmas. Além disso, Berkeley (BSD) utiliza soquetes como sua forma primária de IPC, em vez dos elementos do System V. O Linux tem capacidade para utilizar as duas formas de IPC, tanto BSD quanto System V. System V IPC (N. do T.)

[2]

memory overcommit — a sobre-alocação de memória é uma funcionalidade do núcleo do Linux que permite as aplicações alocarem mais memória do que realmente existe. A idéia por trás desta funcionalidade é que algumas aplicações alocam grandes quantidades de memória "apenas para o caso de precisarem", mas na verdade nunca utilizam esta memória. Portanto, a sobre-alocação de memória permite a execução de mais aplicações do que na verdade cabe na memória, desde de que as aplicações realmente não utilizem a memória alocada. Se o fizerem, o núcleo fecha a aplicação. GNUsound - FAQ (N. do T.)

SourceForge.net Logo