Ce qui se passe
ZippyDB est le magasin clé-valeur le plus utilisé de Meta : métadonnées produit, compteurs, configuration, plus d'un milliard d'opérations par seconde. Jusqu'à présent, chaque client s'y connectait directement — et un client peut être l'une de plus d'un million de machines, appartenant à des centaines d'équipes qu'on ne met pas à jour d'un claquement de doigts.
Le maillage qui en résulte est dense : un client typique tient des dizaines de milliers de connexions sortantes, un hôte de base en accepte autant en entrée. Chacune consomme mémoire, CPU et descripteur de fichier, la plupart du temps sans rien faire.
Meta raconte l'incident qui va avec : un bug de routage a conduit chaque client à ouvrir une connexion par shard, les hôtes ont dépassé leur limite de descripteurs, et la flotte est entrée en boucle de redémarrage.
L'argument n'est pas le gain, c'est l'exposant
En accès direct, le fan-in d'un hôte de base est proportionnel à la population de clients : chaque nouvelle cohorte dégrade tous les hôtes. Derrière ZGateway, il se réduit approximativement au nombre de régions multiplié par la densité de shards par hôte — deux valeurs que l'équipe de la base contrôle. La population de clients disparaît de l'équation.
Les chiffres du modèle (20 régions, 500 000 hôtes de base, 30 000 hôtes proxy, 1 000 000 de clients, 50 000 shards par client) donnent une chute de 97 à 98 % des connexions par hôte, et 19 fois moins de connexions persistantes au total, puisqu'une connexion backend multiplexe désormais plusieurs clients.
Le prix est annoncé, ce qui rend le billet utilisable : ZGateway porte environ 40 % du trafic ZippyDB (projeté au-delà de 60 %) pour ~6 % de surcoût de calcul, plus un saut réseau et un étage supplémentaire à exploiter.
Ce que seul un étage partagé peut faire
Un batcher client ne regroupe que les requêtes de son propre processus. Le proxy, lui, voit passer tout le monde :
- Batching : les requêtes vers un même shard (clé : cas d'usage + shard physique) sont fusionnées en un seul RPC backend, ce qui amortit sérialisation Thrift, résolution de shard, autorisation et appels système.
- Coalescing : si mille appelants demandent la même clé au même instant, la lecture backend est faite une fois — une clé chaude ne peut plus provoquer de ruée sur une réplique. Un cas d'usage étant facturé au QPS émis, le batching étire aussi son quota sans travail de sa part. Deux garde-fous encadrent la mise en mémoire : éviction des entrées inactives au-delà d'un TTL, et plafond de lots en vol.
L'isolement, mesuré
Un étage partagé sert des centaines de locataires : un seul emballement ne doit pas affamer les autres. ZGateway applique un Discriminant Load Shedding — un bucket par locataire et par priorité, vidés en tourniquet, devancé par un contrôleur de concurrence CPU en AIMD.
En surcharge contrôlée au-delà de 90 % de CPU, sur environ 1 350 buckets actifs, 6 seulement étaient délestés ; les ~1 344 autres exécutaient 99,9 % de leurs requêtes sans rejet, pour un goodput de 97 à 98 % et un coût de mécanisme d'environ 8 % de CPU.
Ce qu'on en retient hors de Meta
L'échelle n'est pas la vôtre, le raisonnement l'est. C'est celui qui justifie un PgBouncer devant Postgres, ou un pooler devant n'importe quelle base dont la population de clients grandit plus vite qu'elle.
- Regardez si votre fan-in est proportionnel au nombre de clients : c'est ce terme-là qu'un proxy supprime, pas seulement un nombre de connexions.
- Un étage partagé est le seul endroit où batching, coalescing et délestage par locataire peuvent être écrits une fois, au lieu de vivre dans chaque client.
- Chiffrez le prix avant : un saut de plus, ~6 % de calcul, et une migration qui doit rester progressive et réversible — chez Meta, un pourcentage de trafic, un filtre régional et un coupe-circuit, en pure configuration.
Source : Engineering at Meta