postgres postgresql init initdb

Inicialização do cluster/instância

Uma instância, ou cluster, é um agrupamento de bancos de dados controlados por um SGBD (Sistema de Gerenciamento de Banco de Dados). Ela também contém objetos globais, como usuários e tablespaces, assim como arquivos de configuração. É sobre as instâncias (não sobre seus bancos de dados) que fazemos backups, restaurações, replicações físicas, monitoramento e diversas outras atividades de administração do sistema.

Obs.: A nomenclatura cluster é histórica e foi introduzida pelo padrão SQL na década de 80. O PostgreSQL tenta se manter o mais próximo possível do padrão SQL, por isso usa essa nomenclatura. Mas outros SGBDs costumam chamar o mesmo conceito de instância. Outros chamam de instância o processo que controla o grupo. Para evitar confusões do termo cluster em outros contextos, vou usar o termo instância a partir de agora para significar o grupo de bancos de dados.

                     ┌───────────────────┐
╔════════════════════╡ instância/cluster ╞═════════════════════╗
║                    └───────────────────┘                     ║
╠═╡global/╞═══════╗  ╔═════════════════════════════════╡base/╞═╣
║                 ║  ║                                         ║
║     O     O     ║  ║ ┏┥banco de dados┝┓ ┏━┥banco de dados┝━┓ ║
║    ─┼─   ─┼─    ║  ║ ┃└┤postgres├────┘┃ ┃ ┌─┤schema├─────┐ ┃ ║
║     │     │     ║  ║ ┗━━━━━━━━━━━━━━━━┛ ┃ │ ☑ tabelas    │ ┃ ║
║    ╱ ╲   ╱ ╲    ║  ║ ┏┥banco de dados┝┓ ┃ │ ☑ índices    │ ┃ ║
║ ☑ usuários      ║  ║ ┃└┤template1├───┘┃ ┃ │ ☑ visões     │ ┃ ║
║ ☑ grupos        ║  ║ ┗━━━━━━━━━━━━━━━━┛ ┃ │ ☑ sequências │ ┃ ║
║ ☑ slots de      ║  ║ ┏┥banco de dados┝┓ ┃ │ ☑ …          │ ┃ ║
║ ☑ replicação    ║  ║ ┃└┤template0├───┘┃ ┃ └──────────────┘ ┃ ║
║ ☑ pg_control    ║  ║ ┗━━━━━━━━━━━━━━━━┛ ┗━━━━━━━━━━━━━━━━━━┛ ║
║                 ║  ║                                         ║
╠═════════════════╝  ╚═════════════════════════════════════════╣
║                                                              ║
╠═╡pg_wal/╞══════════════════════════╗     ╔══════╡pg_tblspc/╞═╣
║ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐    ║     ║                   ║
║ │…++++│→│…++++│→│…++++│→│…++++│→…  ║     ║                   ║
║ └┤/…1├┘ └┤/…2├┘ └┤/…3├┘ └┤/…4├┘    ║     ║        │          ║
╚════════════════════════════════════╩═════╩════════╪══════════╝
                                                    │
                                                    ↓
                                                 ╔╡/…╞╗
                                                 ║    ║
                                                 ╚════╝

Todo PostgreSQL nasce com a inicialização do diretório de dados (também conhecido como datadir ou PGDATA), que hospeda a instância. Ele contém subdiretórios para cada banco de dados, assim como subdiretórios para objetos globais, arquivos de configuração, regras de autenticação, logs textuais, logs de transação e outros.

Exemplo de diretório de dados recém iniciado:

datadir
├── PG_VERSION
├── base
│   ├── 1
│   ├── 13754
│   └── 13755
├── global
│   ├── ⋮
│   ├── pg_control
│   └── pg_filenode.map
├── pg_commit_ts
├── pg_dynshmem
├── pg_hba.conf
├── pg_ident.conf
├── pg_logical
│   ├── mappings
│   ├── replorigin_checkpoint
│   └── snapshots
├── pg_multixact
│   ├── members
│   └── offsets
├── pg_notify
│   └── 0000
├── pg_replslot
├── pg_serial
├── pg_snapshots
├── pg_stat
├── pg_stat_tmp
├── pg_subtrans
│   └── 0000
├── pg_tblspc
├── pg_twophase
├── pg_wal
│   ├── 000000010000000000000001
│   └── archive_status
├── pg_xact
│   └── 0000
├── postgresql.auto.conf
├── postgresql.conf
└── postmaster.pid

