Aula 15: ZFS avançado — snapshots, clones e replicação entre servidores

Aula 15: ZFS avançado — snapshots, clones e replicação entre servidores

Bem-vindo à Aula 15 do curso FreeBSD — Do Zero ao Avançado. Nesta etapa, você vai dominar os recursos mais poderosos do ZFS avançado: snapshots instantâneos, clones com economia de espaço e replicação de datasets entre servidores — funcionalidades que transformam o gerenciamento de dados em ambientes de produção. Se você já opera sistemas FreeBSD com ZFS no dia a dia, sabe que a capacidade de criar pontos de restauração instantâneos não é apenas uma conveniência, mas um requisito crítico para políticas de backup, recuperação de desastres e ambientes de desenvolvimento. O que muitos profissionais não exploram é o verdadeiro potencial do ZFS avançado quando combinamos snapshots incrementais com replicação nativa via rede, eliminando a necessidade de ferramentas externas como rsync ou scripts complexos de sincronização.

Em nossos projetos na JRT Technology Solutions, utilizamos diariamente snapshots automáticos para proteger ambientes críticos de bancos de dados PostgreSQL em FreeBSD, onde uma falha humana ou corrupção de dados pode ser revertida em segundos, sem impacto significativo no espaço em disco. A replicação ZFS, por sua vez, é a espinha dorsal de nossos planos de disaster recovery: sincronizamos datasets completos entre datacenters geograficamente distribuídos com compressão embutida e verificação de integridade ponta a ponta, algo que apenas o ZFS avançado oferece de forma nativa no FreeBSD. Nesta aula, você aprenderá a implementar exatamente essas soluções.

O nível desta aula é intermediário, exigindo que você já tenha concluído as aulas anteriores do curso, especialmente aquelas sobre criação de pools, datasets e propriedades básicas do ZFS. Você deve ter acesso a pelo menos um sistema FreeBSD 14.0-RELEASE ou superior com um pool ZFS funcional — e, para a seção de replicação, dois servidores conectados via rede (podem ser máquinas virtuais na mesma bridge, desde que possuam conectividade IP entre si). Não se preocupe se você não tiver dois servidores físicos: demonstraremos como simular o ambiente de replicação usando datasets locais antes de partir para a configuração remota completa via SSH.

Ao final desta aula, você será capaz de criar snapshots atômicos de qualquer dataset, gerar clones writable instantâneos para testes e desenvolvimento, configurar políticas de retenção automática de snapshots, e replicar datasets inteiros — inclusive de forma incremental — entre servidores FreeBSD usando apenas comandos nativos do ZFS. Você também aprenderá a diagnosticar e corrigir os erros mais comuns que afetam ambientes com ZFS avançado em produção, como conflitos de espaço, snapshots órfãos e falhas de replicação por incompatibilidade de versões. Prepare-se para elevar seu domínio do ZFS a um patamar profissional.

O que você vai aprender nesta aula

  • Compreender a arquitetura interna dos snapshots no ZFS e como eles diferem de snapshots em LVM ou sistemas de arquivos tradicionais
  • Criar, listar, inspecionar e destruir snapshots com precisão, incluindo snapshots recursivos em hierarquias de datasets
  • Utilizar o comando zfs rollback para restaurar datasets inteiros a estados anteriores, com e sem confirmação de perda de dados
  • Gerar clones writable a partir de snapshots, compreendendo o mecanismo de copy-on-write e a dependência pai-filho
  • Promover clones a datasets independentes, eliminando a dependência do snapshot de origem
  • Configurar replicação local e remota usando zfs send e zfs receive, incluindo envio incremental
  • Implementar replicação segura via túnel SSH com compressão e verificação de integridade
  • Automatizar políticas de snapshot com scripts shell e agendamento via cron
  • Diagnosticar e resolver os 5 erros mais frequentes em ambientes com ZFS avançado

Pré-requisitos e Ambiente

Para executar todos os procedimentos desta aula sem interrupções, você precisará dos seguintes itens:

  • Um servidor FreeBSD 14.0-RELEASE ou superior (para replicação remota, dois servidores com conectividade IP entre si)
  • Um pool ZFS existente — em nossos exemplos usaremos o pool zroot, mas você pode adaptar para qualquer pool funcional
  • Pelo menos 5 GB de espaço livre no pool para criação de datasets, snapshots e clones de teste
  • Acesso root ou privilégios sudo configurados para o usuário operador
  • Serviço SSH (sshd) ativo e configurado em ambos os servidores, com autenticação por chave pública para a seção de replicação remota
  • Conhecimento prévio de criação e manipulação básica de datasets ZFS (Aulas 12 a 14 do curso)
  • Editor de texto de sua preferência: vi, ee ou nano

