Publicat în

De ce backup-urile tale sunt prea mari: ghid practic pentru Content-Defined Chunking

Schimbi o singură linie într-un fișier de 50 GB. Backup-ul „incremental” re-încarcă tot fișierul. Nu e vina rețelei, nici a backend-ului de storage. E vina algoritmului care decide unde să taie datele în bucăți. Majoritatea sistemelor de deduplicare folosesc chunking de dimensiune fixă — și aici apare problema. Content-Defined Chunking (CDC) rezolvă exact asta: taie datele pe granițe logice, nu pe dimensiuni arbitrare. Rezultatul? Reducere de 10x, 50x, uneori 100x a dimensiunii backup-urilor incrementale. Să vedem cum funcționează și cum îl implementezi corect.

Problema chunking-ului de dimensiune fixă

Sistemele tradiționale de deduplicare (rsync, tar + gzip, backup-uri la nivel de bloc) împart datele în chunk-uri de mărimi fixe — de obicei 4 KB, 8 KB, 64 KB sau 128 KB. Când modifici datele din mijlocul unui fișier mare, toate chunk-urile de după modificare se deplasează. Hash-urile lor se schimbă. Sistemul de deduplicare le vede ca pe date noi.

Imaginează-ți un fișier CSV de 10 GB cu date de tranzacții. Adaugi un rând nou la început. Cu chunking de 64 KB, toate cele ~160.000 de chunk-uri se deplasează. Backup-ul incremental devine de facto un backup complet.

Aceasta nu e o problemă teoretică. În mediile de producție cu bazele de date PostgreSQL/MySQL, fișiere VMDK/VHDX, containere Docker, sau logs structurate, backup-urile „incrementale” consumă 80-95% din spațiul unui backup complet. Costurile de storage și bandwidth cresc liniar cu frecvența backup-urilor, nu cu volumul schimbărilor reale.

Cum funcționează Content-Defined Chunking

CDC nu taie la offset-uri fixe. Calculează un hash rolling (de obicei Rabin fingerprint sau Gear hash) pe o fereastră glisantă de 32-64 bytes. Când hash-ul îndeplinește o condiție specifică — de exemplu, ultimii N biți sunt zero — declara o graniță de chunk.

# Exemplu conceptual: Rabin fingerprint pe fereastră de 48 bytes
# Graniță când ultimii 13 biți == 0 (chunk mediu ~8 KB)
# Min chunk: 1 KB, Max chunk: 64 KB

Avantajul fundamental: granițele se deplasează împreună cu conținutul. Dacă inserezi 100 bytes la începutul fișierului, doar chunk-urile locale se regenerază. Restul rămâne identic — aceleași hash-uri, aceeași deduplicare.

Algoritmii moderni folosesc:

  • Rabin fingerprint (restic, borgbackup) — robust, matematic bine înțeles
  • Gear hash (kopia, zpaq) — mai rapid pe CPU moderne, SIMD-friendly
  • FastCDC (Facebook, 2016) — optimizat pentru throughput, folosește Gear hash + normalizare

Parametrii critici: | Parametru | Valoare tipică | Impact | |––––|–––––-|–––| | Min chunk size | 1-4 KB | Previne fragmentarea excesivă | | Max chunk size | 64-256 KB | Limitează overhead-ul de metadata | | Target chunk size | 8-64 KB | Echilibru dedup/throughput | | Mask bits (N) | 13-16 biți | Controlează dimensiunea medie |

Instrumente practice: restic, borg, kopia — ce să alegi

Toate cele trei implementează CDC nativ. Diferențele contează în producție.

restic — cel mai matur pentru echipe mici/mijlocii. CDC bazat pe Rabin (target 8 MB, min 512 KB, max 16 MB — notă: restic folosește chunk-uri mari de default pentru throughput). Repo local, S3, B2, Azure, GCS, SFTP. Criptare AES-256 + Poly1305. Lock-free pentru citire, lock-uri pentru scriere. Comenzi esențiale:

# Init repository
restic -r s3:s3.amazonaws.com/bucket-name init

# Backup cu CDC (implicit)
restic -r s3:bucket backup /var/lib/postgresql/data --tag "pg-daily-$(date +%F)"

# Verifică deduplicarea
restic -r s3:bucket stats --mode raw-data
# Raw Data: 2.3 TB, Stored: 180 GB (dedup 92%)

borgbackup — CDC Rabin cu parametri fin tunabili (--chunker-params). Compresie LZ4/ZSTD/LZMA per-chunk. Repository local sau remote via SSH. Foarte bun pentru backup-uri locale pe discuri rotative sau NAS.

