Blog ·
La seule vraie limite à l’occupation d’un rack
Deux ingénieurs choisissent la même unité de rack au même instant. Le formulaire dit libre aux deux. Un index unique partiel tranche, et rien d’autre.
Par Provibr
Deux ingénieurs implantent des machines dans le même rack. Tous deux ouvrent le formulaire, tous deux regardent le U neuf, tous deux voient un emplacement libre, tous deux appuient sur enregistrer. Quoi que fasse votre code applicatif entre ces deux requêtes, il existe une fenêtre pendant laquelle tous deux lisent la même réponse, et aucune vérification avant l’écriture ne la referme.
C’est la plus vieille course du manuel et elle a une seule bonne réponse : c’est la base de données qui tranche. Tout ce qui est au-dessus est là pour produire un refus lisible, pas pour empêcher une collision. Se tromper dans cet ordre est exactement la façon dont on se retrouve avec une règle d’unicité qui fuit un jour chargé, et dans un datacenter une fuite signifie quelqu’un avec un chariot planté devant un rack déjà plein.
La frontière est un index
L’occupation est stockée deux fois à dessein. Une affectation a une ligne d’en-tête, qui est la chose que quelqu’un a créée : cette face, de cette unité à celle-là, et pour une implantation la machine qui s’y trouve. Et elle a une ligne par emplacement occupé : ce rack, cette face, ce U unique.
La table des emplacements existe pour exactement une raison. Elle porte un index unique partiel sur le rack, la face et le numéro d’emplacement, restreint aux lignes qui n’ont pas été libérées. Cet index est la seule vraie limite à l’occupation dans tout le système. Rien d’autre ne peut l’être, parce qu’un index unique ne peut pas faire de jointure : il ne voit que les colonnes de la ligne sur laquelle il repose, donc le rack et la face doivent être dénormalisés sur la ligne d’emplacement pour que la contrainte existe tout court.
Le prix, c’est que libérer une affectation fait deux mises à jour dans une seule transaction, puisque l’horodatage de libération vit à la fois sur l’en-tête et sur les emplacements. Le retour, c’est que l’invariant est appliqué par la base de données plutôt que par le soin de celui qui écrira la prochaine fonctionnalité.
Nous l’avons mesuré au lieu de le raisonner. Deux vraies connexions Postgres, une barrière mutuelle pour que toutes deux soient dans leur transaction avant que l’une valide, toutes deux affectant la face avant U neuf. Résultat : exactement une affectation écrite, une erreur 23505 nommant cet index, et aucun en-tête orphelin laissé par le retour arrière. C’est la phrase que l’on veut pouvoir écrire à propos d’une garantie de concurrence, et on ne peut pas l’écrire en lisant le code.
À quoi sert vraiment la vérification avant l’écriture
Il existe une fonction pure qui planifie une affectation, et elle refuse de trois façons, dans cet ordre.
La face n’existe pas. Un châssis ouvert sans face arrière n’est pas un rack dans le dos duquel on accroche quoi que ce soit, et c’est pourquoi le fait qu’un rack ait une face avant et une face arrière est une propriété du rack plutôt qu’une supposition.
Hors limites. La plage entière doit tenir entre l’unité de départ du rack et sa fin, bornes comprises. Les racks ne commencent pas tous à un et ne numérotent pas tous vers le haut, donc c’est une arithmétique contre la géométrie de ce rack précis et non contre le nombre quarante-deux.
Occupé, et ce refus porte la liste des emplacements qui entrent en conflit. Un message qui dit « plein » renvoie quelqu’un au formulaire sans idée de l’endroit où regarder. Un message qui dit que la face avant U neuf et U dix sont pris l’envoie à la réponse.
Aucune de ces trois n’est la frontière. Les deux ingénieurs du premier paragraphe passent les trois. La fonction existe pour que le cas ordinaire, qui est une personne à la fois qui se trompe, produise une phrase plutôt qu’un code d’erreur de base de données.
La profondeur inconnue se comporte comme la pleine profondeur
Tout équipement a une classe de profondeur : pleine, demie, ou inconnue. Un équipement demi-profondeur n’affecte que la face sur laquelle il est fixé. Un équipement pleine profondeur affecte l’avant et l’arrière.
L’inconnue affecte l’avant et l’arrière elle aussi, et ce choix mérite d’être défendu parce que le réflexe est l’inverse. L’inconnue ressemble à une donnée manquante que l’on remplira plus tard, et en attendant il semble sans danger de laisser l’autre côté libre.
Ce n’est pas sans danger. Une machine dont la profondeur se révèle pleine ne peut pas être installée si quelqu’un a rempli l’arrière entre-temps, et la correction se fait avec la machine déjà sur place. Bloquer l’arrière vous coûte un emplacement que vous auriez peut-être eu. Ne pas le bloquer vous coûte une livraison. L’inconnue n’est pas une absence de contrainte, c’est une contrainte que vous ne pouvez pas encore nommer, et son côté sûr est le côté prudent.
Le même principe traverse le reste du modèle de capacité : un poids inconnu, une consommation inconnue ou un état d’affectation périmé se lisent comme inconnu ou bloqué, et jamais comme de la capacité libre.
Une implantation n’expire jamais
Les affectations existent en quatre types. Une implantation est une machine physiquement présente. Un blocage est de l’espace retiré du service pour le câblage. Un gel de déplacement et une réservation sont les deux qui gardent de l’espace pour quelque chose en mouvement ou en commande. Seul le premier a un écran aujourd’hui ; les trois autres existent en tant que données pour que la primitive soit une chose plutôt que quatre choses semblables.
Une contrainte CHECK impose qu’une implantation n’ait pas d’expiration. Cela ressemble à une petite règle. Ce qu’elle empêche, c’est une ligne qui cesse discrètement de compter un mardi alors que la machine est toujours boulonnée en place, c’est-à-dire un rack dont le logiciel croit qu’il a un emplacement libre. Une réservation qui expire est une fonctionnalité ; une implantation qui expire est un mensonge avec une minuterie dessus.
Une deuxième contrainte exige qu’une implantation ait un équipement, puisque les trois autres types n’en ont légitimement aucun, et un index unique partiel n’autorise au plus qu’une implantation active par équipement. Sans cet index, la même machine peut être enregistrée dans deux racks à la fois. Ce n’est pas un problème de qualité de données que l’on remarque dans un rapport ; c’est un problème que l’on remarque quand quelqu’un est planté devant le mauvais rack.
À savoir à propos des index de cette forme : ils sont globaux plutôt que cantonnés par organisation. Une machine qui porte déjà une ligne active entre en collision avec la contrainte d’unicité plutôt qu’avec une vérification de propriété, même quand la seconde tentative vient d’une autre organisation. C’est le côté sûr, et cela signifie aussi que tester le cas à deux organisations demande un troisième équipement, parce que la contrainte se déclenche avant que la logique de propriété ne s’exécute.
La même forme un cran plus haut
Confier une machine à un client a exactement la même structure, et cela demande deux index plutôt qu’un, parce que ce sont deux invariants que les gens énoncent d’habitude en une seule phrase.
Un service est sur au plus une machine. Sans cela, un service peut pointer vers deux équipements et sa fiche de localisation pointe dans deux directions.
Une machine est attribuée à au plus un service. Sans cela, la même machine est vendue deux fois, et vous l’apprenez quand deux clients appellent.
Les deux sont des index uniques partiels sur des lignes dont la date de fin est encore vide, ce qui est la même construction que l’index des emplacements et pour la même raison : la vérification dans l’application produit le refus lisible, l’index décide qui gagne.
Une règle n’a pas pu entrer dans la base de données. Un rattachement doit pointer vers un service dédié, et une contrainte CHECK ne peut pas lire une autre table. Celle-là vit dans la fonction qui écrit le rattachement, et il vaut la peine d’être explicite sur celles de vos règles qui sont appliquées par le schéma et celles qui le sont par un chemin de code, parce que la seconde espèce ne vaut que le nombre de chemins d’écriture que vous pensez à faire passer par elle.
Les rattachements sont historiques plutôt que courants. C’est la date de fin qui rend la ligne inactive, et toute lecture d’une localisation physique filtre dessus et sur l’organisation du rattachement comme de l’équipement. Retirez ces filtres et un ancien client lit le rack et l’unité du client venu après lui. Cela a été prouvé rouge avant d’être corrigé, ce qui est la seule façon de savoir qu’un filtre travaille.
Ce que nous écririons
- Mettez l’unicité là où se trouve la ligne. Si la contrainte a besoin d’une jointure, dénormalisez les colonnes dont elle a besoin ; un index ne peut pas faire de jointure et un déclencheur n’est pas une contrainte.
- Matérialisez l’unité de contention. Une ligne par emplacement occupé, pas une plage sur un en-tête, parce qu’une plage ne peut pas être unique face à une autre plage.
- Prouvez la course avec deux connexions et une barrière. Raisonner sur les niveaux d’isolation n’est pas une preuve.
- Faites de la vérification préalable un message, pas une défense, et faites-lui nommer les emplacements exacts qui entrent en conflit.
- Faites que l’inconnu se comporte comme le cas coûteux, pour qu’une mesure manquante ne se présente jamais comme de l’espace libre.
Pour être clair sur la situation : le travail sur la logistique de datacenter est derrière un indicateur de déploiement désactivé par défaut, avec un réglage par organisation par-dessus, si bien que rien de ce qui précède n’est achetable aujourd’hui. Deux choses ne sont pas prouvées : la mesure de concurrence a été faite sur des affectations de type blocage dans un test direct de base de données plutôt que sur le chemin d’implantation lui-même, et les types gel de déplacement et réservation n’ont pas encore de chemin d’écriture. L’habitude plus large de laisser la base de données arbitrer apparaît ailleurs dans ce produit aussi, dans comment les adresses sont distribuées depuis un pool et dans pourquoi une plage de vmid est vraiment une frontière de permission.
Issu du travail sur les datacenters chez Provibr. Pourquoi les cinq questions de capacité au-dessus d’un rack ne doivent pas être additionnées est dans l’espace en rack n’est pas de la capacité, et ce qui se passe quand un système externe prétend savoir où se trouve une machine est dans quand NetBox est la source de vérité.