Aller au contenu
Ingénierie · 5 min de lecture

Plafonnez chaque file avant qu'elle ne remplisse votre disque

L'affirmation Chaque file de votre système — la file de tâches, le tampon de messages, l'arriéré de reprises, la liste en mémoire du travail en attente — a une taille maximale, et...

A Rédigé par Administrator
Plafonnez chaque file avant qu'elle ne remplisse votre disque

L'affirmation

Chaque file de votre système — la file de tâches, le tampon de messages, l'arriéré de reprises, la liste en mémoire du travail en attente — a une taille maximale, et si vous n'avez pas choisi ce maximum, c'est ce que votre mémoire ou votre disque permet, découvert au pire moment possible. Une file sans borne n'empêche pas la surcharge ; elle la retarde et l'amplifie, convertissant une période de forte charge en un épuisement de ressources qui fait tomber tout le système. Une file bornée qui rejette le travail quand elle est pleine est un système qui se dégrade ; une file sans borne est un système qui s'effondre.

Pourquoi les files sans borne échouent pire que la charge qu'elles absorbent

Une file existe pour lisser un décalage entre la vitesse d'arrivée du travail et la vitesse de traitement. Quand l'arrivée dépasse brièvement le traitement, la file retient l'excédent jusqu'à ce que le processeur rattrape — ce à quoi sert exactement une file, et cela fonctionne bien tant que le déséquilibre est temporaire. La défaillance survient quand le déséquilibre n'est pas temporaire : le travail continue d'arriver plus vite qu'il n'est traité, la file grossit sans limite, et désormais, au lieu d'un ralentissement, vous avez une file qui consomme toute la mémoire ou tout le disque disponible jusqu'à ce que le processus soit tué ou que le disque se remplisse et que tout ce qui doit écrire échoue d'un coup.

La file sans borne a pris une condition survivable — plus de travail que vous ne pouvez traiter maintenant — et l'a convertie en une condition non survivable : un épuisement de ressources qui fait échouer tout le système, y compris tout le travail qui n'avait rien à voir avec la surcharge. Elle n'a pas absorbé le problème ; elle l'a accumulé et l'a fait détoner.

Une file bornée force une décision au bon moment

Fixer une taille maximale vous force à répondre, d'avance et calmement, à la question que la file sans borne répond pour vous de façon catastrophique : que devrait-il arriver quand plus de travail arrive qu'on ne peut en traiter ? Une file bornée vous fait décider le comportement de rejet délibérément :

queue = Queue(maxsize=10_000)   # pas illimite

try:
    queue.put(job, block=False)
except QueueFull:
    # une decision qui vous revient, au lieu d'une prise pour vous :
    reject_with_backpressure(job)   # dire a l'appelant de ralentir / reprendre plus tard

Quand la file est pleine, vous rejetez le nouveau travail — et rejeter est une fonctionnalité, pas une défaillance. L'appelant apprend immédiatement que le système est saturé et peut réagir sensément : ralentir, reprendre plus tard, délester sa propre charge. C'est la contre-pression, et c'est ainsi qu'un système bien bâti communique « je suis à pleine capacité » au lieu d'accepter en silence un travail qu'il ne peut pas faire jusqu'à en mourir.

Choisissez le comportement de rejet selon le travail

Que faire du travail rejeté dépend de ce qu'est le travail, et le choix compte :

  • Rejeter et signaler l'appelant. Pour les requêtes synchrones, renvoyez un statut « réessayer plus tard » pour que l'appelant se retire. C'est le bon choix par défaut pour le travail vu par l'utilisateur — un refus clair et immédiat vaut mieux qu'une requête acceptée qui n'aboutit jamais.
  • Jeter le plus ancien. Pour les flux où seules les données récentes comptent — mesures en direct, mises à jour de position — écarter l'élément le plus ancien pour faire place au plus récent garde les données les plus fraîches en mouvement et les périmées ne sont aucune perte.
  • Jeter la plus basse priorité. Quand le travail a une priorité, une file pleine devrait délester l'élément le moins important, non refuser le plus important qui arrive.
  • Déborder vers un stockage durable. Quand aucun travail ne peut être perdu, une file en mémoire pleine peut déborder vers le disque ou un courtier durable — mais ce stockage durable a aussi besoin d'une borne, sinon vous avez seulement déplacé le problème sans borne quelque part de plus lent.

Le mauvais choix est de n'avoir aucun choix, ce qu'une file sans borne vous donne.

Les files que vous ignoriez être des files

La file de messages évidente est facile à borner ; les dangereuses sont les files implicites que vous n'avez pas étiquetées comme des files. Une liste de requêtes en attente d'un service en aval lent est une file. Les connexions non acquittées en attente d'acceptation sont une file. Les lignes de journal tamponnées en attente d'expédition sont une file. Chacune a une taille maximale soit choisie par vous, soit imposée par l'épuisement des ressources, et chacune peut faire tomber un système en grossissant sans limite pendant que personne ne la regarde grossir, car personne ne l'a pensée comme une file ayant besoin d'une borne.

L'habitude à bâtir est de chercher chaque endroit où le travail s'accumule en attendant quelque chose de plus lent, de le reconnaître comme une file, et de demander quelle est sa borne. Si la réponse est « autant de mémoire que nous avons », c'est une file sans borne déguisée, et elle échouera de la même façon que l'évidente.

Bornez-la, puis surveillez son remplissage

Une file bornée devrait être surveillée, car sa profondeur est l'un des meilleurs signaux d'alerte précoce que vous ayez. Une file d'ordinaire presque vide et désormais constamment à moitié pleine vous dit que le traitement prend du retard sur l'arrivée — le déséquilibre qui, sans borne, épuiserait éventuellement vos ressources, attrapé tôt pendant qu'il est encore temps d'ajouter de la capacité de traitement ou d'enquêter sur le ralentissement. Alertez sur une profondeur soutenue, pas seulement sur la file pleine, car pleine est l'urgence et monter vers pleine est l'avertissement qui vous permet de l'éviter :

profondeur_file / max_file > 0,7 pendant 5 minutes  ->  avertir
file rejetant du travail                             ->  alerter

Quoi faire

Trouvez chaque file de votre système, y compris les implicites, et confirmez que chacune a une taille maximale que vous avez choisie plutôt qu'une que votre matériel choisira pour vous sous charge. Pour chacune, décidez ce qui arrive quand elle se remplit, en ajustant le comportement de rejet à la nature du travail. Puis surveillez les profondeurs pour qu'un arriéré croissant vous avertisse avant de devenir un rejet et qu'un rejet vous avertisse avant de devenir une panne. Un système bâti de files bornées se dégrade avec grâce sous plus de charge qu'il ne peut en traiter ; un système bâti de files sans borne fonctionne parfaitement jusqu'au moment où il ne fonctionne plus du tout.

#reliability #queues #architecture #backpressure

À lire aussi