Se você estiver utilizando máquinas virtuais para simular o ambiente de replicação, certifique-se de que ambas as VMs estejam na mesma rede bridge e possuam nomes de host distintos. Utilizaremos servidor-a como origem da replicação e servidor-b como destino ao longo de toda a aula.

Entendendo Snapshots no ZFS avançado: Arquitetura e Funcionamento Interno

Antes de executarmos qualquer comando, é fundamental compreender como os snapshots funcionam internamente no ZFS — isso evitará surpresas desagradáveis quando você precisar gerenciar milhares deles em produção. Diferentemente de snapshots em LVM (Logical Volume Manager) no Linux, que alocam espaço fixo para áreas de copy-on-write, os snapshots do ZFS avançado são baseados puramente em ponteiros de bloco. Quando você cria um snapshot, o ZFS não copia nenhum dado — ele simplesmente preserva a árvore de referências (block pointers) que apontam para os blocos de dados no momento da criação. Isso significa que um snapshot ocupa zero bytes no momento de sua criação, e só começa a consumir espaço conforme os blocos originais são modificados ou excluídos no dataset ativo.

O mecanismo que torna isso possível é o copy-on-write (CoW) inerente ao ZFS. Sempre que um bloco de dados no dataset ativo é sobrescrito, o ZFS não modifica o bloco original — ele grava o novo conteúdo em um bloco diferente no disco e atualiza os ponteiros do dataset ativo para apontar para o novo bloco. O bloco original permanece intacto porque o snapshot ainda mantém referências para ele. Esta é a razão pela qual você pode ter centenas de snapshots sem esgotar o espaço do pool, desde que a taxa de modificação (churn rate) dos dados seja baixa. Em nossos projetos na JRT Technology Solutions, gerenciamos ambientes com snapshots horários retidos por 90 dias em datasets de 2 TB, onde o consumo real de espaço para snapshots raramente excede 15% do tamanho do dataset.

Outro aspecto crucial é que snapshots no ZFS são atômicos e consistentes no nível do sistema de arquivos — não no nível da aplicação. Isso significa que, se você tirar um snapshot de um dataset contendo arquivos de um banco de dados MySQL que está com buffers de escrita abertos, o snapshot conterá o estado exato dos arquivos naquele instante, mas isso não garante consistência transacional do banco. Para bancos de dados, recomendamos sempre executar um FLUSH TABLES WITH READ LOCK (MySQL) ou pg_start_backup() (PostgreSQL) antes de criar o snapshot, prática que abordaremos com mais detalhes na seção de boas práticas. O ZFS avançado oferece a propriedade snapdir (visible ou hidden) que controla se o diretório .zfs/snapshot fica acessível aos usuários — uma funcionalidade extremamente útil para restaurações self-service.

Existe ainda uma distinção importante entre snapshots recursivos e não recursivos. Quando você cria um snapshot com a flag -r (recursive), o ZFS cria snapshots atômicos simultâneos em todos os datasets filhos da hierarquia, garantindo consistência cruzada entre datasets relacionados. Isso é essencial quando você tem, por exemplo, um dataset para logs e outro para dados de aplicação que precisam ser restaurados para o mesmo ponto no tempo. Sem a recursividade, cada snapshot seria independente e poderia capturar estados ligeiramente diferentes. A desvantagem é que snapshots recursivos são tratados como um grupo — você não pode destruir um filho sem destruir todo o grupo, a menos que utilize a opção -d (defer) para adiar a destruição.

Passo a Passo: Criando e Gerenciando Snapshots no ZFS avançado

Vamos agora colocar a teoria em prática. Nosso cenário de trabalho será um dataset chamado zroot/dados contendo arquivos de exemplo que simulam um ambiente de aplicação real. Criaremos este dataset, popularemos com dados, tiraremos snapshots em momentos específicos e verificaremos o funcionamento completo do ciclo de vida de snapshots. Cada comando será explicado linha por linha, com a saída esperada exibida em bloco separado para que você possa comparar com seu próprio terminal.

  1. Criar o dataset de teste e popular com conteúdo inicial
# 1. Criar o dataset pai que usaremos durante toda a aula
zfs create -o mountpoint=/dados zroot/dados

# 2. Criar uma estrutura de diretórios simulando uma aplicação web
mkdir -p /dados/app/uploads /dados/app/config /dados/logs