Alguns dos conteúdos mais interessantes são:

Múltiplas versões e instâncias por máquina

Em alguns casos é útil, e até mesmo necessário, que uma máquina hospede mais de uma versão do PostgreSQL (binário e diretório de dados), por exemplo durante um upgrade por pg_upgrade.

Por isso, a instalação do PostgreSQL pelo repositório do PGDG usa diretórios diferenciados pela versão, tanto para os binários, quanto para os dados. Por exemplo, em CentOS o diretório de binários é /usr/pgsql-<versão>/bin e o diretório de dados é /var/lib/pgsql/<versão>/data.

Adicionalmente, também é possível instanciar mais de um PostgreSQL da mesma versão majoritária usando diretórios e portas diferentes para cada. Mas esse caso de uso é menos comum.

Debian/Ubuntu

Em Debian, o diretório de binários é /usr/lib/postgresql/<versão> e os diretórios de dados são /var/lib/postgresql/<versão>/<instância>, sendo que main é o nome padrão da instância criada automaticamente. Para ajudar a gerenciar a escolha de diretório e de portas para novas instâncias, Debian e derivados disponibilizam scripts de conveniência mais complexos, que exigem o fornecimento da versão e identificador da instância.

postgres@pg-1:~$ pg_createcluster 16 outro

CentOS/RHEL

Em CentOS, é necessário inicializar o diretório de dados, alterar a porta e duplicar o arquivo de serviço.

Primeiro, inicializando um outro diretório de dados:

[postgres@pg-1 ~]$ /usr/pgsql-16/bin/initdb -D /var/lib/pgsql/16/outro

Então alterando a porta de /var/lib/pgsql/16/outro/postgresql.conf.

Duplicando o arquivo de serviço e apontando para outro diretório:

[root@pg-1 ~]$ cp /usr/lib/systemd/system/postgresql-16.service /etc/systemd/system/postgresql-16-outro.service
[root@pg-1 ~]$ systemctl daemon-reload
[root@pg-1 ~]$ systemctl set-property postgresql-16-outro.service Environment=PGDATA=/var/lib/pgsql/16/outro

Prática

O comando usado para inicializar a instância é o initdb. Como o conteúdo do diretório tem arquivos com estruturas específicas da versão majoritária, é vital usar o initdb da mesma versão que o servidor. Portanto, esse executável, assim como outros de nível de servidor, costuma ser encontrado em um diretório versionado.

Além do initdb, algumas distribuições disponibilizam scripts de conveniência que primeiro inicializam a instância e então iniciam ou habilitam o respectivo serviço do PostgreSQL.

CentOS/RHEL

Inicialização pelo script de conveniência, como root:

[root@pg-1 ~]# /usr/pgsql-16/bin/postgresql-16-setup initdb

Inicialização pelo initdb, como postgres:

[postgres@pg-1 ~]$ /usr/pgsql-16/bin/initdb -D /var/lib/pgsql/16/data

Debian/Ubuntu

Inicialização pelo script de conveniência, como root ou postgres:

postgres@pg-1:~$ pg_createcluster 16 main

Inicialização pelo initdb, como postgres:

postgres@pg-1:~$ /usr/lib/postgresql/16/initdb -D /var/lib/postgresql/16/main

ATENÇÃO: O script de conveniência irá criar o diretório de dados em /var/lib/postgresql/<versão>/<instância> mas com os arquivos de configuração em /etc/postgresql/<versão>/<instância>. Isso tem a intenção de separar dados em /var e configurações em /etc, mas dificulta algumas tarefas posteriores, como backup e replicação.