Home Comunidade Eventos YouTube Networks Desafios // produtos Academy News CTI | CVE Contato

02 - Persistência vs Volátil

video explicativo
Video explicativoEspaco reservado para o video desta anotação — adicione video: https://youtu.be/... no frontmatter da nota.

1. Modos de Armazenamento e a Diretiva Storage=

O comportamento do systemd-journald em relação à retenção de dados é governado primariamente pela diretiva Storage= no arquivo de configuração /etc/systemd/journald.conf (ou em drop-ins em /etc/systemd/journald.conf.d/*.conf). A taxonomia dos modos de armazenamento compreende quatro estados mutuamente exclusivos:

1.1. Storage=volatile

Neste modo, os dados do journal são gravados estritamente em memória RAM, utilizando o sistema de arquivos temporário tmpfs montado em /run/log/journal/.

  • Comportamento de Ciclo de Vida: Nenhuma informação é escrita no disco rígido ou SSD. No instante em que o sistema operacional é desligado ou reiniciado (ou se ocorrer um power loss ou Kernel Panic), a totalidade dos registros mantidos em memória volatiliza-se irreversivelmente.
  • Casos de Uso Primários: Sistemas embarcados (embedded Linux) com memórias Flash do tipo NOR/NAND sujeitas a desgaste por ciclos de escrita (Program/Erase cycles), sistemas operando com raiz em modo somente leitura (Read-Only Root Filesystem), e nós de processamento efêmeros em clusters (stateless nodes) onde os logs são transmitidos em tempo real pela rede via systemd-journal-remote.

1.2. Storage=persistent

Força a gravação dos dados em armazenamento não volátil, no diretório /var/log/journal/.

  • Comportamento Autônomo: Se o diretório /var/log/journal/ não existir no momento em que o daemon é iniciado (ou durante a transição de boot), o próprio systemd-journald tenta criar o diretório com as permissões e contextos de segurança (SELinux/AppArmor) corretos, ativando a persistência imediatamente.
  • Casos de Uso Primários: Servidores de produção, estações de trabalho e qualquer ambiente onde a auditoria histórica pós-reboot, análise de causa raiz (post-mortem analysis) e conformidade regulatória sejam mandatórias.

1.3. Storage=auto (O Padrão Distribuído)

Representa uma abordagem híbrida e condicional. É a configuração padrão na maioria das distribuições Linux modernas (Debian, Ubuntu, RHEL, Arch Linux).

  • Lógica de Decisão: O systemd-journald verifica ativamente a existência física do diretório /var/log/journal/.
  • Se o diretório existir, o daemon comporta-se exatamente como Storage=persistent, gravando no disco não volátil.
  • Se o diretório não existir, o daemon atua como Storage=volatile, gravando em /run/log/journal/, sem criar o diretório em /var/ de forma autônoma.

  • Garantia de Flexibilidade: Permite que distribuidores ofereçam uma única imagem de sistema onde a persistência pode ser ativada pelo administrador simplesmente criando o diretório com mkdir -p /var/log/journal e reiniciando o serviço ou aplicando o flush.

1.4. Storage=none

Aniquila completamente a retenção local de logs.

  • Comportamento Interno: Todas as entradas de log recebidas via pipes de stdout/stderr, soquete /dev/log ou /dev/kmsg são descartadas imediatamente no espaço de memória (redirecionadas internamente para um nulo funcional).
  • Exceções: Se a duplicação/encaminhamento estiver ativada (ForwardToSyslog=yes, ForwardToConsole=yes, etc.), as mensagens ainda serão entregues a esses destinos externos antes do descarte do registro no journal.

2. A Mecânica de Transição no Boot: O Processo de Flush

Um dos desafios mais complexos na arquitetura de inicialização do Linux é a fase do early boot. Quando o kernel passa o controle para o PID 1 (systemd), o sistema de arquivos raiz (/) frequentemente está montado apenas como leitura (Read-Only), e a partição dedicada /var/ pode residir em um volume LVM, disco cifrado via LUKS ou ponto de montagem de rede que ainda não está disponível.

Para resolver o paradoxo de ter que registrar logs antes que o disco de destino de logs possa ser escrito, o systemd-journald implementa um pipeline de migração em duas fases denominado Flush.

+-------------------------------------------------------------------------+
|                              FASE 1: EARLY BOOT                         |
|                                                                         |
|  [Kernel Ring Buffer / Stdout / Sockets]                                |
|                        │                                                |
|                        ▼                                                |
|            systemd-journald (RAM)                                       |
|                        │                                                |
|                        ▼                                                |
|            /run/log/journal/<machine-id>/                               |
|            (tmpfs - Volátil / Alta Velocidade)                          |
+-------------------------------------------------------------------------+
                                 │
                                 │  Montagem do /var (Read-Write)
                                 │  Alcançado: local-fs.target
                                 │  Execução: systemd-journal-flush.service
                                 ▼
+-------------------------------------------------------------------------+
|                              FASE 2: LATE BOOT                          |
|                                                                         |
|  1. Interrupção temporária de novas gravações                           |
|  2. Leitura dos arquivos em /run/log/journal/<machine-id>/              |
|  3. Transfere e funde entradas em /var/log/journal/<machine-id>/        |
|  4. Remoção atômica dos arquivos binários em RAM                        |
|  5. Transição de ponteiros de escrita para o Disco Não-Volátil          |
+-------------------------------------------------------------------------+

2.1. Sequenciamento de Unidades do Systemd

A migração ordenada do estado volátil para o persistente é orquestrada por uma unidade de serviço dedicada no Grafo Acíclico Dirigido (DAG): systemd-journal-flush.service.

  1. Montagem do Sistema de Arquivos: O boot prossegue até que todos os sistemas de arquivos locais declarados em /etc/fstab estejam devidamente montados em modo leitura-escrita (Read-Write). A conclusão desta fase é sinalizada pela unidade local-fs.target.
  2. Invocação do Flush: A unidade systemd-journal-flush.service possui as diretivas:
Requires=local-fs.target
After=local-fs.target
ExecStart=journalctl --flush

  1. A Syscall / Sinal IPC: O comando journalctl --flush não realiza a cópia direta por si só; ele envia uma requisição IPC D-Bus (ou o sinal assíncrono SIGUSR1) para o processo systemd-journald ativo.

2.2. A Transfomação Atômica de Estado (Merging)

Ao receber a instrução de flush, o systemd-journald executa a seguinte sequência de operações binárias de baixo nível:

  1. Abre o diretório persistente /var/log/journal/<machine-id>/.
  2. Trava temporariamente as threads de gravação para garantir a consistência das tabelas B-Tree dos arquivos em memória RAM.
  3. Lê os registros do arquivo .journal presente em /run/log/journal/<machine-id>/.
  4. Insere ordenadamente cada registro no arquivo .journal ativo dentro de /var/log/journal/<machine-id>/, recomputando os hashes do dicionário, atualizando as árvores de busca e integrando os metadados de tempo (Realtime e Monotonic).
  5. Desconecta os descritores de arquivo de /run/log/journal/.
  6. Deleta sumariamente os arquivos de log do diretório volátil e remove a estrutura temporária do tmpfs.
  7. Redireciona todos os ponteiros de escrita dos novos logs de entrada diretamente para o disco rígido/SSD.

Este mecanismo garante que nenhuma mensagem de log gerada nos primeiros milissegundos do boot seja perdida, unificando o histórico do early boot e do runtime em um único repositório ordenado.


3. Estrutura Física de Diretórios e a Função do machine-id

A organização dos arquivos binários em disco e em memória RAM segue uma estrita hierarquia de namespaces isolados por nó físico.

3.1. O Caminho do Identificador Único

Tanto em /run/log/journal/ quanto em /var/log/journal/, o systemd-journald nunca grava arquivos diretamente na raiz do diretório. Ele exige a criação de um subdiretório cujo nome é o código hexadecimal de 128 bits da máquina:

  • Caminho Volátil: /run/log/journal/3a8f9b2c1d4e5f6a7b8c9d0e1f2a3b4c/
  • Caminho Persistente: /var/log/journal/3a8f9b2c1d4e5f6a7b8c9d0e1f2a3b4c/

Este identificador é lido diretamente do arquivo /etc/machine-id (ou /var/lib/dbus/machine-id).

Razão Arquitetural do Isolamento por Machine ID:

Em ambientes corporativos com armazenamento centralizado via SAN, NFS ou iSCSI, múltiplos servidores virtuais ou físicos podem ter suas partições /var/log/ montadas em um volume de rede compartilhado. Se o systemd-journald gravasse em caminhos genéricos, haveria corrupção catastrófica de arquivos binários devido a escritas concorrentes por diferentes PIDs de diferentes kernels. Ao isolar os arquivos pelo machine-id único de cada SO, múltiplos nós podem compartilhar o mesmo diretório de armazenamento central sem risco de colisão de I/O.

3.2. Anatomia dos Arquivos .journal

Dentro do subdiretório do machine-id, encontram-se os arquivos de dados propriamente ditos:

  1. system.journal: O arquivo de gravação ativo para logs gerados pelo kernel, serviços do sistema e daemons do espaço de usuário.
  2. user-<UID>.journal: Arquivos de gravação ativos para logs gerados pelas instâncias do systemd --user de usuários comuns logados (por exemplo, user-1000.journal).
  3. system@<hash>.journal / user-<UID>@<hash>.journal: Arquivos rotacionados. Quando o arquivo ativo atinge os limites de tamanho estabelecidos em configuração, ele é selado (marcado como somente leitura) e renomeado acrescentando o hash do identificador e dos timestamps, e um novo arquivo ativo é criado.
  4. system.journal~ / user-<UID>.journal~: Arquivos de log corrompidos ou desconectados de forma imprópria. Se a máquina sofrer uma queda de energia catastrófica enquanto o systemd-journald realizava uma operação de gravação, o cabeçalho do arquivo não terá a flag de fechamento limpo (dirty bit ativo). No boot seguinte, o systemd-journald renomeia o arquivo adicionando o caractere ~ ao final, isola o arquivo corrompido para preservação forense e inicia um novo system.journal zerado.

4. Análise Comparativa de Impacto no Sistema

A escolha entre persistência total, volatilidade estrita ou operação híbrida afeta diretamente três métricas de infraestrutura: latência de I/O, desgaste de hardware e capacidade de recuperação de desastres.

Métrica / Propriedade Armazenamento Volátil (/run/) Armazenamento Persistente (/var/)
Meio Físico RAM (tmpfs). Disco de Bloco (SSD, NVMe, HDD).
Latência de Escrita Nanossegundos / Microssegundos (Acesso direto a memória bus). Milissegundos (Submetido a filas de I/O de bloco, barriers e flush do FS).
Consumo de Recursos Consome memória RAM alocada dinamicamente (pode pressionar a VFS). Consome espaço em disco não volátil (sujeito a exaustão de inodes/espaço).
Sobrevivência ao Reboot Não. Histórico é perdido 100% a cada reinicialização. Sim. Mantém histórico completo acumulado de múltiplos boots.
Resistência a Panic/Crash Logs do momento do crash são perdidos se a RAM for zerada. Preserva logs até a última chamada de fsync ou intervalo de sync.
Desgaste de Hardware Zero desgaste em mídias de armazenamento Flash. Causa gravações contínuas (submete SSDs a desgaste de TBW - Bytes Written).
Atribuição de Segurança Requer reconstrução da árvore em memória a cada boot. Suporta validação contínua de integridade via FSS (Forward Secure Sealing).

5. Sincronização de Disco e a Diretiva SyncIntervalSec=

No modo persistente, escrever todas as mensagens de log no disco no exato instante em que chegam inviabilizaria o desempenho do sistema de I/O da máquina. Um servidor web recebendo 10.000 requisições por segundo geraria 10.000 operações de escrita de bloco atômicas por segundo, forçando o motor de disco a atuar em pico constante de operação.

Para balancear a performance do sistema com a integridade dos dados, o systemd-journald utiliza uma técnica de Gravação Assíncrona Buffereada combinada com chamadas de sincronização periódicas.

5.1. A Mecânica do SyncIntervalSec=

A diretiva SyncIntervalSec= no /etc/systemd/journald.conf (cujo valor padrão é tipicamente 5s) determina o intervalo máximo de tempo antes que o systemd-journald force uma chamada de sistema fdatasync() ou fsync() nos arquivos .journal abertos no disco.

  1. Quando uma mensagem chega ao journald, ela é parseada, indexada na memória e gravada na página de buffer do sistema de arquivos no kernel (Page Cache).
  2. A mensagem é considerada ingerida, mas ainda reside no cache de escrita não volátil do kernel.
  3. A cada ciclo de SyncIntervalSec=, o systemd-journald acorda uma thread interna e emite um fdatasync() nos descritores de arquivos ativos. Isso força o subsistema VFS do kernel a esvaziar os dirty buffers de memória e gravar fisicamente os blocos nos pratos do HD ou na memória Flash do SSD.

5.2. Tratamento de Emergências e Gravação Síncrona

O systemd-journald quebra a regra da assincronicidade e força uma escrita síncrona imediata (fsync() instantâneo) sem aguardar o temporizador do SyncIntervalSec= se a mensagem de log recebida possuir uma prioridade Syslog crítica:

  • PRIORITY=0 (Emergency / Emergência)
  • PRIORITY=1 (Alert / Alerta)
  • PRIORITY=2 (Critical / Crítico)
  • PRIORITY=3 (Error / Erro)

Isto garante que, em caso de falha crítica iminente do aplicativo ou pânico de kernel iminente, as mensagens que explicam a causa do colapso sejam consolidadas no disco não volátil antes do desastre total.


6. Manipulação Prática e Diagnóstico de Estado

O administrador de sistemas interage com a máquina de estados de armazenamento através do utilitário journalctl e chamadas diretas de controle do systemd.

6.1. Verificação do Modo Ativo de Armazenamento

Para verificar se o journald está operando em modo volátil ou persistente no momento presente, inspeciona-se a localização dos arquivos ativos através do próprio journalctl:

# Exibe os arquivos de journal atualmente mapeados na memória
journalctl --header | grep -E "File Path|State"

Se as rotas exibidas apontarem para /run/log/journal/..., o sistema está em modo volátil. Se apontarem para /var/log/journal/..., o sistema está em modo persistente.

6.2. Forçando o Flush Manualmente

Caso o administrador tenha acabado de criar o diretório /var/log/journal/ em um sistema configurado como Storage=auto, não é necessário reiniciar o servidor. A migração dos logs residentes na RAM para o disco pode ser forçada instantaneamente com o comando:

journalctl --flush

Este comando bloqueia o terminal até que toda a base de dados acumulada em /run/ seja transcrita, indexada e consolidada em /var/, removendo os arquivos voláteis ao final.

6.3. Relocação Volátil Forçada (journalctl --relocate)

O comando oposto ao flush é o journalctl --relocate. Ele instrui o systemd-journald a fechar os arquivos no disco não volátil (/var/log/journal/), mover todos os registros atuais para o sistema de arquivos em memória RAM (/run/log/journal/) e continuar gravando exclusivamente em RAM a partir daquele ponto. Este comando é fundamental em operações de manutenção onde a partição /var/ precisa ser desmontada para redimensionamento de LVM, verificação de consistência (fsck) ou criptografia em tempo de execução.