# 3. Gerar arquivos de configuração (simulando um deploy inicial)
echo "DB_HOST=localhost" > /dados/app/config/database.conf
echo "APP_ENV=production" > /dados/app/config/app.conf

# 4. Gerar arquivos de dados simulados (100 MB para teste de espaço)
dd if=/dev/urandom of=/dados/app/uploads/imagem_grande.bin bs=1M count=100 2>/dev/null

# 5. Criar alguns arquivos de log iniciais
echo "[2026-07-26 10:00:00] Aplicacao iniciada com sucesso" > /dados/logs/app.log
echo "[2026-07-26 10:05:00] Primeira requisicao processada" >> /dados/logs/app.log

# 6. Verificar a estrutura criada
find /dados -type f -exec ls -lh {} \;
-rw-r--r--  1 root  wheel    29B Jul 26 10:02 /dados/app/config/database.conf
-rw-r--r--  1 root  wheel    24B Jul 26 10:03 /dados/app/config/app.conf
-rw-r--r--  1 root  wheel   100M Jul 26 10:05 /dados/app/uploads/imagem_grande.bin
-rw-r--r--  1 root  wheel    42B Jul 26 10:05 /dados/logs/app.log
  1. Criar o primeiro snapshot — estado inicial da aplicação
# 7. Criar snapshot com nome descritivo e timestamp
# Formato recomendado: dataset@tipo-data-hora
zfs snapshot zroot/dados@deploy-inicial-20260726

# 8. Verificar se o snapshot foi criado
zfs list -t snapshot -r zroot/dados
NAME                                    USED  AVAIL  REFER  MOUNTPOINT
zroot/dados@deploy-inicial-20260726      0B      -  96K  -

Observe que a coluna USED mostra 0B. Isso confirma que o snapshot, no momento da criação, não ocupa espaço adicional — ele apenas preserva as referências para os 100 MB de dados que já existiam. O valor na coluna REFER (96K) refere-se aos metadados do próprio dataset, não aos dados de usuário. À medida que modificarmos os arquivos, o campo USED crescerá para refletir os blocos antigos que estão sendo preservados exclusivamente por este snapshot.

  1. Simular modificações no sistema e criar um segundo snapshot
# 9. Modificar arquivo de configuração (simulando alteração em produção)
echo "DB_HOST=192.168.1.50" > /dados/app/config/database.conf
echo "APP_ENV=production" > /dados/app/config/app.conf
echo "DEBUG_MODE=false" >> /dados/app/config/app.conf

# 10. Adicionar nova entrada de log
echo "[2026-07-26 11:00:00] Migracao de banco de dados concluida" >> /dados/logs/app.log

# 11. Criar um novo arquivo (upload de usuário simulado)
dd if=/dev/urandom of=/dados/app/uploads/foto_perfil.bin bs=1M count=50 2>/dev/null

# 12. Criar segundo snapshot capturando o estado pós-alterações
zfs snapshot zroot/dados@pos-migracao-20260726

# 13. Listar todos os snapshots do dataset
zfs list -t snapshot -o name,used,refer,creation -r zroot/dados
NAME                                     USED   REFER  CREATION
zroot/dados@deploy-inicial-20260726     50.1M    96K  Sun Jul 26 10:10 2026
zroot/dados@pos-migracao-20260726          0B    96K  Sun Jul 26 11:05 2026

Agora vemos que o primeiro snapshot (deploy-inicial-20260726) está consumindo 50.1 MB de espaço. Por quê? Porque criamos um novo arquivo de 50 MB (foto_perfil.bin) e modificamos arquivos existentes. Os blocos antigos do database.conf e do app.conf originais agora são mantidos exclusivamente pelo primeiro snapshot, enquanto o dataset ativo aponta para os novos blocos. Os 100 MB do arquivo imagem_grande.bin permanecem compartilhados entre o snapshot e o dataset ativo, pois não foram modificados — o ZFS não duplica esses blocos. Esta é a economia de espaço característica do ZFS avançado.

  1. Inspecionar o conteúdo de um snapshot sem restaurá-lo
# 14. Habilitar o diretório oculto .zfs para acesso fácil aos snapshots
zfs set snapdir=visible zroot/dados

# 15. Listar o conteúdo do snapshot diretamente pelo diretório .zfs
ls -la /dados/.zfs/snapshot/deploy-inicial-20260726/app/config/

# 16. Comparar arquivo atual com versão do snapshot
echo "=== Versão ATUAL ==="
cat /dados/app/config/database.conf
echo ""
echo "=== Versão no SNAPSHOT deploy-inicial ==="
cat /dados/.zfs/snapshot/deploy-inicial-20260726/app/config/database.conf
=== Versão ATUAL ===
DB_HOST=192.168.1.50

=== Versão no SNAPSHOT deploy-inicial ===
DB_HOST=localhost

A propriedade snapdir=visible torna o diretório .zfs acessível no ponto de montagem do dataset. Dentro dele, o subdiretório snapshot contém uma entrada para cada snapshot existente, permitindo navegação e recuperação granular de arquivos individuais sem necessidade de rollback completo — uma funcionalidade extremamente útil que nossos especialistas utilizam diariamente em operações de recuperação na JRT Technology Solutions quando um cliente exclui acidentalmente um arquivo específico e não deseja reverter todo o dataset.

  1. Restaurar o dataset para um snapshot anterior (rollback)
# 17. Tentar rollback direto (vai falhar porque existem snapshots intermediários)
zfs rollback zroot/dados@deploy-inicial-20260726
cannot rollback to 'zroot/dados@deploy-inicial-20260726': more recent snapshots exist
use '-r' to force deletion of the following snapshots:
zroot/dados@pos-migracao-20260726

O ZFS impede o rollback quando existem snapshots mais recentes, protegendo você contra perda acidental de estados intermediários. Temos duas opções: usar -r para destruir todos os snapshots posteriores, ou usar -R para destruir os snapshots e também todos os clones derivados deles. A abordagem segura em produção é primeiro verificar se você realmente precisa destruir os snapshots intermediários.

# 18. Realizar rollback com confirmação, destruindo snapshots posteriores
zfs rollback -r zroot/dados@deploy-inicial-20260726

# 19. Verificar que os dados voltaram ao estado original
cat /dados/app/config/database.conf
ls -la /dados/app/uploads/
DB_HOST=localhost

-rw-r--r--  1 root  wheel  104857600 Jul 26 10:05 imagem_grande.bin

Após o rollback, o arquivo foto_perfil.bin (50 MB) desapareceu, e o database.conf voltou a apontar para localhost. O espaço dos snapshots destruídos foi liberado imediatamente. Em ambientes de produção, sempre documente quais snapshots serão perdidos antes de executar um rollback com -r, pois a operação é irreversível.

ZFS avançado: Criando e Gerenciando Clones com Economia de Espaço

Enquanto snapshots são read-only por definição, clones são cópias writable derivadas de snapshots, utilizando o mesmo mecanismo de copy-on-write para compartilhar blocos com o snapshot de origem. Imagine que você precisa criar um ambiente de desenvolvimento idêntico ao de produção, com 500 GB de dados. Sem clones, você precisaria copiar fisicamente todos os arquivos — consumindo outros 500 GB e tempo considerável. Com ZFS avançado, um clone ocupa inicialmente zero bytes adicionais, e só consome espaço conforme as diferenças vão sendo escritas. Em nossos ambientes na JRT Technology Solutions, provisionamos ambientes de homologação completos em segundos usando clones, permitindo que desenvolvedores testem contra dados reais de produção sem risco de corrupção do original.

Existe, no entanto, uma restrição fundamental: um clone mantém uma dependência de origem (origin) com o snapshot que o gerou. Enquanto essa dependência existir, você não pode destruir o snapshot de origem sem antes destruir ou promover o clone. A promoção de um clone (zfs promote) inverte a relação de dependência, transformando o clone em um dataset independente e o dataset original em um clone dele — uma operação atômica que não move dados fisicamente, apenas reorganiza os metadados de dependência na árvore do pool.

  1. Criar um clone do snapshot deploy-inicial
# 20. Verificar snapshots disponíveis após o rollback
zfs list -t snapshot -r zroot/dados

# 21. Criar um clone chamado 'dev-teste' a partir do snapshot
zfs clone zroot/dados@deploy-inicial-20260726 zroot/dados-dev

# 22. Verificar a estrutura — o clone aparece como um dataset normal
zfs list -r zroot/dados -o name,used,refer,origin,mountpoint
NAME                USED   REFER  ORIGIN                                  MOUNTPOINT
zroot/dados        50.1M    96K  -                                        /dados
zroot/dados-dev       8K    96K  zroot/dados@deploy-inicial-20260726      /dados-dev

Observe a coluna ORIGIN do dataset zroot/dados-dev: ela aponta para o snapshot que o originou. Neste momento, o clone dados-dev compartilha todos os blocos com o snapshot deploy-inicial-20260726, consumindo apenas metadados (8K). Se você navegar até /dados-dev, encontrará exatamente os mesmos arquivos do snapshot, mas com permissão de escrita.

  1. Modificar o clone e verificar o impacto no espaço
