Arquitetura cdylib + backend, modos dump/oplog incremental, point-in-time replay, manifest assinado em Ed25519, exporter Prometheus e isolamento de licença para Bacula Community 15.0.3+ e Bacularis.
Documento técnico complementar à página do plugin PodHeitor MongoDB.
1. Problema: backup de MongoDB com Bacula stock é um furo
O Bacula File Daemon, sozinho, faz backup de arquivos. MongoDB, em produção, não é um conjunto de arquivos coerentes em ponto algum do tempo: mover /var/lib/mongo com o mongod ativo produz um snapshot inconsistente que falha o --repair ou — pior — abre silenciosamente em estado corrompido. As alternativas tradicionais têm cada uma seu custo:
- Bacula Enterprise MongoDB plugin — só faz
mongodumpfull; não tem oplog incremental, não tem PITR, não tem manifest assinado, não tem exporter de métricas. - Veeam / Commvault — preço por TB protegido escala mal em clusters MongoDB grandes; PITR ainda depende de oplog manual.
- Scripts caseiros de
mongodump— ignoram o read preference, hammeram o PRIMARY, não detectam rotation gap de oplog, e o operador descobre só na hora do desastre.
O PodHeitor MongoDB endereça esses pontos com paralelismo cross-DB e cross-collection, oplog tip persistente, replay PIT por timestamp ou contador de incremental, e empacotamento RPM/DEB com unit systemd hardenizada.
2. Modelo arquitetural
O plugin segue o padrão PodHeitor de cdylib + backend standalone, com PTCOMM (length-tagged framing em stdin/stdout) entre os processos:
bacula-fd (root, daemon)
│
│ dlopen
▼
/opt/bacula/plugins/podheitor-mongodb-fd.so (Rust cdylib)
│
│ fork+exec, PTCOMM stdin/stdout
▼
/opt/bacula/bin/podheitor-mongodb-backend (per-job subprocess)
├── mongodump / mongorestore
├── stats sidecar → /opt/bacula/working/podheitor-mongodb-<r>-stats.json
├── oplog tip file → ...-tip.json
└── manifest + topology + RestoreObject → Bacula catalog (FT_RESTORE_FIRST=25)
│
▼
/opt/bacula/bin/podheitor-mongodb-exporter
(HTTP :9105/metrics, bacula:bacula, hardened systemd)
O motivo do split é o mesmo do HPC: crash isolation (um panic no driver MongoDB não wedga bacula-fd), liberdade de paralelismo (o backend hospeda tokio + threadpools cross-DB sem violar o contrato Bacula de “uma thread por bpContext“), e license firewall (o subprocesso nunca toca o ABI do Bacula; o cdylib o faz exclusivamente via crate bacula-fd-abi com extern "C" independente).
3. Modos de backup suportados (v1.0)
| Modo | Mecanismo | Status v1.0 |
|---|---|---|
dump |
mongodump lógico streaming, BSON over PTCOMM |
GA — JobId 7984/7985 validados |
dump multi-DB pipelined |
N DBs em paralelo, com cap configurável (parallel_dbs=4) |
GA — JobId 7906 |
dump per-collection chunking |
Particiona collection grande por _id via $bucketAuto |
GA — JobId 7925/7927 |
Oplog incremental (level=I) |
applyOps over the wire — incrementais reais, não diff de dump |
GA — JobId 8037-8041 |
| PIT replay | second / RFC 3339 / :inc / @inc |
GA — JobId 8065-8099 |
snapshot (LVM/ZFS) |
Stub de código | Phase 3 — pendente lab LVM/ZFS-backed |
hot_backup (Percona createBackup) |
Stub de código | Phase 4 — pendente Percona Server lab |
| Sharded cluster orchestration | Stub de código | Phase 6 — pendente |
replicate (DR clone) |
Stub de código | Phase 7 — pendente |
4. SECONDARY-aware source picker
Backup que martela o PRIMARY é backup que custa SLA. O plugin parseia o replicaSet connection string, executa rs.status() no driver, e escolhe um SECONDARY saudável (readPreference=secondaryPreferred respeitado). Se nenhum SECONDARY estiver acessível, cai para PRIMARY com warning explícito no job log — comportamento documentado, não silencioso.
Validado em campo: JobId 7728/7996.
5. Oplog incremental — a peça que falta no Bacula Enterprise
Incrementais “de verdade” em MongoDB exigem o oplog. O plugin mantém um oplog tip persistente em /opt/bacula/working/podheitor-mongodb-<resource>-tip.json: a cada job level=I, lê o tip do job anterior, abre cursor tailable em local.oplog.rs a partir desse timestamp, e streama todos os applyOps até o tip atual.
Detecção de rotation gap é mandatória: se o oplog deu wrap entre dois jobs, o tip antigo não existe mais. O plugin detecta isso comparando o ts do primeiro entry vs o tip esperado e aborta com mensagem clara — operador deve rodar Full novo. Validado em JobId 8047-8050.
6. Point-in-time replay
Restore granular para um instante arbitrário, sem precisar restaurar a chain inteira na máquina destino:
# Por timestamp absoluto (RFC 3339)
pluginoptions "podheitor-mongodb: mode=restore pit=2026-04-15T14:30:00Z dry_run=true"
# Por contador de incremental dentro do dia
pluginoptions "podheitor-mongodb: mode=restore pit=:inc=12"
# Por segundo Unix
pluginoptions "podheitor-mongodb: mode=restore pit=1713187800"
O dry_run=true faz o plugin computar a chain (Full + N incrementais) e emite preview no job log sem aplicar — útil para operador verificar antes de executar restore destrutivo. Validado em JobId 8097/8099.
O per-restore sidecar JSON elimina a necessidade de reiniciar o FD para mudar parâmetros de restore — o sidecar é lido a cada job e descartado depois (Phase 5ε, JobId 8090/8092).
7. Manifest assinado e verificação BLAKE3
Cada backup emite um manifest JSON que catalogo o que foi salvo: lista de DBs, collections, contagens de documentos, oplog tip, topologia do replica set no momento do backup. O manifest é hashado com BLAKE3 e assinado com Ed25519 via chave configurada por env var (PODHEITOR_MONGODB_SIGNING_KEY).
No restore, o plugin verifica a assinatura antes de aplicar — protege contra tampering pós-backup (ransomware que tenta reescrever backups antes de detonar). A chave fica fora do FD; os artefatos podem ser auditados independentemente via verify-artifacts.sh.
8. Empacotamento e exporter Prometheus
v1.0 ships RPM (EL9) + DEB (Debian 12 / Ubuntu 22.04), assinados (RPM in-archive + DEB detached GPG), validados em smoke matrix de 5 distros via podman (5/5 PASS). O exporter Prometheus expõe em :9105/metrics:
podheitor_mongodb_exporter_scrapes_totalpodheitor_mongodb_backup_duration_seconds{resource}podheitor_mongodb_oplog_lag_seconds{resource}podheitor_mongodb_last_success_timestamp{resource}
O exporter roda como bacula:bacula sob unit systemd hardenizada (ProtectSystem=strict, NoNewPrivileges=yes, PrivateTmp=yes), lendo apenas os stats sidecars no working dir.
9. FileSet exemplo (replica set)
FileSet {
Name = "MongoDB-RS-Dump"
Include {
Options { Signature = SHA256 }
Plugin = "podheitor-mongodb: mode=dump uri=mongodb://backup_user@rs0-1,rs0-2,rs0-3/?replicaSet=rs0&readPreference=secondaryPreferred&authSource=admin database=* parallel_dbs=4 verify=true"
}
}
Job {
Name = "MongoDB-Backup"
Type = Backup
Client = mongo-fd
FileSet = "MongoDB-RS-Dump"
Storage = File1
Pool = Default
Schedule = "WeeklyCycle"
}
10. Versões suportadas (v1.0)
- MongoDB Community 4.4, 5.0, 6.0, 7.0, 8.0
- Percona Server for MongoDB 6.0, 7.0, 8.0 (modo
hot_backupem Phase 4 — code-stub) - MongoDB Enterprise 7.0+ (
$backupCursor) — Phase 9 / v1.5 - Bacula Community 15.0.3+ e Bacularis
11. License posture
O plugin distribui sob licença PROPRIETARY single-license. O backend nunca toca o ABI do Bacula.
Pronto para avaliar?
Trial gratuito de 30 dias para clusters MongoDB qualificados (Community, Percona, Enterprise). Garantimos no mínimo 50% de desconto vs Bacula Enterprise, Veeam ou Commvault, com mais funcionalidades inclusas — incluindo PIT replay e manifest assinado que nenhum competidor entrega out-of-the-box.
Heitor Faria — Fundador, PodHeitor International
✉ [email protected]
☎ +1 (789) 726-1749 · +55 (61) 98268-4220 (WhatsApp)
🔗 Página do plugin PodHeitor MongoDB
Disponível em:
Português
English (Inglês)
Español (Espanhol)