Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Compression zstd Décidé

Compression par chunk, en zstd, à un seul emplacement possible : entre le découpage et l'AEAD. À 2 Mio de chunk, chaque chunk se compresse pleinement seul — donc pas de dictionnaire.

Où — et quand — la compression a lieu

Dans le pipeline décidé, il n’y a qu’un seul créneau viable : par chunk, après FastCDC, après la dérivation de la clé depuis le clair, et juste avant l’AEAD.

# par chunk, sur le clair — tout est déterministe
clé_chunk = BLAKE3_keyed(secret, chunk) # clé dérivée du CLAIR
payload = compresse(chunk) # ← la compression a lieu ICI
chiffré = XChaCha20-Poly1305(clé_chunk, payload)
adresse = BLAKE3(chiffré)

La clé reste dérivée du clair, pas du compressé : la compression ne change que le payload chiffré, jamais la logique de clé ni de manifeste. Les trois autres emplacements sont exclus :

  • Compresser puis découper (CDC sur le flux compressé) → tue la dédup : la compression rend le flux positionnel, un octet modifié en tête décale tout l'aval et tous les chunks changent d'adresse. Le découpage se fait sur le clair.
  • Compresser après chiffrement → impossible : le chiffré est à entropie maximale, incompressible.
  • Par fichier plutôt que par chunk → le chunk est l'unité de dédup et de chiffrement ; on compresse chaque chunk indépendamment.

La contrainte qui domine : déterminisme figé

Le compressé doit être identique sur toute la flotte Puisque adresse = BLAKE3(chiffré) et que la dédup se fait sur l'adresse, deux machines d'un même tenant doivent produire un chiffré bit-à-bit identique pour le même chunk. La clé et le nonce le sont déjà ; reste le payload. Les octets compressés doivent donc être identiques partout, pour toujours — sinon le même chunk logique se stocke deux fois et la dédup se dégrade en silence.

En pratique, on épingle un profil de compression versionné, rangé dans la config du tenant (même discipline que les paramètres de découpage) : codec + version de zstd + niveau + framing + la règle de décision. zstd est déterministe pour un (version, niveau, params) donné, mais pas garanti stable entre versions majeures — d’où l’épinglage.

Compresser seulement si ça aide

Beaucoup de chunks sont déjà compressés (jpeg, mp4, zip, docx…). Les recompresser gâche du CPU et, par le principe des tiroirs, gonfle légèrement le résultat : zstd ajoute son framing (en-tête de frame + en-têtes de bloc), et sur du contenu incompressible il range un « raw block » ≈ taille + une dizaine d'octets.

Règle : tenter zstd, garder le compressé seulement s’il est plus petit, sinon stocker brut — avec 1 octet de flag brut|zstd à l’intérieur du payload chiffré (couvert par le tag AEAD, ne fuit pas). Cette décision fait elle aussi partie du profil épinglé : deux clients doivent trancher pareil, ou le chiffré diffère et la dédup casse.

Le codec

zstd, niveau ~3. Meilleur ratio/vitesse, déterministe, niveaux réglables. La cible inclut des NAS bas de gamme (déjà l’argument du choix d’AEAD) : on vise un niveau modéré, pas 19. lz4 serait plus rapide mais moins bon, inutile car zstd niveau bas est déjà très rapide ; brotli/xz trop lents pour du débit backup.

Dictionnaires zstd — écartés

Utiles seulement sur de petits chunks Un dictionnaire donne au compresseur un « faux historique » de contenu commun, ce qui aide énormément sur les petits chunks (peu de redondance interne, temps de chauffe). À 2 Mio de chunk, chaque chunk a déjà tout le contexte qu'il lui faut : le dictionnaire n'apporte quasi rien. Or son coût est réel — artefact à entraîner côté client, à chiffrer par tenant, à distribuer, et surtout à épingler dans le profil : en changer forke l'espace d'adresses et impose une migration.

On les écarte donc tant qu’on reste sur de gros chunks. Piste conservée si un jour un cas d’usage impose de petits chunks : rendre chaque chunk auto-descriptif (un index de profil dans le payload chiffré, un registre de profils et un objet dictionnaire chiffré par tenant), pour qu’une flotte mixte restaure toujours correctement. Hors périmètre actuel.