# 23. Criar um arquivo dentro do clone (escrevendo novos dados)
dd if=/dev/urandom of=/dados-dev/app/teste_novo.bin bs=1M count=20 2>/dev/null

# 24. Modificar um arquivo existente no clone
echo "AMBIENTE=desenvolvimento" > /dados-dev/app/config/ambiente.conf

# 25. Verificar consumo de espaço — apenas os novos blocos são alocados
zfs list -r zroot/dados -o name,used,refer,origin
NAME                USED   REFER  ORIGIN
zroot/dados        50.1M    96K  -
zroot/dados-dev    20.1M  20.1M  zroot/dados@deploy-inicial-20260726

O clone agora consome 20.1 MB, correspondentes exatamente ao novo arquivo de 20 MB mais metadados. O arquivo original imagem_grande.bin (100 MB) continua sendo compartilhado com o snapshot de origem sem duplicação. Se você destruir o clone, o espaço será liberado; se destruir o snapshot de origem, receberá um erro de dependência.

  1. Promover o clone a dataset independente
# 26. Tentar destruir o snapshot de origem (vai falhar)
zfs destroy zroot/dados@deploy-inicial-20260726
cannot destroy 'zroot/dados@deploy-inicial-20260726': snapshot has dependent clones
use '-R' to destroy the following datasets:
zroot/dados-dev
# 27. Promover o clone — agora ele se torna independente
zfs promote zroot/dados-dev

# 28. Verificar a nova relação de dependência
zfs list -r zroot/dados -o name,used,refer,origin
NAME                USED   REFER  ORIGIN
zroot/dados         150M    96K  zroot/dados-dev@deploy-inicial-20260726
zroot/dados-dev    20.1M  20.1M  -

Após a promoção, a relação se inverteu: agora zroot/dados (o dataset original) é que depende do snapshot de zroot/dados-dev. Na prática, isso significa que você pode destruir o dataset original se desejar, pois o clone promovido tornou-se o novo “ancestral”. Esta técnica é extremamente útil em cenários de disaster recovery onde você precisa ativar um ambiente de contingência e posteriormente torná-lo o novo primário.

Tabela 1: Comandos Essenciais para Snapshots e Clones no ZFS Avançado
Comando Descrição Flags Críticas
zfs snapshot dataset@nome Cria snapshot atômico do dataset -r (recursivo), -o property=value (define propriedades)
zfs list -t snapshot Lista todos os snapshots do pool/dataset -r (recursivo), -o (colunas personalizadas), -s (ordenação)
zfs rollback dataset@snap Restaura dataset ao estado do snapshot -r (destrói snapshots posteriores), -R (destrói snaps e clones), -f (força)
zfs destroy dataset@snap Remove snapshot específico -r (recursivo), -d (adiado — requer zfs destroy -d para confirmar), -R (destrói dependentes)
zfs clone snap dataset_novo Cria clone writable de um snapshot -o property=value (define propriedades), -p (cria datasets pais se necessário)
zfs promote dataset Promove clone a dataset independente Sem flags adicionais — operação atômica
zfs diff snap1 snap2 Mostra diferenças entre dois snapshots -F (formato legível), -t (timestamp), -H (saída parseável)
zfs hold tag dataset@snap Impede destruição do snapshot (userref) -r (recursivo); liberar com zfs release tag snap

Replicação ZFS entre Servidores com Send e Receive — O Coração do ZFS avançado

A replicação nativa do ZFS é, sem dúvida, um dos recursos mais impactantes do ZFS avançado em ambientes corporativos. Diferentemente de ferramentas como rsync, que operam no nível de arquivos e precisam percorrer toda a árvore de diretórios para detectar mudanças, o zfs send trabalha no nível de blocos, serializando apenas os blocos que diferem entre dois snapshots. Isso significa que, em um dataset de 2 TB onde apenas 50 MB foram modificados desde o último snapshot, a replicação incremental enviará apenas esses 50 MB — com compressão adicional habilitada via -c ou através de pipes para gzip/bzip2. Em nossos projetos de disaster recovery na JRT Technology Solutions, replicamos datasets de bancos de dados entre datacenters com latência de apenas 2 a 3 minutos para incrementais, mesmo em links de 100 Mbps, graças à eficiência do send/recv do ZFS.

