Un binaire, un bucket : quand construire des services sur du stockage objet

Par Diogo Hudson Dias
Senior engineer drawing an architecture with a single service backed by cloud object storage on a glass wall in a modern office.

Vous pouvez désormais livrer des services entiers avec un seul binaire stateless et un bucket. Pas de base de données. Pas de file. Pas de volumes blocs. Juste du stockage objet. Ces dernières semaines, des posts Show HN comme des serveurs Git légers au‑dessus de stores type S3, des flux durables sur HTTP adossés à du stockage objet, et des bibliothèques auto‑hébergées qui tournent entièrement sur des buckets ont été en tendance. Ce n’est pas un bricolage de nouveauté. C’est un patron d’architecture qui dispose enfin des primitives pour être de niveau production — si vous l’appliquez là où il convient.

Si vous êtes CTO et cherchez à réduire le blast radius de votre infra et le risque fournisseur, ce modèle mérite d’être sérieusement étudié. Mais ce n’est pas une religion. C’est un compromis délibéré : vous échangez des latences < 10 ms et des transactions ACID contre une durabilité extrême, de la portabilité et une simplicité opérationnelle. Ci‑dessous, un cadre de décision et quelques chiffres concrets pour décider où « un binaire, un bucket » a sa place dans votre stack.

Pourquoi c’est viable maintenant

  • La cohérence forte est là. Depuis 2020, les principaux stockages objet comme Amazon S3 offrent une cohérence lecture‑après‑écriture forte pour PUT, DELETE et LIST. Vous n’avez plus à contourner l’éventuelle cohérence pour du CRUD basique.
  • Coût et portabilité en progrès. Les requêtes S3 sont peu coûteuses au million, Cloudflare R2 a supprimé les péages d’egress, et les API compatibles S3 (MinIO, R2, Wasabi) rendent le « déplacer votre bucket ailleurs » une vraie couverture.
  • L’edge et le serverless ont mûri. Les endpoints VPC, les caches edge régionaux et le compute à la requête permettent de garder des latences raisonnables sans une ferme de serveurs stateful.

Ce que « un binaire, un bucket » signifie concrètement

Des patterns que vous verrez :

  • Journaux en ajout‑seulement (append‑only). Les événements sont écrits sous forme d’objets immuables partitionnés par temps ou shard. Les consommateurs listent et lisent des plages ; une compaction périodique fusionne les petits fichiers.
  • Blobs adressés par contenu. Artefacts, images, poids de modèles ou packfiles adressés par leur hash ; les index sont de petits manifestes.
  • Pointeurs de snapshot. Un minuscule manifeste « latest » pointe vers des objets immuables représentant l’état courant ; les mises à jour sont sérialisées via un writer unique ou un lease.
  • Formats lisibles par plages. Stockez Parquet, des packfiles ou des bundles type tar afin de servir de petites tranches via HTTP Range au lieu de créer des millions de petits objets.

Le fil conducteur : immuabilité d’abord, compaction ensuite, pointeurs en dernier.

Où ce modèle excelle

  • Traces d’audit réglementées et exigences WORM. Object Lock et le versioning vous donnent une sémantique écrire‑une‑seule‑fois, conserver N années, prête à l’emploi. Si vous vivez sous des obligations de type SEC 17a‑4 ou avez besoin d’une immuabilité prouvable, c’est votre allié.
  • Registres d’artefacts et médiathèques. De gros blobs immuables avec des mises à jour de métadonnées occasionnelles : c’est exactement le cas d’usage des buckets.
  • Taux d’écriture faibles à modérés avec lectures en rafales. 5–50 écritures/s par service avec un fan‑out de lecture 10–100x est confortable, surtout si vous batcher les écritures et mettez les lectures en cache.
  • Couverture multi‑cloud. Envie d’exécuter le même service sur AWS, GCP ou on‑prem ? Les API compatibles S3 plus un binaire stateless rendent la portabilité réelle.

Où ça fait mal

  • Compteurs chauds et état à forte contention. Pas d’incréments atomiques ni de transactions multi‑lignes. Si vous avez besoin d’ACID, il vous faut toujours une base de données.
  • Latence de queue < 20 ms. Le p50 typique des GET d’objets se situe à quelques dizaines de millisecondes ; le p99 peut atteindre 100–400 ms. Avec du cache, vous en masquez une partie, pas tout.
  • Très hauts débits d’écritures de tout petits objets. Les coûts par requête et la surcharge de métadonnées peuvent dépasser les coûts de stockage si vous matraquez le bucket avec des milliers d’objets par seconde.

