Le samedi 4 avril 2026, le plan de données de l'AppView de Bluesky — le backend servant les lectures de l'application sociale — a commencé à journaliser des erreurs du type « failed to set post cache item: dial tcp: bind: address already in use ». Le plan de données s'appuie fortement sur memcached pour alléger la charge de sa base Scylla principale, et Jim Calabro, l'ingénieur infrastructure d'astreinte, a constaté que les pics de journaux coïncidaient avec des creux du trafic côté utilisateur. La supervision réseau était propre, si bien que la cause est restée cachée tout le week-end pendant que le service fonctionnait tant bien que mal.

La cause racine était un nouveau service interne déployé cette semaine-là : moins de trois requêtes GetPostRecord par seconde, mais 15 000 à 20 000 URI de posts par lot (la normale étant de 1 à 50). Chaque gestionnaire RPC du plan de données borne sa concurrence avec errgroup.SetLimit — seul cet endpoint était dépourvu de cette ligne. Un seul appel engendrait jusqu'à 20 000 goroutines, déclenchant une tempête de connexions memcached ; une fois le pool d'inactivité de 1 000 sockets débordé, elles s'accumulaient en TCP TIME_WAIT et épuisaient tous les ports éphémères. Le client s'exécutait dans un seul centre de données et, faute de métriques par client, les erreurs de cache de tout type masquaient le coupable.

Le lundi 6 avril, la situation a basculé dans une spirale mortelle : avec des millions de requêtes memcached échouant par seconde, la politique de Bluesky consistant à journaliser chaque erreur a tenté des millions d'écritures de journal write(2) bloquantes par seconde. Le déluge d'appels système bloquants a fait passer le runtime Go d'environ 150 à 1 500 threads OS, affamant le GC jusqu'à de longues pauses stop-the-world. Un GOGC et un GOMEMLIMIT réglés agressivement ont fait planter périodiquement le plan de données par OOM — environ 30 minutes en marche, puis arrêt, et ainsi de suite. Chaque redémarrage aggravait le problème : les sockets en TIME_WAIT empêchaient le processus redémarré de recréer son pool memcached.

Le pansement du lundi était d'une absurdité éclatante : un dialer personnalisé qui choisissait une IP de loopback 127.x.y.z aléatoire pour chaque connexion sortante, élargissant l'espace ip+port au-delà de la plage épuisée. Cela a stoppé la spirale, et ce n'est que le mercredi que l'équipe a trouvé la véritable cause racine et rétabli le SetLimit(50) manquant. Le post-mortem public de Calabro reconnaissait aussi un échec de communication : la page de statut avait mis en cause un fournisseur de réseau tiers, ce qui « n'était clairement pas le cas ».

Une indisponibilité intermittente pour environ la moitié de tous les utilisateurs de Bluesky pendant environ huit heures le 6 avril 2026 — la pire panne de la plateforme du temps de son responsable infrastructure

La concurrence bornée était imposée par convention, non par la structure : chaque gestionnaire avait son SetLimit sauf un, et un seul endpoint non borné suffisait à épuiser les ressources de l'hôte.

Le contrat de trafic n'avait aucune limite de forme : rien ne rejetait un lot de 20 000 éléments, si bien qu'un client interne discret — 3 requêtes par seconde — surpassait des millions de clients normaux comme source de charge.

La gestion des défaillances a amplifié la panne : journaliser chaque erreur memcached à raison de millions d'erreurs par seconde a transformé un problème de cache en explosion de threads, en pauses du GC et en plantages par OOM.

L'observabilité supposait de petites requêtes et n'avait pas de métriques par client, si bien que les erreurs de chaque type de cache ont masqué l'unique appelant et l'unique endpoint responsables pendant des jours.

Le redémarrage comme mode de rétablissement était défaillant : les sockets en TIME_WAIT du processus mort empêchaient le nouveau processus de reconstruire ses pools memcached, transformant les redémarrages après OOM en nouvel épuisement de ports.

Une seule boucle de goroutines non bornée a pesé plus lourd que toutes les autres protections. Les limites de concurrence doivent être structurelles, et non une habitude par endpoint : l'unique endpoint qui en était dépourvu est devenu toute la panne.

Le service a été stabilisé le lundi grâce au dialer à loopback aléatoire, qui a été retiré une fois le vrai correctif — le rétablissement de la limite de concurrence — déployé le mercredi 8 avril. L'exposition totale a été d'environ huit heures d'indisponibilité intermittente pour environ la moitié des utilisateurs. Le post-mortem, publié le 10 avril 2026, promettait une observabilité par client, la détection des clients envoyant un petit nombre de requêtes surdimensionnées, et un passage d'une journalisation à fort volume vers des métriques Prometheus et du traçage OpenTelemetry ; il a fait l'objet d'une analyse indépendante détaillée par la chercheuse en fiabilité Lorin Hochstein deux jours plus tard.

VÉRIFIEZ LES SOURCES

Les sources

  1. April 2026 Outage Post-Mortem Jim Calabro (Bluesky infrastructure engineer), pckt.blog · pckt.blog ·
  2. Thoughts on the Bluesky public incident write-up Surfing Complexity (Lorin Hochstein) · surfingcomplexity.blog ·
  3. Bluesky April 2026 Outage Post-Mortem (discussion, 141 points) Hacker News · news.ycombinator.com ·