O fluxo básico de replicação consiste em três etapas: (1) criar um snapshot no servidor de origem, (2) enviar o snapshot serializado via zfs send e (3) receber e reconstruir o dataset no servidor de destino via zfs receive. Para a replicação inicial (full), o snapshot de origem é enviado por completo; para replicações subsequentes (incrementais), utiliza-se a sintaxe zfs send -i snap_anterior snap_atual, que envia apenas os blocos modificados entre os dois snapshots. O destino reconstrói o estado completo aplicando os incrementos sobre a base já existente. Existem também os modos -R (replicação recursiva, preservando propriedades e snapshots) e -p (preserva propriedades), essenciais para migração completa de hierarquias de datasets.

Passo a Passo: Replicação Local (Mesmo Pool) para Testes

Antes de configurar a replicação entre servidores, vamos praticar o fluxo completo em um cenário local, replicando dados entre dois datasets no mesmo pool. Isso permite testar todo o pipeline sem dependência de rede, e é uma técnica valiosa para migrações dentro do mesmo storage.

# 29. Criar dataset de destino para receber a replicação
zfs create zroot/dados-backup

# 30. Garantir que temos um snapshot recente para enviar
zfs snapshot zroot/dados@para-replicar-20260726

# 31. Realizar o envio (send) e recebimento (receive) em pipeline local
# O flag -v (verbose) mostra progresso; -p preserva propriedades
zfs send -v zroot/dados@para-replicar-20260726 | zfs receive -v zroot/dados-backup

# 32. Comparar os datasets — devem ser idênticos
zfs list -r zroot/dados -o name,used,refer,origin
zfs list -r zroot/dados-backup -o name,used,refer
full send of zroot/dados@para-replicar-20260726 estimated size is 50.1M
total estimated size is 50.1M
receiving full stream of zroot/dados@para-replicar-20260726 into zroot/dados-backup@para-replicar-20260726
received 50.1M stream in 2 seconds (25.0M/sec)
NAME                          USED   REFER  ORIGIN
zroot/dados                  50.1M    96K  zroot/dados-dev@deploy-inicial-20260726
zroot/dados@para-replicar-20260726   0B    96K  -
NAME                          USED   REFER
zroot/dados-backup           50.1M  50.1M
zroot/dados-backup@para-replicar-20260726   0B    96K

Observe que o comando zfs receive automaticamente cria um snapshot no destino com o mesmo nome do snapshot enviado. O dataset zroot/dados-backup agora contém uma cópia fiel dos dados no momento do snapshot. A taxa de transferência de 25 MB/s é limitada pela velocidade do disco local, mas em um cenário real de rede esse número será limitado pela largura de banda.

Passo a Passo: Replicação Incremental (Send/Receive Diferencial)

A replicação incremental é o verdadeiro diferencial do ZFS avançado. Ela permite sincronizar apenas as mudanças ocorridas entre dois snapshots, reduzindo drasticamente o volume de dados transmitidos. Para demonstrar, faremos modificações no dataset de origem e replicaremos apenas o delta.

# 33. Fazer modificações no dataset de origem
echo "NOVO_PARAMETRO=valor_teste" >> /dados/app/config/app.conf
dd if=/dev/urandom of=/dados/app/uploads/novo_upload.bin bs=1M count=30 2>/dev/null

# 34. Criar um novo snapshot capturando as alterações
zfs snapshot zroot/dados@incremental-1-20260726

# 35. Enviar APENAS a diferença entre os dois snapshots
# -i snapshot_anterior snapshot_atual = modo incremental
zfs send -v -i zroot/dados@para-replicar-20260726 zroot/dados@incremental-1-20260726 | zfs receive -v zroot/dados-backup
send from @para-replicar-20260726 to zroot/dados@incremental-1-20260726 estimated size is 30.1M
total estimated size is 30.1M
receiving incremental stream of zroot/dados@incremental-1-20260726 into zroot/dados-backup@incremental-1-20260726
received 30.1M stream in 1 seconds (30.1M/sec)

O envio incremental transferiu apenas 30.1 MB em vez dos 80 MB totais que o dataset agora contém. Em cenários com datasets de terabytes e modificações diárias de poucos gigabytes, essa eficiência é o que viabiliza janelas de backup curtas e replicação quase em tempo real. Para automatizar esse processo, você pode criar um script que mantenha uma lista de snapshots sincronizados entre origem e destino, comparando os snapshots existentes em ambos os lados antes de decidir qual incremental enviar.

Configuração Detalhada: Replicação Remota via SSH no ZFS avançado

