Aller au contenu

Blog ·

Un délai d’attente n’est pas un bouton d’arrêt

Une échéance met fin à votre attente, pas au travail. Ce qu’un plafond d’une heure fait à une longue sauvegarde, et comment consigner un résultat inconnu.

Par Provibr

Toute commande distante a besoin d’une échéance. Cette partie-là ne prête pas à discussion : un processus qui peut attendre indéfiniment finira par attendre indéfiniment, et une seule requête bloquée retiendra un exécutant, une connexion et une ligne dans votre file d’attente jusqu’à ce que quelqu’un redémarre quelque chose.

Ce qui est bien moins évident, c’est ce que fait réellement cette échéance. Elle met fin à l’attente de votre côté. Elle ne met pas fin, dans le cas général, au travail de l’autre côté. Tout ce qu’il y a de difficile dans les opérations longues vit dans cet écart.

Nous faisons tourner un agent sur les hyperviseurs de nos clients et nous lui envoyons des commandes. La sauvegarde d’une machine virtuelle est la commande qui nous a fait prendre cet écart au sérieux, car une sauvegarde peut honnêtement durer une heure, et une heure est exactement là où se situent nos propres limites.

Le plafond n’est pas une préférence

Notre agent borne toute échéance de commande à une heure. La plateforme peut en demander davantage ; elle ne l’obtiendra pas. Cette borne est un unique min() sur la valeur qui arrive dans la requête, avec zéro compris comme « non défini » et un repli de deux minutes lorsque le champ est absent.

Cette borne a une conséquence que l’on manque quand on règle des délais dans un fichier de configuration. Si la plateforme croit à une échéance à laquelle l’agent ne croit pas, vous avez deux systèmes en désaccord sur le moment où une commande est morte, et le désaccord se manifeste sous la pire forme possible : l’agent abandonne, rend compte et passe à autre chose, tandis que la plateforme tient toujours la ligne ouverte et attend une réponse qui n’arrivera jamais sous la forme qu’elle espère.

La règle à laquelle nous avons abouti est donc ennuyeuse, et mérite d’être écrite malgré tout. Chaque délai côté plateforme est choisi avec le plafond de l’agent présent dans la pièce. Nos échéances de sauvegarde et de restauration valent une heure précisément parce que c’est ce plafond, et sur plusieurs dizaines d’échéances de commande ce sont les deux seules qui le touchent.

Les échéances ne sont pas une affaire de style

Voici à quoi ressemblent réellement nos échéances de commande, et pourquoi chacune est ce qu’elle est.

CommandeÉchéancePourquoi ce nombre
Lire le matériel, lire les règles de pare-feu30 sUne lecture. Plus long que cela signifie qu’autre chose est cassé.
Écrire les règles de pare-feu120 sUn appel d’API par règle, dans les deux sens, au plafond de règles.
Lister les points de restauration60 sUn appel par stockage de sauvegarde sur le nœud, et un stockage en répertoire contenant des milliers d’archives lit son propre index depuis le disque.
Mise à jour de l’agent par lui-même300 sTélécharger, calculer l’empreinte, écrire. Généreux pour une ligne lente chez le client.
Créer une sauvegarde3600 sLe plafond de l’agent.
Restaurer une sauvegarde3600 sLe même plafond, atteint plus tôt : une restauration déplace environ deux fois les octets que la sauvegarde a déplacés.
Préparer une machine cloud neuve1200 sMises à jour de paquets sur une image qui peut avoir des semaines, puis l’installation.
Exécuter une migration de panneau1800 sDeux panneaux lus intégralement, écrits, puis recomptés.

Deux de ces lignes sont des histoires plutôt que des nombres.