Le calcul de coûts que la plupart des équipes zappent

Modélisons les versions naïve et raisonnable d’un service de type file adossé à un bucket.

Naïf : un objet par message

  • Taux d’écriture : 200 messages/s (modéré).
  • Taux de lecture : 1000 lectures/s (fan‑out 5x).
  • Opérations mensuelles : ~518 millions d’écritures, ~2,6 milliards de lectures.
  • En utilisant des prix S3 typiques par requête : 0,005 $ par 1000 PUT ; 0,0004 $ par 1000 GET.

Coût : écritures ≈ 518,400k / 1k × $0.005 = $2,592/mois ; lectures ≈ 2,592,000k / 1k × $0.0004 = $1,037/mois. Total ≈ $3,629/mois en frais de requêtes seuls, hors stockage. Ce n’est pas catastrophique, mais c’est du gaspillage — parce que vous payez par minuscule objet.

Raisonné : batcher et empaqueter

  • Batch des écritures : 100 messages par objet → 2 écritures/s au lieu de 200.
  • Lectures par plages : lisez des messages spécifiques via des offsets dans un bundle de 8–64 MB ; mettez les bundles en cache à l’edge.
  • Opérations mensuelles : ~5,18 millions d’écritures, les lectures chutent de 10–100x avec le cache.

Coût : écritures ≈ 5,184k / 1k × $0.005 = ~$26/mois ; lectures peut‑être ~$100–$300/mois selon le taux de hit. Bilan : 10–50x moins cher en frais de requêtes. Les coûts de stockage changent à peine.

La leçon : avec le stockage objet, la granularité fait votre budget. Si vous ne pouvez pas batcher, vous payerez.

Latence, parlons vrai

Supposons un accès dans la région via un endpoint VPC :

  • GET p50 : 10–30 ms est typique.
  • GET p95–p99 : des pointes à 100–400 ms arrivent. Concevez en conséquence.
  • PUT p50 : 10–50 ms ; le p99 peut flirter avec quelques centaines de ms.

Si vous avez besoin d’une queue à un chiffre de millisecondes pour les chemins chauds, ce n’est pas le bon outil. Si vous pouvez cacher les queues derrière du cache et du travail asynchrone, vous êtes bien.

Modèle de cohérence et de concurrence

Les grands buckets d’aujourd’hui vous donnent une cohérence forte lecture‑après‑écriture pour les nouveaux objets et les overwrites. Vous pouvez faire confiance à un LIST après un PUT. Vous ne pouvez pas faire du bucket votre gestionnaire de verrous. Des patterns que nous avons vus fonctionner de façon fiable :

  • Un seul writer par shard avec un lease stocké dans un KV rapide (DynamoDB/etcd). Le bucket stocke des objets immuables ; le KV protège le petit pointeur mutable.
  • Commits par manifeste. Écrivez vos données dans un nouvel objet adressé par contenu, puis mettez à jour un petit manifeste qui y pointe. Sérialisez les mises à jour du manifeste via un writer unique ou un lease.
  • Écritures idempotentes via hachage. Utilisez le SHA‑256 du payload comme clé pour éviter les doublons en cas de retries.

Pourriez‑vous tenter un compare‑and‑swap sur un objet pointeur dans le bucket ? Pas de façon portable. Gardez vos verrous dans un KV conçu pour cela, et gardez vos données immuables dans le bucket.

Modèles d’architecture qui tiennent en production

1) Disposition pour le batching et la compaction

  • Partitionner par temps et shard : p. ex., topic=orders/partition=03/dt=2026-08-25/0001.parquet.
  • Écrire petit, compacter plus tard : émettez des objets de 1–8 MB à l’ingest pour la latence, puis compactez chaque heure en objets de 64–256 MB pour réduire fortement les frais de requêtes et de listing.
  • Utiliser des formats amicaux aux plages : Parquet, packfiles, bundles type tar avec un pied d’index afin que les lectures ne récupèrent que les plages nécessaires.

2) Un petit KV pour le plan de contrôle

  • Stocker pointeurs, leases et numéros de séquence dans un KV avec écritures conditionnelles. Limitez‑le à quelques centaines d’écritures/s.
  • Tout le reste est immuable et vit dans le bucket. Si ça bouge ou mute, c’est que vous le faites mal.

3) Caching agressif

  • CDN edge pour les lectures avec des TTL longs et invalidation par clés versionnées.
  • Cache NVMe local dans le binaire pour les bundles chauds et les entrées de compaction.
  • URLs pré‑signées afin que les clients puissent télécharger de gros blobs directement depuis le bucket sans transiter par votre binaire.

4) Garde‑fous de coûts

  • Alertes budgétaires sur les compteurs de requêtes, pas seulement le transfert et le stockage.
  • Abandon automatique des uploads multipart incomplets ; sinon vous fuirez du stockage et de l’argent.
  • Rotation des préfixes pour limiter le coût des listings dans d’énormes répertoires ; évitez de lister le monde à chaque requête.

5) Sécurité et conformité

  • Buckets privés avec endpoints VPC pour éviter l’egress public et réduire la surface d’attaque.
  • SSE‑KMS pour le chiffrement avec des clés par tenant si vous êtes multi‑tenant.
  • Object Lock (mode governance ou compliance) pour les jeux de données à rétention critique.
  • Access logs et CloudTrail activés ; conservez ces logs dans un bucket séparé et verrouillé.

Cas d’usage qui fonctionnent vraiment

  • Magasins de contenu de type Git. Mettez des packfiles et des refs dans le bucket ; sérialisez les mises à jour de refs dans un KV. Un petit binaire traduit le protocole Git wire en opérations sur le bucket. C’est exactement ce que font plusieurs nouveaux serveurs Git légers sur HN.
  • Flux d’événements durables sur HTTP. Les messages sont stockés dans des bundles partitionnés par temps ; les consommateurs paginent dans les bundles via des requêtes Range. La latence est de quelques dizaines à quelques centaines de millisecondes, mais la durabilité est extrême et l’exploitation est simple.
  • Médias, modèles et artefacts. Embrassez l’immuabilité. Utilisez l’adressage par contenu ; ne réécrivez jamais les vraies données, seulement des manifestes.
  • Snapshots de feature flags et configuration. Un seul pointeur vers la config active, servie via CDN ; des bundles de config dans le bucket ; un KV coordonne le basculement de pointeur.

Où cela déraille dans la nature

  • Traiter les buckets comme du POSIX. Pas de renommage atomique, pas de verrous de répertoire, et le listing est lent si vous déposez 100 millions d’objets dans un seul préfixe.
  • Tempêtes de petits objets. Si vous êtes en‑dessous de ~1 MB par objet en moyenne et poussez des centaines d’écritures/s, les coûts de requêtes vous mangeront.
  • LIST sans borne dans des chemins chauds. Ayez toujours des jetons de continuation ; ne faites jamais de LIST au‑delà du nécessaire ; mieux, lisez depuis un manifeste ou un index.
  • Illusions inter‑région. La latence de réplication est réelle. Ne bâtissez jamais une coordination inter‑région en comptant sur une réplication qui rattrape.

Portabilité et réalités fournisseurs

L’API S3 est le standard de facto, mais les sémantiques diffèrent en bordure :

  • Cohérence : S3 a de la lecture‑après‑écriture forte ; certains fournisseurs historiquement non pour LIST. Vérifiez en staging.
  • Tarification egress et requêtes : Cloudflare R2 a supprimé les péages d’egress, mais les classes de requêtes sont tarifées différemment de S3. Faites le calcul avant de courir après le « no egress ».
  • On‑prem : MinIO est excellent pour des sémantiques S3 dans votre propre DC ou des régions in‑country lorsque la LGPD ou des contrats client imposent une résidence des données au Brazil.

Un cadre de décision applicable dès cette semaine

Notez votre charge candidate sur chaque axe de 1 (mauvais fit) à 5 (excellent fit) :

  1. Taux d’écriture et granularité. Moins de 10 écritures/s en moyenne et batchable en objets de 1–8 MB ? Note 5. Des centaines de petites écritures/s impossibles à batcher ? Note 1.
  2. Tolérance à la latence. OK avec des lectures à 50–150 ms et des queues occasionnelles à 200–400 ms ? Note 5. Besoin d’un p99 < 20 ms ? Note 1.
  3. Immutabilité d’abord. 95 % de vos données sont en ajout‑seulement ? Note 5. La plupart sont des lignes chaudes et mutables nécessitant des transactions ? Note 1.
  4. Rétention réglementaire. Besoin de WORM ou d’une rétention prouvable ? Note 5. Pas de pression de conformité ? Note 3. Besoin d’effacements/mises à jour fréquents ? Note 1.
  5. Valeur de la portabilité. Une couverture multi‑cloud ou on‑prem compte ? Note 5. Vous êtes all‑in sur un service managé unique de toute façon ? Note 2.