A replicação entre servidores distintos requer que o stream de dados do zfs send seja transportado pela rede. O método mais seguro e eficiente é encapsular o pipe dentro de uma sessão SSH, que provê criptografia, compressão adicional e autenticação robusta. Antes de executar os comandos, é necessário configurar a autenticação por chave pública entre os servidores para evitar prompts de senha durante a replicação automatizada. Mostraremos a configuração completa, incluindo a criação das chaves e a distribuição adequada.

No servidor de origem (servidor-a):

# 36. Gerar par de chaves SSH sem passphrase (para automação)
ssh-keygen -t ed25519 -f /root/.ssh/id_ed25519_zfs_replication -N ""

# 37. Exibir a chave pública para copiar para o destino
cat /root/.ssh/id_ed25519_zfs_replication.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJR... restante_da_chave root@servidor-a

No servidor de destino (servidor-b):

# 38. Criar dataset que receberá a replicação (mesmo nome ou nome diferente)
zfs create -o mountpoint=/dados-remoto zroot/dados-replicado

# 39. Autorizar a chave pública do servidor de origem
# Copie a linha completa exibida pelo cat no servidor-a
mkdir -p /root/.ssh
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJR... restante_da_chave root@servidor-a" >> /root/.ssh/authorized_keys

# 40. Ajustar permissões (crítico para o SSH aceitar a chave)
chmod 700 /root/.ssh
chmod 600 /root/.ssh/authorized_keys

# 41. Testar conectividade SSH do servidor de origem
# Execute no servidor-a:
ssh -i /root/.ssh/id_ed25519_zfs_replication root@192.168.1.101 "hostname && zfs list -H -o name zroot/dados-replicado"
servidor-b
zroot/dados-replicado

Executar a replicação remota completa:

# 42. No servidor-a, enviar snapshot via SSH para o servidor-b
# O pipe é redirecionado através do SSH para o zfs receive remoto
zfs send -v zroot/dados@para-replicar-20260726 | \
  ssh -i /root/.ssh/id_ed25519_zfs_replication root@192.168.1.101 \
  "zfs receive -v zroot/dados-replicado"

Replicação incremental remota:

# 43. Enviar apenas o incremental pela rede
zfs send -v -i zroot/dados@para-replicar-20260726 zroot/dados@incremental-1-20260726 | \
  ssh -i /root/.ssh/id_ed25519_zfs_replication root@192.168.1.101 \
  "zfs receive -v zroot/dados-replicado"

Replicação recursiva com todas as propriedades e snapshots:

# 44. Envio recursivo preservando datasets filhos, propriedades e snapshots
zfs send -v -R zroot/dados@incremental-1-20260726 | \
  ssh -i /root/.ssh/id_ed25519_zfs_replication root@192.168.1.101 \
  "zfs receive -v -F zroot/dados-replicado"

A flag -R no zfs send replica recursivamente toda a hierarquia de datasets abaixo de zroot/dados, incluindo snapshots, clones e propriedades customizadas. A flag -F no zfs receive força a sobrescrita do dataset de destino se ele já existir — use com extrema cautela em ambientes de produção, pois isso destruirá quaisquer dados no destino que não estejam no stream de envio. Em nossos protocolos de replicação na JRT Technology Solutions, sempre validamos o estado do destino antes de aplicar -F, geralmente mantendo um snapshot de segurança no destino antes da operação.

Verificando a Instalação / Testando a Configuração

Após implementar a replicação, é essencial verificar a integridade dos dados no destino para garantir que não houve corrupção durante a transferência. O ZFS oferece checagens de checksum ponta a ponta que protegem contra corrupção silenciosa, mas ainda assim devemos validar manualmente a consistência lógica dos arquivos.

# 45. No servidor de destino, verificar se o dataset foi recebido corretamente
zfs list -r zroot/dados-replicado -o name,used,refer,origin

# 46. Comparar checksums de um arquivo entre origem e destino
# No servidor-a (origem):
md5 /dados/app/config/app.conf

# No servidor-b (destino):
md5 /dados-remoto/app/config/app.conf

# 47. Verificar integridade do pool de destino (scrub)
zpool scrub zroot
zpool status zroot

# 48. Listar snapshots no destino — devem corresponder aos enviados
zfs list -t snapshot -r zroot/dados-replicado
NAME                                                   USED   REFER  ORIGIN
zroot/dados-replicado                                  80.2M  50.1M  -
zroot/dados-replicado@para-replicar-20260726           30.1M  50.1M  -
zroot/dados-replicado@incremental-1-20260726               0  30.1M  -