# Parametri CDC custom: target 1 MB, min 100 KB, max 4 MB
borg create --chunker-params 100,23,21,4096 \
  --compression lz4 \
  repo::backup-{now:%Y-%m-%d} /data

kopia — cel mai rapid pe hardware modern (ARM64, AVX2/NEON). Gear hash + FastCDC. UI web integrată, policy-based retention, maintenance automat. Ideal pentru Kubernetes (operator dedicat) și medii multi-tenant.

# kopia policy pentru PostgreSQL
policies:
  - name: pg-daily
    schedule: "0 2 * * *"
    sources:
      - path: /var/lib/postgresql/data
    retention:
      keepLatest: 30
      keepDaily: 7
      keepWeekly: 4
      keepMonthly: 12

Pentru infrastructură dedicată în România, dedicated-servers.ro oferă servere cu NVMe locale și bandwidth 10 Gbps — ideal pentru repository-uri restic/borg locale cu replicare cross-datacenter. Dacă preferi soluții cloud-managed, serverspan.ro are instanțe GPU/CPU optimizate pentru workload-uri de backup compresat.

Optimizări pentru workload-uri reale

Baze de date (PostgreSQL, MySQL, MongoDB)

Nu face backup la fișierele .ibd / .frm / WAL direct. Folosește pg_dump / mysqldump / mongodump cu --single-transaction → stdout → pipe în restic/borg. CDC funcționează pe stream, nu pe fișiere fizice.

pg_dump -Fc -Z0 --no-sync db_name | restic -r repo backup --stdin --stdin-filename db.dump

-Z0 dezactivează compresia pg_dump (restic/borg fac compresia per-chunk mai eficient). --no-sync evită fsync în timpul dump-ului.

Fișiere VMDK/VHDX (VM-uri)

Activează changed block tracking (CBT) la nivel de hypervisor (VMware CBT, Hyper-V RCT). Backup-ul incremental la nivel de bloc + CDC la nivel de fișier = best of both worlds. Restic 0.17+ are suport experimental pentru CBT via plugin-uri.

Containere Docker

Backup la volume, nu la overlay filesystem. Montează volumul într-un container helper:

docker run --rm -v app_data:/data -v restic-repo:/repo restic/restic \
  -r /repo backup /data --tag "docker-app-$(date +%F)"

Log-uri structurate (JSON, NDJSON)

CDC e extrem de eficient aici — granițele coincid cu boundary-urile de obiecte. Target chunk 1-4 MB funcționează bine.

Metrice pe care trebuie să le monitorizezi

| Metrică | Target | Alertă dacă | |–––|–––|––––-| | Deduplication ratio | > 10x (incremental) | < 3x pentru 2 backup-uri consecutive | | Chunk index size | < 2% din data stored | > 5% (prea multe chunk-uri mici) | | Backup duration | < RPO window | > 1.5x mediană ultimele 7 zile | | Restore test duration | < RTO | orice eșec sau > 2x baseline |

Rulează restic stats --mode raw-data zilnic. Graficează ratio-ul. O scădere bruscă indică fie o schimbare de workload (reindexare DB, rotire log-uri aggressive), fie o problemă la chunker (parametri incorecti, fișiere sparse).

Pași practici de implementat azi

  1. Auditează backup-ul curent — rulează restic stats sau borg info pe ultimele 3 backup-uri; notează ratio-ul de deduplicare
  2. Testează CDC pe un subset — backup-ează un singur volum non-critic cu restic/borg/kopia; compară dimensiunea repo vs. backup anterior
  3. Ajustează parametrii chunker — pentru DB dump-uri: target 1-4 MB; pentru VM images: target 8-16 MB cu CBT; pentru logs: target 1-2 MB
  4. Automatizează verificarea — script care rulează restic check --read-data-subset=5% săptămânal și alertează pe eșec
  5. Documentează restore procedure — test trimestrial complet, test lunar partial (un singur fișier/tabelă)

–

Content-Defined Chunking nu e magică — e matematică aplicată corect. Diferența între un backup incremental de 50 GB și unul de 500 MB pentru aceeași modificare de o linie e alegerea algoritmului de chunking. Dacă încă folosești rsync, tar, sau backup-uri la nivel de bloc fără CDC, plătești storage și bandwidth inutil. Migrează azi. Costul e zero (instrumentele sunt open source), câștigul e măsurabil de mâine.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *