- O PostgreSQL 18 combina a estratégia de cópia de arquivos (FILE_COPY) com recursos de clonagem do sistema de arquivos para clonar bancos de dados quase instantaneamente
- Com a nova configuração
file_copy_method = clone, é possível aproveitar o recurso de clonagem (FICLONE) de sistemas de arquivos modernos como XFS, ZFS e APFS
- Nos benchmarks, ao clonar um banco de dados de 6 GB, o método tradicional WAL_LOG levou cerca de 67 segundos, enquanto o método com clone caiu para cerca de 0,2 segundo
- O banco de dados clonado inicialmente compartilha os mesmos blocos físicos, mas em operações de escrita ocorre a separação via copy-on-write
- Porém, a clonagem só é possível quando não há conexões ativas e há a limitação de funcionar apenas dentro de um único sistema de arquivos
Estrutura de clonagem baseada em template no PostgreSQL
- No PostgreSQL, ao executar o comando
CREATE DATABASE dbname, internamente o sistema clona o banco de dados template1 para criar o novo banco
- Isso equivale a
CREATE DATABASE dbname TEMPLATE template1
- Em vez de
template1, é possível especificar outro banco de dados, permitindo clonagem com templates personalizados
- No PostgreSQL 18, esse sistema de templates foi expandido para uma estrutura de clonagem instantânea
CREATE DATABASE ... STRATEGY
- Desde o PostgreSQL 15, foi introduzido o parâmetro
CREATE DATABASE ... STRATEGY, permitindo escolher o método de clonagem
- O padrão é
WAL_LOG, que faz clonagem em nível de bloco por meio de Write-Ahead Log
- Esse método reduz a carga de I/O e melhora o suporte à concorrência, mas é lento em clonagens de grande volume
- Ao especificar
STRATEGY=FILE_COPY, é possível voltar ao método tradicional de cópia de arquivos, e no PostgreSQL 18 foi adicionada uma nova opção de clonagem com base nisso
FILE_COPY e file_copy_method
- A configuração
file_copy_method do PostgreSQL 18 controla o método de cópia de arquivos no nível do sistema operacional
- O valor padrão é
copy, que lê todos os bytes e grava em um novo local
- Ao mudar para
clone, o PostgreSQL usa o recurso de clonagem do sistema de arquivos (FICLONE), permitindo clonagem instantânea sem consumo adicional de espaço
- Sistemas de arquivos compatíveis: XFS, ZFS, APFS e ZFS no FreeBSD
- Procedimento de configuração
- Montar o cluster PostgreSQL sobre um sistema de arquivos compatível
- Definir
file_copy_method = clone e recarregar a configuração
Resultados de benchmark
- Após criar um banco de testes de cerca de 6 GB (
source_db), foram comparados dois métodos
- Método
WAL_LOG: 67.000 ms (cerca de 67 segundos)
- Método
FILE_COPY + clone: 212 ms
- Com o mesmo volume de dados, foi observada uma melhora de velocidade de mais de 300 vezes
- O banco clonado (
fast_clone) quase não consome espaço adicional em disco
Como os dados clonados funcionam
- Ao usar
file_copy_method = clone, apenas os metadados do sistema de arquivos são clonados, e os dois bancos passam a compartilhar os mesmos blocos físicos
- O tamanho do banco de dados reportado pelo PostgreSQL continua sendo o tamanho lógico (cerca de 6 GB)
- Quando ocorrem escritas, entra em ação o copy-on-write (COW), separando as páginas afetadas
- Páginas que contêm linhas modificadas
- Páginas onde novos tuples são gravados
- Páginas de índice, FSM, visibility map etc.
- Mesmo ao executar
VACUUM, ocorre separação adicional de páginas
Verificação de blocos compartilhados no XFS
- O comando
filefrag -v permite verificar se os dois bancos compartilham os mesmos blocos físicos
- No estado inicial, todos os extents aparecem marcados como
shared
- Ao atualizar algumas linhas, os primeiros 40 blocos (cerca de 160 KB) são separados e passam a apontar para endereços físicos diferentes
- Os demais extents continuam em estado compartilhado
Cuidados e limitações
- Não pode haver conexões ativas no banco de origem durante a clonagem
- Essa é uma limitação do PostgreSQL, não um problema do sistema de arquivos
- Em ambientes de produção, é comum usar um banco de templates separado
- A clonagem só funciona dentro de um único sistema de arquivos
- Se houver vários tablespaces em pontos de montagem diferentes, o processo volta para cópia normal
- Em serviços gerenciados em nuvem (AWS RDS, Google Cloud SQL etc.), esse recurso não pode ser usado porque não há acesso ao sistema de arquivos
- Em VMs próprias ou ambientes bare metal, é possível ter controle total
Conclusão
- O recurso
file_copy_method = clone do PostgreSQL 18 usa diretamente a clonagem em nível de sistema operacional para
reduzir drasticamente o tempo de clonagem de bancos de dados grandes
- Em ambientes de teste, desenvolvimento e aprendizado, isso permite implementar workflows de banco de dados com clonagem e reset quase instantâneos
- Ainda assim, é necessário projetar a operação levando em conta a restrição de conexões ativas e a exigência de um único sistema de arquivos
1 comentários
Comentários do Hacker News
Para quem não pode esperar ou precisa de isolamento completo de instância no PG18, criei o Velo, uma ferramenta de branching instantâneo usando snapshots do ZFS
Funciona com qualquer versão do PostgreSQL, e cada branch tem contêiner e porta independentes
Pode ser criado em cerca de 2 a 5 segundos para um DB de 100 GB
A diferença em relação ao método do PG18 é que ele não compartilha uma única instância, oferecendo isolamento completo de servidor
Link do GitHub
No passado, quando a empresa migrou para RDS, construímos internamente um sistema parecido
Como problemas aconteciam com frequência durante migrações em produção, automatizamos as etapas abaixo para evitar isso
Graças a esse processo, conseguimos pegar muitos bugs específicos de produção que não apareciam localmente nem no CI
Depois automatizamos isso com um script Ruby simples, e ouvi dizer que ainda usam esse script até hoje
Só agora descobri que a estratégia de template cloning pode ser configurada
Usei o Neon para criar ambientes de integração em tempo real, e no meu projeto em Golang pgtestdb eu crio um DB Postgres com migração completa de schema aplicada para cada teste
Já vi uma startup criar DBs de staging instantâneos com btrfs, e é interessante ver ideias parecidas reaparecendo
Esse tipo de clonagem rápida e testes é uma grande vantagem do Postgres e do Sqlite, e seria ótimo se também fosse possível em Clickhouse e MySQL
Hoje em dia o PostgreSQL parece ter virado um DB coringa que cobre praticamente todos os usos de SQL
E ainda é gratuito
Fico pensando se ainda existe motivo para usar outro DB SQL
O Clickhouse é muito mais rápido para analytics, e DBs como Cassandra são vantajosos para cargas centradas em escrita
Ou seja, cada DB ainda tem seus pontos fortes
Quando os dados crescem, surgem quedas de desempenho e problemas de migração
No meu caso, o desempenho do particionamento nativo era ruim, então precisei implementar um particionamento customizado
Essa escolha traz vários impactos negativos quando a carga aumenta
É um tema tratado também neste post do blog da Uber
Mesmo assim, no ambiente de nuvem ainda confio mais no Postgres
Por isso, em implantações OLTP de grande escala, o MySQL continua sendo o mais usado (ex.: YouTube, Uber)
Usando estruturas de dados imutáveis (HAMT), dá para criar um DB com clonagem instantânea independentemente do tipo de filesystem
Eu disse isso em teoria, mas também já implementei na prática
Não entendo por que não existem mais DBs baseados em HAMT
Link para a documentação relacionada
Eu não sabia que no Postgres v15 o WAL_LOG passou a ser o padrão
Em ambientes de teste paralelos no CI, faz mais sentido voltar para a estratégia FILE_COPY
Abri uma issue sobre isso no antigo projeto integresql
Já criei uma ferramenta simples com GUI, pgtt, para testar apps baseados em Postgres localmente
Ela simplifica bastante a configuração do ambiente de desenvolvimento
Parece que ajudaria no trabalho repetitivo com migrações SQL
Li outros posts do blog e, no geral, são excelentes
Em especial, foi a primeira vez que descobri os tipos range do Postgres
Fico curioso se o MariaDB também tem algo assim
Estou quebrando a cabeça porque resetar o DB ao estado inicial a cada teste é lento
Como usamos MariaDB em produção, é difícil trocar de DB
Mesmo assim, o lado do Postgres parece melhor
Esse método é bem eficiente
A AWS também oferece um recurso parecido
Documentação de clones do Aurora
Para testes de integração, isso é pouco prático