Celle de la machine cloud retombait autrefois sur la valeur par défaut de deux minutes. Deux minutes suffisent pour une image qui se trouve être à jour, et ne suffisent pour rien d’autre : la plateforme signalait donc un échec pendant que l’installation à l’intérieur de la machine poursuivait son chemin et se terminait quelques minutes plus tard. La commande était marquée en échec. La machine tournait. C’est la pire sorte d’erreur : pas une panne, une contradiction, et c’est le client qui doit la résoudre.

Celle de la migration est la plus longue échéance qui ne soit pas le plafond de l’agent, et le raisonnement qui la sous-tend est un décompte plutôt qu’une impression. Le migrateur fait un appel d’API par utilisateur et un par serveur contre le panneau de destination. À mille serveurs, cela fait mille appels sortants et mille réponses en retour, avec une lecture complète des deux côtés avant et un recomptage après.

Les coûts d’une erreur ne sont pas symétriques

C’est le principe qui sous-tend les deux histoires. Une échéance trop courte et une échéance trop longue échouent de manières complètement différentes, et les traiter comme les deux extrémités d’un même curseur vous donne le mauvais nombre à chaque fois.

Trop longue : une opération qui est réellement morte tient une ligne ouverte un peu plus longtemps. Quelqu’un attend. Rien n’est corrompu, rien n’est dupliqué, et le nettoyage qui finit par arriver est sans histoire.

Trop courte : vous consignez un échec pour un travail qui a réussi. Vos enregistrements et la réalité sont désormais en désaccord, et tous les chemins de reprise dont vous disposez, réessayer, recréer, rembourser, alerter, visent un problème qui n’existe pas et en fabriqueront un second.

Ce ne sont pas deux maux équivalents, ils ne devraient donc pas recevoir des marges de même taille. Pour tout ce qui crée, déplace ou supprime des ressources réelles, nous prenons délibérément le côté généreux et nous écrivons pourquoi.

Deux horloges qui démarrent à des instants différents

Il y a dans tout système de commandes mises en file une subtilité facile à manquer et facile à mesurer. Notre plateforme calcule l’échéance comme un instant absolu, au moment précis où la ligne de commande est écrite. L’agent calcule la sienne comme une durée, qui commence quand il se met à exécuter.

Ce sont deux horloges différentes. Si l’agent est hors ligne, ou occupé, ou si la commande reste trente secondes dans la file, la plateforme a déjà dépensé trente secondes de son budget et l’agent non. La plateforme abandonne la première.

C’est le bon sens de lecture, et il vaut la peine de dire explicitement pourquoi. L’échéance de la plateforme répond à la question que le client pose réellement : depuis combien de temps ai-je cliqué ? Celle de l’agent en répond à une autre : combien de temps ce travail a-t-il le droit de tourner ? Le temps écoulé depuis le clic est le nombre dont parle une conversation avec le support. Les rendre identiques serait plus élégant et répondrait à la mauvaise question.

Une troisième horloge se cache là-dedans. Sur notre agent, l’attente d’un jeton de concurrence se passe en dehors de l’échéance d’exécution. Une commande mise en file derrière une autre commande visant la même intégration ne consomme pas son propre budget pendant qu’elle attend. Si vos échéances sont serrées, vérifiez laquelle de vos horloges inclut la mise en file ; la réponse est rarement celle qui figure dans la documentation.

Ce que l’échéance annule réellement

Quand l’échéance de l’agent expire, il signale une annulation et cesse d’attendre. Ce que cette annulation atteint, c’est votre propre code : la boucle d’interrogation qui demandait à l’hyperviseur où en était la tâche.

Elle n’atteint pas l’hyperviseur. La sauvegarde continue de tourner. Elle se terminera, ou elle échouera, entièrement sans nous. Rien de cette annulation n’est descendu jusqu’à la baie de stockage.

