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
(oupostmaster
em 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_buffers
para 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_commit
estiver 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.