MD5 (/dados/app/config/app.conf) = a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
MD5 (/dados-remoto/app/config/app.conf) = a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6

Os hashes MD5 idênticos confirmam que a replicação foi íntegra. O comando zpool scrub verifica todos os checksums no pool de destino, garantindo que os blocos foram gravados corretamente no disco. Em ambientes de produção, recomendamos executar scrub semanalmente e configurar alertas para qualquer erro detectado — mesmo com ZFS avançado, falhas de hardware podem corromper dados que não estão em replicação ativa.

Erros Comuns e Como Resolver

  • Erro 1: “cannot receive incremental stream: most recent snapshot of dataset does not match incremental source”

    Causa: O destino não possui o snapshot base necessário para aplicar o incremental. Isso ocorre quando snapshots intermediários foram destruídos no destino, ou quando você tenta enviar um incremental baseado em um snapshot que nunca foi replicado.

    Sintoma: O comando zfs receive falha imediatamente com a mensagem acima, sem transferir dados.

    Solução: Liste os snapshots no destino com zfs list -t snapshot -r dataset_destino e compare com a origem. Se o snapshot base estiver ausente, você precisará fazer um full send novamente. Para evitar isso, implemente retenção simétrica de snapshots em ambos os lados e nunca destrua snapshots no destino sem confirmar que não são base para incrementais futuros. Uma técnica segura é usar zfs hold para proteger snapshots de destruição acidental.

  • Erro 2: “cannot mount ‘dataset’: failed to create mountpoint”

    Causa: O ponto de montagem especificado no dataset de destino já existe como diretório não vazio, ou o diretório pai não existe e a propriedade mountpoint está configurada para um caminho inválido.

    Sintoma: Após o zfs receive, o dataset aparece na lista mas não é montado automaticamente, ou o comando zfs mount retorna erro.

    Solução: Verifique o mountpoint com zfs get mountpoint dataset. Se o diretório já existe e contém arquivos, remova-o (rm -rf /caminho) ou altere o mountpoint com zfs set mountpoint=/novo/caminho dataset. Se o diretório pai não existe, crie-o com mkdir -p /caminho/pai e então execute zfs mount dataset. Em replicações recorrentes, configure o mountpoint no destino para evitar conflitos com datasets locais.

  • Erro 3: “warning: cannot send ‘dataset@snap’: not an earlier snapshot from the same filesystem”

    Causa: Você especificou snapshots de datasets diferentes no comando zfs send -i, ou inverteu a ordem (snapshot mais recente listado antes do mais antigo).

    Sintoma: O comando falha com a mensagem de warning, e nenhum dado é enviado.

    Solução: Verifique se ambos os snapshots pertencem ao mesmo dataset com zfs list -t snapshot -r dataset. A ordem correta é sempre zfs send -i snapshot_MAIS_ANTIGO snapshot_MAIS_RECENTE. Se precisar reverter a ordem (enviar para trás), você deve usar zfs rollback no destino em vez de replicação.

  • Erro 4: “out of space” durante zfs receive

    Causa: O pool de destino não possui espaço livre suficiente para receber o stream completo. Isso é particularmente comum em replicações incrementais onde o destino acumulou snapshots que consomem espaço significativo, ou quando a taxa de compressão no destino é menor que na origem.

    Sintoma: O zfs receive aborta no meio da transferência com mensagem de falta de espaço, e o dataset de destino pode ficar em estado inconsistente.

    Solução: Primeiro, verifique o espaço disponível no pool de destino: zpool list e zfs list -o space. Libere espaço destruindo snapshots antigos no destino (zfs destroy dataset@snap_antigo) ou snapshots não essenciais. Se o dataset de destino ficou parcialmente recebido, destrua-o com zfs destroy -r dataset_destino e reinicie a replicação após liberar espaço. Para prevenir, monitore proativamente o espaço e configure quotas (zfs set quota=) e reservas (zfs set reservation=) adequadas.

  • Erro 5: “cannot receive new filesystem stream: destination has been modified”

    Causa: Foram feitas alterações diretamente no dataset de destino após ele ter recebido dados replicados. O ZFS protege a integridade do

Quer aprender na prática com especialistas?

A JRT Technology Solutions oferece treinamentos e implementação de FreeBSD para equipes corporativas.



Falar no WhatsApp

Thiago Paes Rodrigues

Com mais de 22 anos de experiência em Tecnologia da Informação, este profissional construiu uma trajetória sólida como empresário, atuando de forma estratégica na implementação de soluções tecnológicas que otimizam processos e impulsionam resultados em diferentes setores.