Ce n’est pas une limitation à faire disparaître par de l’ingénierie. C’est la forme honnête du problème, et le geste utile consiste à consigner le résultat avec franchise plutôt qu’à faire semblant. La classification qui a survécu au contact de la production compte trois issues et non deux.

  • Échec. Nous savons qu’il ne s’est rien passé. Le client peut réessayer, et il n’y a rien à nettoyer.
  • Inconnu. Nous avons cessé d’écouter avant qu’il y ait une réponse. Quelque chose existe peut-être.
  • À rapprocher. Nous avons une raison positive de penser qu’il existe quelque chose dont nous ne pouvons pas rendre compte.

Une restauration qui dépasse son échéance est le cas le plus tranchant. Il y a peut-être désormais, sur l’hyperviseur, une machine qui tourne et pour laquelle notre base n’a aucune ligne. La marquer en échec serait un mensonge qui cache une machine ; la marquer en succès serait un mensonge qui en invente une. Elle est marquée comme demandant un examen, et le panneau demande au client d’aller voir au lieu de lui proposer un bouton de réessai qui construirait une deuxième machine à côté de la première.

Nous avons mis cette règle dans le code sous la forme d’une liste des cas certains, et non des cas incertains. Quatre codes d’erreur précis signifient que le travail n’a jamais commencé, parce que tous les quatre viennent de vérifications que l’agent effectue avant de passer le premier appel. Tout le reste, y compris n’importe quel code d’erreur que nous ajouterions plus tard en oubliant de le classer, retombe sur l’incertitude. La direction compte : un code oublié qui se comptabilise discrètement en échec fait disparaître des registres une machine existante, tandis qu’un code oublié qui se comptabilise en incertain coûte seulement un coup d’œil à quelqu’un.

Un résultat incertain a besoin d’un moyen de devenir certain

Un statut qui veut dire « quelqu’un devrait vérifier » n’est honnête que si quelqu’un, ou quelque chose, vérifie effectivement. Le nôtre est un exécutant qui demande périodiquement à chaque machine ayant un historique de sauvegarde de lister à nouveau ses points de restauration, de sorte qu’une archive discrètement disparue chez le fournisseur devienne une notification plutôt qu’une liste qui a raccourci le jour où un client a eu l’idée de regarder.

Cette boucle porte une contrainte de sobriété délibérée, car chaque listage est une commande qui tourne sur l’hôte de quelqu’un d’autre. Elle ne visite que les machines qui ont une politique ou au moins un point de restauration connu, et elle prend un lot borné par tour. Le jour où cela cessera de suffire, la bonne correction sera un curseur, pas un nombre plus grand.

La boucle doit aussi survivre au fait que deux de vos propres serveurs décident de l’exécuter à la même seconde. Nous le faisons avec une clé d’idempotence durable faite de la machine et du numéro de fenêtre, et non d’un horodatage : deux serveurs ne battent jamais à la même milliseconde, mais ils sont assurément dans la même fenêtre de six heures, si bien qu’un horodatage ne dédupliquerait rien.

Ce que nous vous conseillerions d’écrire

Si vous choisissez des échéances pour du travail distant, quatre questions vous mènent presque partout.

  1. Quel est le plafond dur, et qui le fait respecter ? Si deux composants sont en désaccord, le plus petit gagne en pratique et le plus grand est une fiction.
  2. Quand démarre chaque horloge ? Le temps d’attente en file est dans le budget ou il n’y est pas, et les deux réponses se défendent. Ne pas savoir, non.
  3. Qu’est-ce que l’expiration annule ? Si la réponse est « notre propre attente », dites-le à voix haute, car tout le reste de la conception en découle.
  4. De quel côté tombe une issue non classée ? Faites de l’incertitude la valeur par défaut, et faites de la certitude ce qu’il faut écrire noir sur blanc.

Rien de tout cela ne raccourcit une longue sauvegarde. Cela rend vrai le compte rendu qui en est fait, et c’est cette partie-là que vous lirez à deux heures du matin.

Commencez avec un hôte et un agent

Créez un compte, installez l’agent avec une seule commande et connectez votre premier hôte Proxmox. La période d’essai dure 14 jours et ne demande aucune coordonnée de paiement.