postgresql postgres checkpoint checkpointer bgwriter
Na ciência da computação, a hierarquia de memória é uma representação dos vários meios de armazenamento em função da velocidade de acesso, custo, volume disponível e volatilidade. É desenhada como uma pirâmide, com memórias mais rápidas no topo, memória principal no centro e memórias secundárias e terciárias na base.
- As camadas superiores são registradores e cache de processador (L1I, L1D, L2…), que são relevantes para o desenvolvimento do PostgreSQL mas não necessariamente para a administração dele.
- A seguir vem a camada de memória principal (RAM), onde os processos do PostgreSQL residem enquanto estão em execução. Ela também é usada para buffers e cache de disco, cuja gestão é o assunto central deste tópico.
- Abaixo dela está a camada de memória secundária (ou de disco ou de storage), normalmente apoiada sobre SSDs e HDDs, possivelmente em tiering. Nela, os diretórios de dados e de tablespaces armazenam os objetos (tabelas, índices…), representados como séries de blocos (de 8kB por padrão no PostgreSQL).
- Por fim, o armazenamento terciário contém dados de grande volume e baixo acesso, como backups, arquivamento de WAL e possivelmente dumps. Portanto, costuma ser feito sobre fitas e outras tecnologias de baixo custo e longa duração.
┌───┐
┌─┴─┬─┴─┐
(1) │L1I│L1D│
┌─┴───┴───┴─┐
│ L2 │
┌─┴───────────┴─┐
│ L3 │
┌═─═┴═─═─═─═─═─═─═─═┴═─═┐
║ RAM ║
│ │
║ ╔════════════╗ ║
(2) │ ║ PostgreSQL ║ │
║ ╚════════════╝ ║
│ │
║ ║
┌━─━─━─━─━┴═━═━═━═━═━═━═━═━═━═━═━═┴━─━─━─━─━┐
┃ Disco ┃
│ │
┃ Tabelas e Índices WAL ┃
│ ┏━┓┏━┓┏━┓┏━┓┏━┓┏━┓┏━┓┏━┓ ┌─────────┐ │
┃ ┣━┫┣━┫┗━┛┣━┫┣━┫┣━┫┣━┫┣━┫ │┏━┓┏━┓┏━┓│ ┃
(3) │ ┣━┫┗━┛┏━┓┣━┫┣━┫┣━┫┣━┫┗━┛ │┗━┛┗━┛┗━┛│ │
┃ ┣━┫┏━┓┗━┛┣━┫┗━┛┣━┫┗━┛┏━┓ └┤/…00012├┘ ┃
│ ┣━┫┣━┫┏━┓┣━┫┏━┓┗━┛┏━┓┗━┛ ┌─────────┐ │
┃ ┣━┫┣━┫┣━┫┗━┛┣━┫┏━┓┗━┛┏━┓ │┏━┓┏━┓┏━┓│ ┃
│ ┣━┫┣━┫┣━┫┏━┓┣━┫┣━┫┏━┓┣━┫ │┗━┛┗━┛┗━┛│ │
┃ ┗━┛┗━┛┗━┛┗━┛┗━┛┗━┛┗━┛┗━┛ └┤/…00013├┘ ┃
┏━━━━━━━━━━━━━━━┴━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━┴━━━━━━━━━━━━━━━┓
┃ Arquivamento contínuo ┃
┃ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┃
┃ │┏━┓┏━┓┏━┓│ │┏━┓┏━┓┏━┓│ │┏━┓┏━┓┏━┓│ │┏━┓┏━┓┏━┓│ │┏━┓┏━┓┏━┓│ │┏━┓┏━┓┏━┓│ ┃
┃ →│┗━┛┗━┛┗━┛│→│┗━┛┗━┛┗━┛│→│┗━┛┗━┛┗━┛│→│┗━┛┗━┛┗━┛│→│┗━┛┗━┛┗━┛│→│┗━┛┗━┛┗━┛│→ ┃
┃ └┤/…00007├┘ └┤/…00008├┘ └┤/…00009├┘ └┤/…00010├┘ └┤/…00011├┘ └┤/…00012├┘ ┃
┠──────↑────────↑──────↑────────↑───────────↑────────↑─────────↑────────↑───┨
(4) ┃ Backups ┃
┃ ╔═══════════════╗ ╔═══════════════╗ ╔═══════════════╗ ╔═══════════════╗ ┃
┃ ╠═════╗ ╔═════╣ ╠═════╗ ╔═════╣ ╠═════╗ ╔═════╣ ╠═════╗ ╔═════╣ ┃
┃ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ┃
┃……╠═════╝ ╚═════╣…╠═════╝ ╚═════╣…╠═════╝ ╚═════╣…╠═════╝ ╚═════╣……┃
┃ ╠══════════╗ ║ ╠══════════╗ ║ ╠══════════╗ ║ ╠══════════╗ ║ ┃
┃ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ┃
┃ ╚══════════╩════╝ ╚══════════╩════╝ ╚══════════╩════╝ ╚══════════╩════╝ ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
Dentro da memória principal, o PostgreSQL ocupa algumas áreas distintas. Além dele, outros processos em execução na mesma máquina também usam memória, o que pode diminuir a quantidade de memória disponível direta ou indiretamente para o PostgreSQL. Adicionalmente, o próprio kernel toma proveito de toda memória não usada pelos processos para agilizar operações em disco através de estratégias como readahead, cache e buffers.
- Se a aplicação reside na mesma máquina do PostgreSQL, ela compete pela memória e pode causar problemas de contenção, portanto é desejável que ela esteja em máquinas distintas.
-
O
postgres(oupostmasterem CentOS antes do PG 16), processo principal do PostgreSQL, é responsável por alocar uma região de memória única e compartilhada entre todos os processos, configurada porshared_buffers. - Essa região é usada para comunicação inter-processos, para páginas de cache de leitura de disco e para páginas de buffers de escrita em disco.
- Alguns processos do PostgreSQL não precisam de memória adicional, operando quase que completamente sobre a memória compartilhada.
-
Outros processos podem precisar de memória extra (configurada por
autovacuum_work_mem,maintenance_work_mem, entre outras). - Conexões externas executando comandos utilitários de manutenção, como o VACUUM, podem alocar memória específica para essas operações.
-
Conexões externas executando comandos simples podem não alocar memória ou
alocar poucas vezes o valor de
work_mem. -
Conexões externas executando comandos complexos podem alocar várias vezes o
valor de
work_mem. -
Como o PostgreSQL opera sobre os blocos de disco através das primitivas de
I/O com buffers do sistema operacional, os blocos de disco (A), (B), (C) são
mantidos tanto em disco, quanto em
page cache do kernel e em
shared_bufferspara uso dos processos do PostgreSQL. O WAL também recebe cópias deles à medida que as mudanças são geradas pelas transações.
╔═══════════╗ ┌═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═┐
║ Aplicação ║ ║ (2)╔══╡shared_buffers╞══╗ ║
╚═══════════╝ │ ╔╡postgres╞═══════════════╗ ║ (3) ║ (4)╔╡checkpointer╞╗ │
(1)│││ VACUUM ║ ║ ╔══════════════════════╗║(6) ║ ┏━━━┓ ┏━━━┓ ╠═══════════════════╩══════════════╝ ║
││└──────────│─→║→║ maintenance_work_mem ║╠═══════╣ ┃ ┃ ┃(C)┃ ║ ╔╡background writer╞╗ │
││ ║ ║ ╚══════════════════════╝║ ║ ┗━━━┛ ┗━━━┛ ╠══════════════╩═══════════════════╝ ║
││ │ ╚═════════════════════════╝ ║ ┏━━━┓ ┏━━━┓ ║ ╔╡walwriter╞╗ │
││ ║ ╔╡postgres╞═══╗ ║ ┃(A)┃ ┃ ┃ ╠══════════════════════╩═══════════╝ ║
││ SELECT │ ║ ╔══════════╗║(7) ║ ┗━━━┛ ┗━━━┛ ║ ╔╡autovacuum launcher╞╗ │
│└───────────║─→║→║ work_mem ║╠═══════════════════╣ ┏━━━┓ ┏━━━┓ ╠════════════╩═════════════════════╝ ║
│ │ ║ ╚══════════╝║ ║ ┃ ┃ ┃(B)┃ ║ ╔════════════╡autovacuum╞╗ │ │
│ ║ ╚═════════════╝ ║ ┗━━━┛ ┗━━━┛ ║ (5)║╔═════════════════════╗ ║ │ ║
│ │ ╔╡postgres╞═════════╗ ║ ┏━━━┓ ┏━━━┓ ╠═══════╣║ autovacuum_work_mem ║←║←┘ │
│ SELECT ║ ║ ╔══════════╗ ║(8) ║ ┃ ┃ ┃ ┃ ║ ║╚═════════════════════╝ ║ ║
└────────────│─→║→║ work_mem ║╗ ╠═════════════╣ ┗━━━┛ ┗━━━┛ ║ ╚════════════════════════╝ │
║ ║ ╚══════════╝║╗ ║ ╚════════════════════╝ ║
│ ║ ╚══════════╝║╗ ║ │
║ ║ ╚══════════╝║╗ ║ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ║
│ ║ ╚══════════╝║╗ ║ ┃ ┃ ┃(A)┃ ┃ ┃ ┃(C)┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ │
║ ║ ╚══════════╝║ ║ (9)┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ║
│ ║ ╚══════════╝ ║ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ │
║ ╚═══════════════════╝ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃(B)┃ ┃ ┃ ┃ ┃ ║
│ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ │
║ ║
┌━─━─━─━─━─━─━─━─━┴═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═┴━─━─━─━─━─━─━─━─━┐
┃ ┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓ ┃
│ ┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃(C)┃┃ ┃┃ ┃┃ ┃┃ ┃ │
┃ ┣━━━┫┣━━━┫┣━━━┫┗━━━┛┣━━━┫┣━━━┫┣━━━┫┗━━━┛┣━━━┫┣━━━┫┗━━━┛ ┃
│ ┃ ┃┃ ┃┃ ┃┏━━━┓┃ ┃┃ ┃┃ ┃┏━━━┓┃ ┃┃(A)┃┏━━━┓ ┌─────────────────────────┐┌─────────────────────────┐ │
┃ ┣━━━┫┣━━━┫┗━━━┛┃ ┃┗━━━┛┣━━━┫┣━━━┫┃ ┃┣━━━┫┣━━━┫┃ ┃ │┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓││┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓│ ┃
│ ┃ ┃┃ ┃┏━━━┓┗━━━┛┏━━━┓┃ ┃┃ ┃┣━━━┫┃ ┃┃ ┃┣━━━┫ │┃ ┃┃(A)┃┃ ┃┃(B)┃┃ ┃││┃(C)┃┃(B)┃┃ ┃┃(A)┃┃ ┃│ │
┃ ┣━━━┫┗━━━┛┃ ┃ ┃(B)┃┣━━━┫┣━━━┫┃ ┃┣━━━┫┗━━━┛┃ ┃ │┗━━━┛┗━━━┛┗━━━┛┗━━━┛┗━━━┛││┗━━━┛┗━━━┛┗━━━┛┗━━━┛┗━━━┛│ ┃
│ ┃ ┃ ┣━━━┫ ┗━━━┛┃ ┃┃ ┃┣━━━┫┃ ┃┏━━━┓┗━━━┛ └───────┤/…000012├────────┘└───────┤/…000013├────────┘ │
┃ ┗━━━┛ ┃ ┃ ┣━━━┫┗━━━┛┃ ┃┗━━━┛┃ ┃┏━━━┓ ↑ ┃
│ ┗━━━┛ ┃ ┃ ┗━━━┛ ┗━━━┛┃ ┃ └─────────────────┤pg_control│ │
┃ ┗━━━┛ ┗━━━┛ ┃
└━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━┘
Alguns pontos de atenção:
- Consultas mais complexas consomem mais memória por processo/conexão/sessão/transação.
- Mais memória consumida por processo implica menos conexões concomitantes e possivelmente thrashing e contenção de memória.
- Mais memória consumida por processo implica menos memória para page cache.
- Menos memória para page cache implica mais leituras em disco para volumetrias grandes.
- Consultas mais simples consomem menos memória por processo/conexão/sessão/transação.
- Menos memória consumida por processo permite estabelecer mais conexões concomitantes.
- Mais conexões causam thrashing, contenção e desperdício de diversos recursos.
- Aplicação envia consulta ao backend do PostgreSQL e aguarda resposta.
-
O backend do PostgreSQL executa consulta que precisa de dados (A). Esses
dados são buscados nas páginas (cópias em memória principal dos blocos de
disco) presentes em
shared_buffers. -
Se uma página não está presente em
shared_buffers, o PostgreSQL requisita uma cópia de page cache do sistema operacional. Mas se estiver presente, o backend a usa diretamente. -
Se a página requisitada não está presente em page cache do sistema
operacional, o bloco é lido do disco. Mas se estiver presente, o sistema
operacional faz a cópia para uma posição livre em
shared_buffers. - Blocos de disco são as unidades básicas de operações de I/O. O tamanho padrão no bloco para o PostgreSQL é 8kB (não configurável, exceto em tempo de compilação). Cada objeto (tabela, índice…) pode ser representado por zero, um ou mais arquivos no sistema de arquivos; e cada arquivo é composto por uma sequência de zero, um ou mais blocos (até um limite de 1GB por arquivo).
╔═══════════╗ ┌═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═┐
║ Aplicação ║ ║ ╔══╡shared_buffers╞══╗ ║
╚═══════════╝ │ ╔╡postgres╞═══════════════╗ ║ ║ ╔╡checkpointer╞╗ │
│││ VACUUM ║ ║ ╔══════════════════════╗║ ║ ┏━━━┓ ┏━━━┓ ╠═══════════════════╩══════════════╝ ║
││└──────────│─→║→║ maintenance_work_mem ║╠═══════╣ ┃ ┃ ┃ ┃ ║ ╔╡background writer╞╗ │
││ ║ ║ ╚══════════════════════╝║ ║ ┗━━━┛ ┗━━━┛ ╠══════════════╩═══════════════════╝ ║
││ │ ╚═════════════════════════╝ ║ ┏━━━┓ ┏━━━┓ ║ ╔╡walwriter╞╗ │
││ (1) ║ ╔╡postgres╞═══╗ ║ ┃(?)┃ ┃ ┃ ╠══════════════════════╩═══════════╝ ║
││ SELECT │ ║ ╔══════════╗║(2) ║ (3)┗━━━┛ ┗━━━┛ ║ ╔╡autovacuum launcher╞╗ │
│└───────────║─→║→║ work_mem ║╠═══════════════════╣ ┏━━━┓ ┏━━━┓ ╠════════════╩═════════════════════╝ ║
│ │ ║ ╚══════════╝║ ║ ┃ ┃ ┃ ┃ ║ ╔════════════╡autovacuum╞╗ │ │
│ ║ ╚═════════════╝ ║ ┗━━━┛ ┗━━━┛ ║ ║╔═════════════════════╗ ║ │ ║
│ │ ╔╡postgres╞═════════╗ ║ ┏━━━┓ ┏━━━┓ ╠═══════╣║ autovacuum_work_mem ║←║←┘ │
│ SELECT ║ ║ ╔══════════╗ ║ ║ ┃ ┃ ┃ ┃ ║ ║╚═════════════════════╝ ║ ║
└────────────│─→║→║ work_mem ║╗ ╠═════════════╣ ┗━━━┛ ┗━━━┛ ║ ╚════════════════════════╝ │
║ ║ ╚══════════╝║╗ ║ ╚════════════════════╝ ║
│ ║ ╚══════════╝║╗ ║ │
║ ║ ╚══════════╝║╗ ║ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ║
│ ║ ╚══════════╝║╗ ║ (4)┃ ┃ ┃(?)┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ │
║ ║ ╚══════════╝║ ║ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ║
│ ║ ╚══════════╝ ║ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ │
║ ╚═══════════════════╝ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ║
│ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ │
║ ║
┌━─━─━─━─━─━─━─━─━┴═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═┴━─━─━─━─━─━─━─━─━┐
┃ ┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓ ┃
│ ┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃ │
┃ ┣━━━┫┣━━━┫┣━━━┫┗━━━┛┣━━━┫┣━━━┫┣━━━┫┗━━━┛┣━━━┫┣━━━┫┗━━━┛(5) ┃
│ ┃ ┃┃ ┃┃ ┃┏━━━┓┃ ┃┃ ┃┃ ┃┏━━━┓┃ ┃┃(A)┃┏━━━┓ ┌─────────────────────────┐┌─────────────────────────┐ │
┃ ┣━━━┫┣━━━┫┗━━━┛┃ ┃┗━━━┛┣━━━┫┣━━━┫┃ ┃┣━━━┫┣━━━┫┃ ┃ │┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓││┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓│ ┃
│ ┃ ┃┃ ┃┏━━━┓┗━━━┛┏━━━┓┃ ┃┃ ┃┣━━━┫┃ ┃┃ ┃┣━━━┫ │┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃││┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃│ │
┃ ┣━━━┫┗━━━┛┃ ┃ ┃ ┃┣━━━┫┣━━━┫┃ ┃┣━━━┫┗━━━┛┃ ┃ │┗━━━┛┗━━━┛┗━━━┛┗━━━┛┗━━━┛││┗━━━┛┗━━━┛┗━━━┛┗━━━┛┗━━━┛│ ┃
│ ┃ ┃ ┣━━━┫ ┗━━━┛┃ ┃┃ ┃┣━━━┫┃ ┃┏━━━┓┗━━━┛ └───────┤/…000012├────────┘└───────┤/…000013├────────┘ │
┃ ┗━━━┛ ┃ ┃ ┣━━━┫┗━━━┛┃ ┃┗━━━┛┃ ┃┏━━━┓ ↑ ┃
│ ┗━━━┛ ┃ ┃ ┗━━━┛ ┗━━━┛┃ ┃ └─────────────────┤pg_control│ │
┃ ┗━━━┛ ┗━━━┛ ┃
└━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━┘
-
Aplicação envia um comando de escrita ao backend do PostgreSQL e aguarda
resposta. Se a página não esiver em
shared_buffers, o fluxo de leitura é executado neste momento antes de continuar. -
O backend do PostgreSQL executa a operação sobre a página presente em
shared_buffers, alterando o conteúdo original (A) para o novo conteúdo (X). As possíveis alterações estão descritas em MVCC. - Obs.: A página é alterada no mesmo lugar, sem ocupar mais espaço, mas o diagrama está mostrando (A) indo para (X) para facilitar a leitura.
- O walwriter registra a página alterada (X) no WAL.
-
A aplicação eventualmente finaliza a transação com um COMMIT, que é marcado
diretamente no WAL (exceto quando
synchronous_commitestiver desabilitado).
╔═══════════╗ ┌═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═┐
║ Aplicação ║ ║ ╔══╡shared_buffers╞══╗ ║
╚═══════════╝ │ ╔╡postgres╞═══════════════╗ ║ ║ ╔╡checkpointer╞╗ │
│││ VACUUM ║ ║ ╔══════════════════════╗║ ║ ┏━━━┓ ┏━━━┓ ╠═══════════════════╩══════════════╝ ║
││└──────────│─→║→║ maintenance_work_mem ║╠═══════╣ ┃ ┃ ┃ ┃ ║ ╔╡background writer╞╗ │
││ ║ ║ ╚══════════════════════╝║ ║ ┗━━━┛ ┗━━━┛ ╠══════════════╩═══════════════════╝ ║
││ │ ╚═════════════════════════╝ ║ ┏━━━┓ ┏━━━┓ ║ ╔╡walwriter╞╗ │
││ (1) ║ ╔╡postgres╞═══╗ ║ ┃(A)┃→→┃(X)┃ ╠══════════════════════╩═══════════╝ ║
││ UPDATE │ ║ ╔══════════╗║ ║ (3)┗━━━┛ ┗━━━┛ ║ ╔╡autovacuum launcher╞╗ │
│└───────────║─→║→║ work_mem ║╠═══════════════════╣ ┏━━━┓ ┏━━━┓ ╠════════════╩═════════════════════╝ ║
│ COMMIT │ ║ ╚══════════╝║(2) ║ ┃ ┃ ┃ ┃ ║ ╔════════════╡autovacuum╞╗ │ │
│ ║ ╚═════════════╝ ║ ┗━━━┛ ┗━━━┛ ║ ║╔═════════════════════╗ ║ │ ║
│ │ ╔╡postgres╞═════════╗ ║ ┏━━━┓ ┏━━━┓ ╠═══════╣║ autovacuum_work_mem ║←║←┘ │
│ SELECT ║ ║ ╔══════════╗ ║ ║ ┃ ┃ ┃ ┃ ║ ║╚═════════════════════╝ ║ ║
└────────────│─→║→║ work_mem ║╗ ╠═════════════╣ ┗━━━┛ ┗━━━┛ ║ ╚════════════════════════╝ │
║ ║ ╚══════════╝║╗ ║ ╚════════════════════╝ ║
│ ║ ╚══════════╝║╗ ║ │
║ ║ ╚══════════╝║╗ ║ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ║
│ ║ ╚══════════╝║╗ ║ ┃ ┃ ┃(A)┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ │
║ ║ ╚══════════╝║ ║ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ║
│ ║ ╚══════════╝ ║ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ │
║ ╚═══════════════════╝ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ║
│ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ │
║ ║
┌━─━─━─━─━─━─━─━─━┴═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═┴━─━─━─━─━─━─━─━─━┐
┃ ┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓ ┃
│ ┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃ │
┃ ┣━━━┫┣━━━┫┣━━━┫┗━━━┛┣━━━┫┣━━━┫┣━━━┫┗━━━┛┣━━━┫┣━━━┫┗━━━┛ (4) (5) ┃
│ ┃ ┃┃ ┃┃ ┃┏━━━┓┃ ┃┃ ┃┃ ┃┏━━━┓┃ ┃┃(A)┃┏━━━┓ ┌─────────────────────────┐┌─────────────────────────┐ │
┃ ┣━━━┫┣━━━┫┗━━━┛┃ ┃┗━━━┛┣━━━┫┣━━━┫┃ ┃┣━━━┫┣━━━┫┃ ┃ │┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓││┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓│ ┃
│ ┃ ┃┃ ┃┏━━━┓┗━━━┛┏━━━┓┃ ┃┃ ┃┣━━━┫┃ ┃┃ ┃┣━━━┫ │┃ ┃┃(X)┃┃COM┃┃ ┃┃ ┃││┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃│ │
┃ ┣━━━┫┗━━━┛┃ ┃ ┃ ┃┣━━━┫┣━━━┫┃ ┃┣━━━┫┗━━━┛┃ ┃ │┗━━━┛┗━━━┛┗━━━┛┗━━━┛┗━━━┛││┗━━━┛┗━━━┛┗━━━┛┗━━━┛┗━━━┛│ ┃
│ ┃ ┃ ┣━━━┫ ┗━━━┛┃ ┃┃ ┃┣━━━┫┃ ┃┏━━━┓┗━━━┛ └───────┤/…000012├────────┘└───────┤/…000013├────────┘ │
┃ ┗━━━┛ ┃ ┃ ┣━━━┫┗━━━┛┃ ┃┗━━━┛┃ ┃┏━━━┓ ↑ ┃
│ ┗━━━┛ ┃ ┃ ┗━━━┛ ┗━━━┛┃ ┃ └─────────────────┤pg_control│ │
┃ ┗━━━┛ ┗━━━┛ ┃
└━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━┘
Ao final, shared_buffers contém apenas a versão nova (X) da página, que é
usada para atender novas leituras e escritas em memória. O WAL também contém
essa versão, e pode ser usado para replicação e recuperação de falhas. Mas a
tabela em disco e page cache podem conter a versão anterior (A) por tempo
indeterminado.
O fluxo de escrita normal tenta fazer todas as operações em memória principal,
transformando as operações em escritas sequenciais e dependendo de confirmação
(fsync) apenas para retornar a garantia de transação em disco
(Durabilidade).
Mas isso faz com que o estado nas tabelas (indicado pelo ponteiro de LSN de
consistência do pg_control) e o estado mais recente escrito no WAL sejam
diferentes. Essa defasagem do pg_control causa um maior tempo de recuperação
de desastres e de parada do serviço, além de outros pontos.
O checkpointer é o processo de background responsável por executar o
checkpoint, que é a ação que garante que as escritas confirmadas para a
aplicação sejam eventualmente propagadas para os objetos e, então, avança o
ponteiro do pg_control.
O checkpoint é acionado periodicamente em função de checkpoint_timeout,
quando o espaço ocupado pelo WAL em pg_wal está próximo do máximo max_wal_size
ou quando o comando CHECKPOINT é executado por um superusuário.
O primeiro passo do checkpoint é enviar as páginas de buffers sujos (ou
seja, que tiveram alterações desde que foram lidos do disco) para que o sistema
operacional faça a escrita (write) nos respectivos blocos disco. Essa escrita
vai ser feita quando o sistema operacional puder.
Para evitar sobrecarregar o I/O, as escritas são distribuídas ao longo de um
tempo proporcional ao checkpoint_timeout, configurável por
checkpoint_completion_target. Por exemplo, se temos
checkpoint_timeout = 10min e checkpoint_completion_target = 0.8,
então as escritas são dispersadas
ao longo de 8min (8min = 10min * 0.8).
Por exemplo, as páginas (X), (Y) e (Z) foram enviadas para page cache e o sistema operacional já conseguiu escrever duas (X) e (Y) em disco:
╔═══════════╗ ┌═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═┐
║ Aplicação ║ ║ ╔══╡shared_buffers╞══╗ ║
╚═══════════╝ │ ╔╡postgres╞═══════════════╗ ║ ║ ╔╡checkpointer╞╗ │
│││ VACUUM ║ ║ ╔══════════════════════╗║ ║ ┏━━━┓ ┏━━━┓ ╠═══════════════════╩══════════════╝ ║
││└──────────│─→║→║ maintenance_work_mem ║╠═══════╣ ┃ ┃ ┃(Z)┃ ║ ╔╡background writer╞╗ │
││ ║ ║ ╚══════════════════════╝║ ║ ┗━━━┛ ┗━━━┛ ╠══════════════╩═══════════════════╝ ║
││ │ ╚═════════════════════════╝ ║ ┏━━━┓ ┏━━━┓ ║ ╔╡walwriter╞╗ │
││ (1) ║ ╔╡postgres╞═══╗ ║ ┃(X)┃ ┃ ┃ ╠══════════════════════╩═══════════╝ ║
││ UPDATE │ ║ ╔══════════╗║ ║ (3)┗━━━┛ ┗━━━┛ ║ ╔╡autovacuum launcher╞╗ │
│└───────────║─→║→║ work_mem ║╠═══════════════════╣ ┏━━━┓ ┏━━━┓ ╠════════════╩═════════════════════╝ ║
│ │ ║ ╚══════════╝║(2) ║ ┃ ┃ ┃ ┃ ║ ╔════════════╡autovacuum╞╗ │ │
│ ║ ╚═════════════╝ ║ ┗━━━┛ ┗━━━┛ ║ ║╔═════════════════════╗ ║ │ ║
│ │ ╔╡postgres╞═════════╗ ║ ┏━━━┓ ┏━━━┓ ╠═══════╣║ autovacuum_work_mem ║←║←┘ │
│ SELECT ║ ║ ╔══════════╗ ║ ║ ┃ ┃ ┃(Y)┃ ║ ║╚═════════════════════╝ ║ ║
└────────────│─→║→║ work_mem ║╗ ╠═════════════╣ ┗━━━┛ ┗━━━┛ ║ ╚════════════════════════╝ │
║ ║ ╚══════════╝║╗ ║ ╚════════════════════╝ ║
│ ║ ╚══════════╝║╗ ║ │
║ ║ ╚══════════╝║╗ ║ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ║
│ ║ ╚══════════╝║╗ ║ ┃ ┃ ┃(X)┃ ┃ ┃ ┃(Z)┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ │
║ ║ ╚══════════╝║ ║ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ║
│ ║ ╚══════════╝ ║ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ │
║ ╚═══════════════════╝ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃(Y)┃ ┃ ┃ ┃ ┃ ║
│ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ │
║ ║
┌━─━─━─━─━─━─━─━─━┴═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═┴━─━─━─━─━─━─━─━─━┐
┃ ┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓ ┃
│ ┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃(C)┃┃ ┃┃ ┃┃ ┃┃ ┃ │
┃ ┣━━━┫┣━━━┫┣━━━┫┗━━━┛┣━━━┫┣━━━┫┣━━━┫┗━━━┛┣━━━┫┣━━━┫┗━━━┛ ┃
│ ┃ ┃┃ ┃┃ ┃┏━━━┓┃ ┃┃ ┃┃ ┃┏━━━┓┃ ┃┃(X)┃┏━━━┓ ┌─────────────────────────┐┌─────────────────────────┐ │
┃ ┣━━━┫┣━━━┫┗━━━┛┃ ┃┗━━━┛┣━━━┫┣━━━┫┃ ┃┣━━━┫┣━━━┫┃ ┃ │┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓││┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓│ ┃
│ ┃ ┃┃ ┃┏━━━┓┗━━━┛┏━━━┓┃ ┃┃ ┃┣━━━┫┃ ┃┃ ┃┣━━━┫ │┃ ┃┃(X)┃┃COM┃┃(Y)┃┃COM┃││┃(Z)┃┃(Y)┃┃COM┃┃(X)┃┃ ┃│ │
┃ ┣━━━┫┗━━━┛┃ ┃ ┃(Y)┃┣━━━┫┣━━━┫┃ ┃┣━━━┫┗━━━┛┃ ┃ │┗━━━┛┗━━━┛┗━━━┛┗━━━┛┗━━━┛││┗━━━┛┗━━━┛┗━━━┛┗━━━┛┗━━━┛│ ┃
│ ┃ ┃ ┣━━━┫ ┗━━━┛┃ ┃┃ ┃┣━━━┫┃ ┃┏━━━┓┗━━━┛ └───────┤/…000012├────────┘└───────┤/…000013├────────┘ │
┃ ┗━━━┛ ┃ ┃ ┣━━━┫┗━━━┛┃ ┃┗━━━┛┃ ┃┏━━━┓ ↑ ┃
│ ┗━━━┛ ┃ ┃ ┗━━━┛ ┗━━━┛┃ ┃ └─────────────────┤pg_control│ │
┃ ┗━━━┛ ┗━━━┛ ┃
└━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━┘
O segundo passo é pedir a confirmação (sync) ao sistema operacional das
escritas enviadas anteriormente. As escritas que não tiverem sido feitas até
este momento serão feitas. E o sistema operacional irá pedir a confirmação de
todas as escritas para a camada inferior (controlador de RAID, storage etc).
╔═══════════╗ ┌═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═┐
║ Aplicação ║ ║ ╔══╡shared_buffers╞══╗ ║
╚═══════════╝ │ ╔╡postgres╞═══════════════╗ ║ ║ ╔╡checkpointer╞╗ │
│││ VACUUM ║ ║ ╔══════════════════════╗║ ║ ┏━━━┓ ┏━━━┓ ╠═══════════════════╩══════════════╝ ║
││└──────────│─→║→║ maintenance_work_mem ║╠═══════╣ ┃ ┃ ┃(Z)┃ ║ ╔╡background writer╞╗ │
││ ║ ║ ╚══════════════════════╝║ ║ ┗━━━┛ ┗━━━┛ ╠══════════════╩═══════════════════╝ ║
││ │ ╚═════════════════════════╝ ║ ┏━━━┓ ┏━━━┓ ║ ╔╡walwriter╞╗ │
││ (1) ║ ╔╡postgres╞═══╗ ║ ┃(X)┃ ┃ ┃ ╠══════════════════════╩═══════════╝ ║
││ UPDATE │ ║ ╔══════════╗║ ║ (3)┗━━━┛ ┗━━━┛ ║ ╔╡autovacuum launcher╞╗ │
│└───────────║─→║→║ work_mem ║╠═══════════════════╣ ┏━━━┓ ┏━━━┓ ╠════════════╩═════════════════════╝ ║
│ │ ║ ╚══════════╝║(2) ║ ┃ ┃ ┃ ┃ ║ ╔════════════╡autovacuum╞╗ │ │
│ ║ ╚═════════════╝ ║ ┗━━━┛ ┗━━━┛ ║ ║╔═════════════════════╗ ║ │ ║
│ │ ╔╡postgres╞═════════╗ ║ ┏━━━┓ ┏━━━┓ ╠═══════╣║ autovacuum_work_mem ║←║←┘ │
│ SELECT ║ ║ ╔══════════╗ ║ ║ ┃ ┃ ┃(Y)┃ ║ ║╚═════════════════════╝ ║ ║
└────────────│─→║→║ work_mem ║╗ ╠═════════════╣ ┗━━━┛ ┗━━━┛ ║ ╚════════════════════════╝ │
║ ║ ╚══════════╝║╗ ║ ╚════════════════════╝ ║
│ ║ ╚══════════╝║╗ ║ │
║ ║ ╚══════════╝║╗ ║ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ║
│ ║ ╚══════════╝║╗ ║ ┃ ┃ ┃(X)┃ ┃ ┃ ┃(Z)┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ │
║ ║ ╚══════════╝║ ║ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ║
│ ║ ╚══════════╝ ║ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ │
║ ╚═══════════════════╝ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃(Y)┃ ┃ ┃ ┃ ┃ ║
│ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ │
║ ║
┌━─━─━─━─━─━─━─━─━┴═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═┴━─━─━─━─━─━─━─━─━┐
┃ ┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓ ┃
│ ┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃(Z)┃┃ ┃┃ ┃┃ ┃┃ ┃ │
┃ ┣━━━┫┣━━━┫┣━━━┫┗━━━┛┣━━━┫┣━━━┫┣━━━┫┗━━━┛┣━━━┫┣━━━┫┗━━━┛ ┃
│ ┃ ┃┃ ┃┃ ┃┏━━━┓┃ ┃┃ ┃┃ ┃┏━━━┓┃ ┃┃(X)┃┏━━━┓ ┌─────────────────────────┐┌─────────────────────────┐ │
┃ ┣━━━┫┣━━━┫┗━━━┛┃ ┃┗━━━┛┣━━━┫┣━━━┫┃ ┃┣━━━┫┣━━━┫┃ ┃ │┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓││┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓│ ┃
│ ┃ ┃┃ ┃┏━━━┓┗━━━┛┏━━━┓┃ ┃┃ ┃┣━━━┫┃ ┃┃ ┃┣━━━┫ │┃ ┃┃(X)┃┃COM┃┃(Y)┃┃COM┃││┃(Z)┃┃(Y)┃┃COM┃┃(X)┃┃ ┃│ │
┃ ┣━━━┫┗━━━┛┃ ┃ ┃(Y)┃┣━━━┫┣━━━┫┃ ┃┣━━━┫┗━━━┛┃ ┃ │┗━━━┛┗━━━┛┗━━━┛┗━━━┛┗━━━┛││┗━━━┛┗━━━┛┗━━━┛┗━━━┛┗━━━┛│ ┃
│ ┃ ┃ ┣━━━┫ ┗━━━┛┃ ┃┃ ┃┣━━━┫┃ ┃┏━━━┓┗━━━┛ └───────┤/…000012├────────┘└───────┤/…000013├────────┘ │
┃ ┗━━━┛ ┃ ┃ ┣━━━┫┗━━━┛┃ ┃┗━━━┛┃ ┃┏━━━┓ ↑ ┃
│ ┗━━━┛ ┃ ┃ ┗━━━┛ ┗━━━┛┃ ┃ └─────────────────┤pg_control│ │
┃ ┗━━━┛ ┗━━━┛ ┃
└━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━┘
Por fim, o ponteiro de consistência contido em pg_control é avançado para o
novo estado consistente alcançado. A partir desse momento, segmentos de WAL
do passado podem ser reciclados.
╔═══════════╗ ┌═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═─═┐
║ Aplicação ║ ║ ╔══╡shared_buffers╞══╗ ║
╚═══════════╝ │ ╔╡postgres╞═══════════════╗ ║ ║ ╔╡checkpointer╞╗ │
│││ VACUUM ║ ║ ╔══════════════════════╗║ ║ ┏━━━┓ ┏━━━┓ ╠═══════════════════╩══════════════╝ ║
││└──────────│─→║→║ maintenance_work_mem ║╠═══════╣ ┃ ┃ ┃(Z)┃ ║ ╔╡background writer╞╗ │
││ ║ ║ ╚══════════════════════╝║ ║ ┗━━━┛ ┗━━━┛ ╠══════════════╩═══════════════════╝ ║
││ │ ╚═════════════════════════╝ ║ ┏━━━┓ ┏━━━┓ ║ ╔╡walwriter╞╗ │
││ (1) ║ ╔╡postgres╞═══╗ ║ ┃(X)┃ ┃ ┃ ╠══════════════════════╩═══════════╝ ║
││ UPDATE │ ║ ╔══════════╗║ ║ (3)┗━━━┛ ┗━━━┛ ║ ╔╡autovacuum launcher╞╗ │
│└───────────║─→║→║ work_mem ║╠═══════════════════╣ ┏━━━┓ ┏━━━┓ ╠════════════╩═════════════════════╝ ║
│ │ ║ ╚══════════╝║(2) ║ ┃ ┃ ┃ ┃ ║ ╔════════════╡autovacuum╞╗ │ │
│ ║ ╚═════════════╝ ║ ┗━━━┛ ┗━━━┛ ║ ║╔═════════════════════╗ ║ │ ║
│ │ ╔╡postgres╞═════════╗ ║ ┏━━━┓ ┏━━━┓ ╠═══════╣║ autovacuum_work_mem ║←║←┘ │
│ SELECT ║ ║ ╔══════════╗ ║ ║ ┃ ┃ ┃(Y)┃ ║ ║╚═════════════════════╝ ║ ║
└────────────│─→║→║ work_mem ║╗ ╠═════════════╣ ┗━━━┛ ┗━━━┛ ║ ╚════════════════════════╝ │
║ ║ ╚══════════╝║╗ ║ ╚════════════════════╝ ║
│ ║ ╚══════════╝║╗ ║ │
║ ║ ╚══════════╝║╗ ║ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ║
│ ║ ╚══════════╝║╗ ║ ┃ ┃ ┃(X)┃ ┃ ┃ ┃(Z)┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ │
║ ║ ╚══════════╝║ ║ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ║
│ ║ ╚══════════╝ ║ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ ┏━━━┓ │
║ ╚═══════════════════╝ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃(Y)┃ ┃ ┃ ┃ ┃ ║
│ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ ┗━━━┛ │
║ ║
┌━─━─━─━─━─━─━─━─━┴═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═━═┴━─━─━─━─━─━─━─━─━┐
┃ ┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓ ┃
│ ┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃ ┃┃(Z)┃┃ ┃┃ ┃┃ ┃┃ ┃ │
┃ ┣━━━┫┣━━━┫┣━━━┫┗━━━┛┣━━━┫┣━━━┫┣━━━┫┗━━━┛┣━━━┫┣━━━┫┗━━━┛ ┃
│ ┃ ┃┃ ┃┃ ┃┏━━━┓┃ ┃┃ ┃┃ ┃┏━━━┓┃ ┃┃(X)┃┏━━━┓ ┌─────────────────────────┐┌─────────────────────────┐ │
┃ ┣━━━┫┣━━━┫┗━━━┛┃ ┃┗━━━┛┣━━━┫┣━━━┫┃ ┃┣━━━┫┣━━━┫┃ ┃ │┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓││┏━━━┓┏━━━┓┏━━━┓┏━━━┓┏━━━┓│ ┃
│ ┃ ┃┃ ┃┏━━━┓┗━━━┛┏━━━┓┃ ┃┃ ┃┣━━━┫┃ ┃┃ ┃┣━━━┫ │┃ ┃┃(X)┃┃COM┃┃(Y)┃┃COM┃││┃(Z)┃┃(Y)┃┃COM┃┃(X)┃┃ ┃│ │
┃ ┣━━━┫┗━━━┛┃ ┃ ┃(Y)┃┣━━━┫┣━━━┫┃ ┃┣━━━┫┗━━━┛┃ ┃ │┗━━━┛┗━━━┛┗━━━┛┗━━━┛┗━━━┛││┗━━━┛┗━━━┛┗━━━┛┗━━━┛┗━━━┛│ ┃
│ ┃ ┃ ┣━━━┫ ┗━━━┛┃ ┃┃ ┃┣━━━┫┃ ┃┏━━━┓┗━━━┛ └───────┤/…000012├────────┘└───────┤/…000013├────────┘ │
┃ ┗━━━┛ ┃ ┃ ┣━━━┫┗━━━┛┃ ┃┗━━━┛┃ ┃┏━━━┓ ↑ ┃
│ ┗━━━┛ ┃ ┃ ┗━━━┛ ┗━━━┛┃ ┃ │pg_control├───────┘ │
┃ ┗━━━┛ ┗━━━┛ ┃
└━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━─━┘
Nos fluxos de leitura e escrita, quando um bloco precisa ser buscado do disco e
copiado para memória principal, ao menos uma página deve estar disponível em
shared_buffers. Caso contrário, se todas as páginas de shared_buffers
estiverem ocupadas e sujas (ou seja, com alterações que não foram escritas em
disco), então o backend que está fazendo a leitura ou escrita deve primeiro
escolher uma página suja e escrevê-la em disco antes de carregar o novo bloco de
interesse. Ou seja, no melhor caso a leitura e escrita são feitas em memória
principal pois operam sobre shared_buffers, mas no pior caso a resposta de
leituras e escritas pode depender da velocidade de escrita aleatória em disco.
O backgroud writer (ou bgwriter) é um processo interno responsável por
encontrar páginas sujas de shared_buffers e escrevê-las em disco, liberando
espaço para que outros backends possam trabalhar com maior eficiência. O fato
de menos páginas serem mantidas sujas em memória significa que o checkpoint
pode ser mais barato já que a escrita e confirmação delas pode ter terminado
antes; mas isso não acontece em casos que as mesmas páginas são sujas
repetidamente.
Quando o bgwriter executa, ele tenta limpar uma quantidade de páginas
proporcionais ao número de páginas que foram sujas recentemente, multiplicadas
por bwriter_lru_multiplier, mas não mais que bgwriter_lru_maxpages. As
páginas escolhidas são aquelas usadas menos recentemente
(LRU).
Depois de executar ele aguarda o tempo bgwriter_delay até ser acionado
novamente.