Petits fichiers : quelles causes côté stockage et quels remèdes ?

Questions d’entrevue Formats et stockage

Intermédiairepetits-fichierscompactionstockage

La réponse courte

Côté stockage, un petit fichier n’est pas un problème Spark : c’est un objet trop léger pour le modèle économique d’un object store et d’un format à pied de fichier. Lister 400 000 clés, ouvrir 400 000 footers Parquet, payer 400 000 GET, pour 12 Go utiles : le listing et les métadonnées coûtent plus cher que les octets.

Les causes qui naissent dans le lac, pas dans l’exécuteur :

  1. Ingestion continue. Un micro-lot ou un flush toutes les minutes, un fichier par lot, parfois un par partition Hive. En une semaine : des dizaines de milliers d’objets par table chaude.
  2. Trop de feuilles de partition. Une cardinalité trop haute (voir la question sur les identifiants) multiplie les dossiers ; chaque dossier reçoit un fichier squelettique.
  3. Plusieurs écrivains sans coordination. Chaque job, chaque pod, chaque stream pose son objet. Sans table transactionnelle, on n’a même pas le droit de les fusionner tranquillement.
  4. Copies et retries. Un job qui réécrit une partition en laissant les orphelins double le compte.

Les remèdes sont des services de table, pas un « on écrira mieux un jour » :

  • Compaction / OPTIMIZE / rewrite_data_files : relire les petits, réécrire des bin-packs de 128 Mo–1 Go, commit atomique dans le journal.
  • Taille cible à l’écriture : auto optimize, optimized writes, roll de fichiers côté streaming (Flink, Kafka Connect, ingestion Databricks).
  • Moins de partitions, clustering plutôt que dossiers.
  • Rétention des orphelins (VACUUM, expiration des snapshots Iceberg) pour que la compaction ne laisse pas l’ancien petit à côté du nouveau gros.

Ce que l’intervieweur vérifie

Que vous parlez d’objets et de listing, pas seulement de « trop de tâches ». Sur S3, LIST n’est pas gratuit, n’est pas infiniment parallèle, et un catalog qui doit statuer 200 000 fichiers au planning d’une requête SQL met le coordinateur à genoux — Trino, Athena, Spark driver, c’est le même symptôme.

La relance : « on compacte à chaque micro-lot ? » Non. On accumule puis on compacte par vague (toutes les heures, tous les 512 Mo en attente, par partition du jour). Compacter en continu sans seuil recrée de la contention et des commits trop fréquents.

Deuxième relance : « Delta OPTIMIZE suffit-il ? » Il réécrit les données. Il ne change pas le producteur. Si le stream continue de poser 2 000 fichiers à l’heure, vous compactez un tapis roulant. Il faut les deux : moins de fichiers à l’arrivée, et une compaction de rattrapage.

Le piège

Mesurer le succès au nombre de fichiers sans regarder la latence d’ingestion. Une compaction trop agressive sur une table MERGE toutes les minutes bloque ou renchérit les écritures (copy-on-write). Et à l’inverse, attendre « le weekend » sur une table de faits qui sert le matin : le dashboard de 8 h lit encore les petits de la nuit.

Le diagnostic à énoncer : compter les objets par préfixe, la taille p50/p90, le temps de LIST / de planification, puis seulement le temps de scan. Si la planification dure 40 s et le scan 8 s, vous n’avez pas un problème de CPU.

Toutes les questions Formats et stockage