Si vous obtenez 18–25 : excellent candidat pour un service adossé à un bucket. 12–17 : envisagez un hybride : données immuables dans des buckets, pointeurs/verrous dans un KV/DB. En‑dessous de 12 : restez sur des bases de données et des files.

Un plan pilote 30–60–90 jours

30 jours : prouver le cœur

  • Choisissez une charge : magasin d’artefacts, journal d’audit, ou un service de config majoritairement en lecture.
  • Construisez un binaire stateless unique en Go ou Rust avec une API minimale : PUT bundle, GET par clé ou par plage, LIST par manifeste.
  • Sous‑tendez‑le avec un store compatible S3 en staging (AWS S3 ou MinIO), plus un petit KV (DynamoDB/etcd) pour les leases et pointeurs.
  • Instrumentez le nombre de requêtes, les latences p50/p95/p99 et les tailles de bundles.

60 jours : durcir

  • Ajoutez la compaction et des index de bundles pour plafonner les coûts de requêtes.
  • Mettez un CDN devant les GET ; passez aux URLs pré‑signées pour les gros téléchargements.
  • Activez le versioning et Object Lock en mode governance pour les jeux de données d’audit.
  • Lancez des tests de cohérence en cas de crash : tuez le process en milieu de commit 1000 fois ; vérifiez qu’aucun état partiel ne s’échappe.

90 jours : décider

  • Comparez coût/latence observés à une conception équivalente adossée à une base.
  • Décidez du périmètre : étendre à plus de services orientés lecture, ou le garder pour artefacts et logs uniquement.
  • Écrivez le runbook : SLOs de compaction, politiques de cycle de vie du bucket, plannings d’abandon multipart, et alertes budgétaires.

Comment nous le stafferions avec un pod nearshore

Pour des startups US, un pod nearshore de deux à trois personnes basé au Brazil peut porter ceci de bout en bout :

  • 1 ingénieur senior Go ou Rust pour implémenter le binaire, l’I/O par plages et la compaction.
  • 1 ingénieur plateforme pour câbler politiques S3, endpoints VPC, KMS et CDN.
  • Data engineer optionnel si vous avez besoin de formats Parquet/colonnaires et d’analytique aval.

Comptez 6–8 heures de recouvrement avec les fuseaux US, et une fenêtre totale de 8–12 semaines pour passer du POC à un service durci avec SLOs et garde‑fous de coûts.

L’essentiel

« Un binaire, un bucket » n’est pas un coup. C’est un levier opérationnel : livrez des systèmes plus simples en misant sur l’immuabilité, le batching et la durabilité que le stockage objet vous offre gratuitement. Utilisez‑le quand la physique de votre workload colle à la physique du bucket. Quand l’adéquation est bonne, vous économisez 20–50 % d’infra, réduisez la surface opérationnelle, et vous offrez une vraie couverture multi‑cloud. Quand l’adéquation est mauvaise, vous construisez un cosplay de système de fichiers lent et coûteux. Choisissez avec discernement.

Points clés

  • Les services adossés à du stockage objet sont désormais prêts pour la prod grâce à la cohérence forte et à la maturité de l’edge/serverless.
  • Excellents fits : données immuables, audit/WORM, artefacts, et taux d’écriture faibles à modérés pouvant être batchés.
  • Mauvais fits : état transactionnel chaud et exigences de queue < 20 ms.
  • La granularité pilote le coût — regroupez en bundles de 1–64 MB et compactez pour éviter l’explosion des frais de requêtes.
  • Gardez verrous et pointeurs dans un vrai KV ; gardez les données immuables dans le bucket.
  • Utilisez le versioning, Object Lock, des endpoints VPC, KMS et un CDN pour durcir sécurité et performance.
  • Menez un pilote 30–60–90 jours avec des SLOs stricts et des alertes budgétaires avant de vous engager.

Auteur : Diogo Hudson Dias

Ready to scale your engineering team?

Tell us about your project and we'll get back to you within 24 hours.

Start a conversation