Introdução
No PostgreSQL, a organização de arquivos e diretórios, bem como a gestão de processos, são componentes fundamentais para entender o seu funcionamento. Este artigo fornecerá uma visão geral de como o PostgreSQL estrutura seus dados e controla seus processos.
Roteiro:
- Arquivos e diretórios dos dados no PostgreSQL:
- Binários
- Arquivos de configuração
- Arquivos de logs
- Subdiretórios
- Processos
Arquivos e diretórios dos dados no PostgreSQL
O PostgreSQL organiza seus dados e configurações em uma estrutura de diretórios específica. A localização desses diretórios pode variar dependendo da instalação, mas geralmente segue um padrão. O diretório principal que contém todos os dados do PostgreSQL é o Base Directory (também conhecido pela variável de ambiente $PGDATA), que é definido durante a inicialização do cluster PostgreSQL com o comando initdb. Para sistemas Linux, o endereço de PGDATA pode variar conforme a distribuição:
- Debian: /var/lib/postgresql/<versão>/<nome_do_cluster>
- Red Hat: /var/lib/pgsql/<versão>/data
Claro, você pode definir qualquer diretório/disco/partição para colocar seus dados, como demonstramos nos artigos anteriores sobre instalação. Portanto é uma boa ideia usar a variável de ambiente $PGDATA (que, a depender da distribuição, já vem setada para o usuário postgres) ou então descobrir esse diretório pelo comando no psql SHOW data_directory:
$ psql -c 'SHOW data_directory;'
data_directory
-----------------------------
/var/lib/postgresql/16/main
(1 row)
Nesse diretório, temos arquivos e subdiretórios importantes para o programa, que veremos a seguir.
Binários
Dentre os principais arquivos do PostgreSQL, temos os binários, que são executáveis responsáveis por iniciar e interagir com o banco de dados. Eles estão em diferentes diretórios, que mudam conforme o sistema operacional. Considerando essas três distribuições Linux, podemos encontrar os principais binários em:
- Debian:
- /usr/share/postgresql-common: contém arquivos e scripts comuns utilizados por várias versões do PostgreSQL, por exemplo, pg_ctlcluster e pg_createcluster;
- /usr/lib/postgresql/<sua_versão>/bin: neste diretório, você pode encontrar os binários específicos da versão do PostgreSQL, como o próprio psql, os utilitários createdb, initdb etc.
- Red Hat:
- /usr/pgsql/<versão>/bin/: guarda binários e executáveis específicos de cada versão do PostgreSQL.
- Instalação via compilação:
- /usr/local/pgsql/bin/
Arquivos de configuração
- postgresql.conf: principal arquivo de configuração do servidor PostgreSQL. Contém parâmetros para ajustar o desempenho, a segurança, o comportamento e outras opções do servidor. Em distribuições Debian e derivados, este arquivo está em outro local, num diretório que agrega todos os arquivos de configuração: /etc/postgresql/<versão>/<nome_do_cluster>;
- pg_hba.conf: configurações de autenticação do host. Define quem pode conectar-se ao banco de dados e como as conexões são autenticadas. Assim como antes, em distribuições Debian e derivados, este arquivo fica em outro local;
- pg_ident.conf: mapeamentos para autenticação do tipo ident no pg_hba.conf. Usado para mapear nomes de usuários do sistema operacional para nomes de usuários do PostgreSQL. Mais uma vez, em distribuições Debian e derivados, este arquivo fica em outro local, vide acima;
- postgresql.auto.conf: armazena as configurações definidas dinamicamente através do comando ALTER SYSTEM SET, bem como outras configurações definidas automaticamente pelo próprio PostgreSQL. Você não deve editar este arquivo manualmente!;
- PG_VERSION: contém a versão do PostgreSQL em uso no cluster (major version);
- postmaster.pid: contém o ID do processo (PID) do servidor PostgreSQL em execução e outras informações, como diretório de dados do cluster, data de início do processo etc.;
- postmaster.opts: arquivo que registra as opções de linha de comando usadas por último na inicialização do servidor PostgreSQL.
Arquivos de logs
Dentro do $PGDATA, temos outros diretórios importantes que guardam arquivos do PostgreSQL, como os arquivos de log. Normalmente, os logs ficam em $PGDATA/logs, mas em distribuições Debian e derivadas eles estão localizados em /var/log/postgresql, como podemos ver na saída abaixo.
# ls -lh /var/log/postgresql/*
total 6.6M
drwxrwxr-t 2 root postgres 4.0K May 19 00:00 .
drwxr-xr-x 10 root root 4.0K May 1 00:00 ..
-rw-r----- 1 postgres adm 123K May 23 09:40 postgresql-16-main.log
-rw-r----- 1 postgres adm 6.0M May 19 00:00 postgresql-16-main.log.1
-rw-r----- 1 postgres adm 254K May 12 00:00 postgresql-16-main.log.2.gz
-rw-r----- 1 postgres adm 18K May 5 00:00 postgresql-16-main.log.3.gz
-rw-r----- 1 postgres adm 125K Apr 28 00:00 postgresql-16-main.log.4.gz
-rw-r----- 1 postgres adm 27K Apr 21 00:00 postgresql-16-main.log.5.gz
-rw-r----- 1 postgres adm 36K Apr 14 00:00 postgresql-16-main.log.6.gz
-rw-r----- 1 postgres adm 1.1K Apr 7 00:00 postgresql-16-main.log.7.gz
-rw-r----- 1 postgres adm 2.0K Mar 31 00:00 postgresql-16-main.log.8.gz
Na verdade, você pode escolher outros lugares arbitrários para colocar seus logs, como em um disco separado (pode ser útil em servidores com muita carga), ajustando a variável log_directory. Abaixo vemos um exemplo da localização do diretório de logs na AWS RDS:
SHOW log_directory;
log_directory
----------------------
/rdsdbdata/log/error
O valor do log_directory pode ser absoluto, com o path completo ou relativo ao diretório do $PGDATA.
Subdiretórios
- base/: contém um subdiretório para cada banco de dados individual no cluster;
- Dentro desses subdiretórios de cada banco que são identificados com números (16390, por exemplo) temos com os dados de cada objeto no banco, como tabelas e índice. Estes arquivos possuem eventualmente outros com o mesmo número e um sufixo _fsm (free space map) e
_vm
(visibility map), que são essenciais para manutenção e otimização e controle de transações. Além disso, temos um diretório chamado pgsql_tmp com arquivos temporários como tabelas temporárias. Eventualmente é possível armazenar estes arquivos temporários em outros tablespaces, ajustando a configuração temp_tablespaces;
- Dentro desses subdiretórios de cada banco que são identificados com números (16390, por exemplo) temos com os dados de cada objeto no banco, como tabelas e índice. Estes arquivos possuem eventualmente outros com o mesmo número e um sufixo _fsm (free space map) e
- global/: contém tabelas e dados globais, como informações sobre usuários e grupos, por exemplo, as tabelas pg_database e pg_control;
- Aqui também temos os arquivos _fsm e _vm, mas a nível global, ou seja, que se aplicam a todos os bancos de dados em um cluster;
- pg_xlog/ ou pg_wal/: contém os arquivos de log de transação (WAL – Write-Ahead Logging), essenciais para a recuperação de dados;
- pg_clog/ ou pg_commit_ts/: mantém informações sobre o estado das transações atuais;
pg_stat/
: armazena dados estatísticos permanentes utilizados para otimização de consultas;- pg_stat_tmp/: armazena dados estatísticos temporários utilizados para otimização de consultas;
pg_tblspc/
: pontos de montagem de tablespaces, que permitem a administração de locais de armazenamento adicionais.
Processos
PostgreSQL é um sistema de gerenciamento de banco de dados do tipo cliente-servidor. Diferente de outros modelos, ele utiliza uma arquitetura multiprocesso para rodar em um único host. Imagine uma equipe trabalhando em conjunto para cuidar do seu banco de dados: esse é o conceito por trás dessa arquitetura.
Essa “equipe” é composta por diversos processos, cada um com uma função específica:
- postmaster (server process): o processo principal do PostgreSQL. É responsável por iniciar, parar e supervisionar todos os processos de servidor do PostgreSQL. Ele recebe conexão de apenas uma porta (a 5432 por padrão), porém podemos ter mais de uma instância do PostgreSQL rodando no mesmo servidor, especificando uma porta para cada instância. Podemos ter, por exemplo, um PostgreSQL na versão 16 na porta 5432 e outro na versão 15 na porta 5433;
- postgres (backend process): cada conexão ao banco de dados é gerenciada por um processo postgres dedicado. Esse processo é responsável por receber e executar as consultas e comandos enviados pelos clientes, garantindo uma experiência personalizada para cada um;
- autovacuum launcher (background process): processo responsável pela limpeza automática do banco de dados, removendo registros obsoletos gerados por operações de UPDATE e DELETE;
- wal writer (background process): gerencia a gravação dos logs de transação (WAL) no disco, garantindo a durabilidade das transações, o que permite a recuperação do banco de dados;
- wal sender (background process): responsável por enviar os registros do WAL (Write-Ahead Logging) do servidor primário para um ou mais servidores de réplica (standby). Este processo é fundamental para a replicação em tempo real e a alta disponibilidade;
- wal receiver (background process): é executado em servidores de réplica e recebe os registros do WAL enviados pelo processo WAL sender do servidor primário;
- statistics collector (background process): é responsável por coletar e agrupar estatísticas sobre a operação do banco de dados, como contagem de linhas lidas, inseridas, atualizadas ou deletadas;
- logging collector (background process): coleta e armazena mensagens de log do servidor PostgreSQL em arquivos de log;
- archiver (background process): copia os arquivos do WAL para um local de arquivamento seguro após eles serem preenchidos;
- bgwriter (background process): é o “background writer”, que periodicamente escreve páginas sujas da memória para o disco, ajudando a manter a consistência dos dados;
- checkpointer (background process): periodicamente cria pontos de verificação (checkpoints) que ajudam na recuperação de falhas;
- IPC (background process): os processos do PostgreSQL se comunicam usando IPC (Inter-Process Communication), que inclui sinais (signals), memória compartilhada (shared memory) e semáforos (semaphores). Estes mecanismos permitem a coordenação entre os processos, garantindo a consistência e a integridade dos dados.
Abaixo segue o comando ps faux | grep postgres executado como root, que é um comando para mostrar todos os processos relacionados ao postgres, de todos os usuários, e sua saída:
# ps faux | grep postgres
postgres 171711 0.0 1.7 217608 17460 ? Ss Apr09 7:52 /usr/lib/postgresql/16/bin/postgres -D /var/lib/postgresql/16/main -c config_file=/etc/postgresql/16/main/postgresql.conf
postgres 171712 0.0 7.8 218036 77644 ? Ss Apr09 0:02 \_ postgres: 16/main: checkpointer
postgres 171713 0.0 0.7 217756 7468 ? Ss Apr09 0:41 \_ postgres: 16/main: background writer
postgres 171715 0.0 0.6 217608 6796 ? Ss Apr09 0:44 \_ postgres: 16/main: walwriter
postgres 171716 0.0 0.7 219208 7108 ? Ss Apr09 1:45 \_ postgres: 16/main: autovacuum launcher
postgres 171717 0.0 0.4 219184 4340 ? Ss Apr09 0:02 \_ postgres: 16/main: logical replication launcher
Como um exemplo adicional, fizemos um teste com o pg_bench (com escala 10x maior do que a padrão, 50 clientes e quatro threads, com duração de 120 segundos) e rodamos, desta vez, o comando top -c, que fornece a visualização dinâmica e interativa dos processos. Este é um trecho da saída:
# top -c
top - 18:01:38 up 57 days, 2:24, 2 users, load average: 19.95, 5.63, 1.93
Tasks: 135 total, 32 running, 103 sleeping, 0 stopped, 0 zombie
%Cpu(s): 64.7 us, 34.3 sy, 0.0 ni, 0.0 id, 1.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 961.0 total, 77.9 free, 505.3 used, 679.6 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 455.7 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1219997 postgres 20 0 239676 7792 6412 S 17.5 0.8 0:09.62 /usr/lib/postgresql/16/bin/pgbench -c 50 -j 4 -T 120 postgres
1220014 postgres 20 0 219816 84068 80660 R 2.3 8.5 0:00.92 postgres: 16/main: postgres postgres [local] idle in transaction
1220040 postgres 20 0 219820 82300 78888 S 2.0 8.4 0:00.90 postgres: 16/main: postgres postgres [local] UPDATE waiting
1220050 postgres 20 0 219820 83928 80516 R 2.0 8.5 0:00.90 postgres: 16/main: postgres postgres [local] UPDATE waiting
1220005 postgres 20 0 219816 80776 77376 R 1.7 8.2 0:00.90 postgres: 16/main: postgres postgres [local] COMMIT
1220007 postgres 20 0 219816 82044 78636 S 1.7 8.3 0:00.90 postgres: 16/main: postgres postgres [local] UPDATE waiting
1220009 postgres 20 0 219816 82604 79204 R 1.7 8.4 0:00.90 postgres: 16/main: postgres postgres [local] idle
1220010 postgres 20 0 219816 82204 78804 S 1.7 8.4 0:00.90 postgres: 16/main: postgres postgres [local] UPDATE waiting
1220011 postgres 20 0 219816 81988 78588 R 1.7 8.3 0:00.90 postgres: 16/main: postgres postgres [local] idle in transaction
1220012 postgres 20 0 219816 82944 79544 S 1.7 8.4 0:00.90 postgres: 16/main: postgres postgres [local] UPDATE waiting
1220013 postgres 20 0 219816 83216 79800 R 1.7 8.5 0:00.90 postgres: 16/main: postgres postgres [local] idle in transaction
1220015 postgres 20 0 219816 84092 80692 S 1.7 8.5 0:00.90 postgres: 16/main: postgres postgres [local] UPDATE waiting
1220017 postgres 20 0 219816 80868 77468 R 1.7 8.2 0:00.90 postgres: 16/main: postgres postgres [local] UPDATE waiting
1220018 postgres 20 0 219816 83108 79708 R 1.7 8.4 0:00.90 postgres: 16/main: postgres postgres [local] idle in transaction
1220021 postgres 20 0 219816 83968 80568 S 1.7 8.5 0:00.90 postgres: 16/main: postgres postgres [local] UPDATE waiting
1220022 postgres 20 0 219816 79704 76304 S 1.7 8.1 0:00.90 postgres: 16/main: postgres postgres [local] UPDATE waiting
1220023 postgres 20 0 219816 82652 79252 R 1.7 8.4 0:00.90 postgres: 16/main: postgres postgres [local] idle in transaction
1220024 postgres 20 0 219820 82452 79036 S 1.7 8.4 0:00.90 postgres: 16/main: postgres postgres [local] UPDATE waiting
1220025 postgres 20 0 219820 80704 77292 R 1.7 8.2 0:00.90 postgres: 16/main: postgres postgres [local] COMMIT
1220026 postgres 20 0 219820 79340 75928 R 1.7 8.1 0:00.90 postgres: 16/main: postgres postgres [local] idle in transaction
O primeiro processo pgbench é o que está executando o teste de benchmarking e consome 17,5% da CPU, sendo o responsável pela maior carga no sistema.
Também é possível observar vários processos em estado R (running) ou S (sleeping), o que é esperado em um ambiente de testes. Também temos os status idle in transaction e UPDATE waiting, indicando que estão aguardando a conclusão de transações ou de operações de atualização.
Conclusão
O PostgreSQL tem uma organização relativamente simples de arquivos, diretórios e processos. Para o desenvolvedor ou usuário final do banco de dados, essas informações podem ser mera curiosidade, mas para quem pretende ser um DBA, a história é bem diferente. É fundamental entender o que cada um faz e onde fica cada informação. Enquanto tudo estiver funcionando bem, você provavelmente não vai se preocupar muito com isso, mas quando problemas ocorrerem, como falhas de hardware, bugs etc., entender esses conceitos básicos será fundamental para resolver os problemas.
Mais informações podem ser encontradas na documentação oficial, aqui.
No próximo artigo, vamos entender um pouco melhor como os objetos do banco são organizados logicamente no catálogo interno e fisicamente nos diretórios $PGDATA/base, $PGDATA/global e $PGDATA/pg_tblspace.