Corrigez-moi si vous le pouvez: comment nous déboguons sur la production. 2e partie

Dans la première partie de mon article, j'ai expliqué comment, chez Badoo, nous avons créé la première version du système de correctifs. En bref, nous devions trouver un moyen de corriger les bugs graves dès la production, accessible à tous les développeurs. Cependant, la première version n'était pas sans inconvénients: nous avons utilisé une méthode de mise en page particulière, qui ne garantissait pas l'atomicité de la mise en page des correctifs et la cohérence du code.

Dans cette partie de l'article, je vais parler d'une nouvelle façon de présenter le code que nous avons trouvé en essayant de résoudre nos problèmes, et comment notre système de correctifs a été transformé avec lui.


Image: source

Solution universelle - Kit de déploiement multiversionnel


Après un autre examen de notre système Jura, youROCK Nasretdinov a déclaré qu'il avait une idée sur la façon de résoudre tous nos problèmes. Tout ce qu'il a demandé, c'était beaucoup de temps pour refaire le système de mise en page. C'est ainsi que le concept du Kit de déploiement multiversionnel, ou, chez les gens ordinaires, le MDK est apparu (Jura l'a comparé à d'autres façons de disposition de code dans son rapport sur HighLoad ++ ).

Le nouveau système a été conçu pour changer notre procédure de mise en page. Pour ceux qui n'ont pas lu ma première partie de l'article, je vais vous expliquer brièvement à quoi ressemble le processus de déploiement: nous collectons d'abord tous les fichiers nécessaires dans un répertoire, puis enregistrons et remettons l'état du répertoire aux serveurs.

Avant l'ère MDK, nous utilisions des périphériques de blocs (c'est-à-dire des images du système de fichiers) appelés boucles pour stocker et livrer. Le répertoire a été copié dans une boucle vide, il a été archivé et envoyé aux serveurs.

Dans le nouveau système, nous versionnons non pas le répertoire entier, mais chaque fichier individuellement afin que la version du fichier soit clairement en corrélation avec son contenu. Pour les répertoires, il existe des cartes (maps) - des fichiers spéciaux dans lesquels les versions de tous les fichiers du répertoire sont enregistrées. Ces cartes sont également versionnées, et tout ressemble à ceci:



Semble familier? C'est ainsi que les objets sont organisés dans Git (vous pouvez en lire plus ici , mais ce n'est pas nécessaire pour comprendre l'article).

Pour le contrôle de version, nous utilisons les huit premiers caractères du hachage MD5 (de sa représentation hexadécimale, pour être précis), extraits du contenu du fichier. Cette version est écrite à la fin du nom de fichier ou au début du nom de la carte (afin que vous puissiez distinguer le fichier de la carte de la version générée):



La version du code est la version de carte du répertoire racine www. Afin de trouver la carte actuelle, nous avons un lien symbolique (lien symbolique) current.map.

Pourquoi ne pas utiliser git?
Malgré le fait que MDK emprunte en partie des idées à Git, ils ont quelques différences. La chose la plus importante est de savoir comment les fichiers sont stockés dans le répertoire de travail (c'est-à-dire sur les machines). Si Git n'y stocke qu'une seule version actuelle, alors MDK contient toutes les versions disponibles des fichiers. Dans le même temps, un seul lien symbolique current.map pointe vers la version actuelle du code, qui utilise le chargement automatique dans son travail et qui peut être modifiée atomiquement. À titre de comparaison, Git utilise git-checkout pour changer la version, qui change les fichiers à son tour et n'est pas atomique.

Construire avec MDK


MDK est nécessaire pour enregistrer l'état du répertoire à la fin de l'assembly. Pour ce faire, nous avons un endroit spécial, que nous avons appelé un référentiel, - un référentiel de toutes les versions de fichiers qui nous sont utiles (c'est-à-dire que nous pouvons vouloir décomposer). Lorsque le nouveau contenu du répertoire est prêt, nous calculons les versions de tous les fichiers qu'il contient et signalons celles qui manquent au référentiel.

Disposition avec MDK


Lors de la mise en page sur chacun des serveurs récepteurs, nous exécutons un script qui vérifie si tous les fichiers nécessaires se trouvent sur le serveur et demande ceux qui manquent dans le référentiel. Nous ne pouvons changer la version en une nouvelle qu'en changeant le lien symbolique current.map.

Comment cela devrait résoudre nos problèmes


On a supposé que si seulement quelques fichiers changeaient dans la nouvelle version, son assemblage et sa mise en page utilisant le nouveau système devraient être au moins comparables dans le temps à la mise en page du correctif en tant que fichiers séparés. Si c'est le cas, alors pour chaque patch, nous générerons simplement une nouvelle version.

Implémentation MDK


MDK avait un inconvénient: sur les machines finales, le nom de chaque fichier devrait avoir sa version. C'est ce qui vous permet de stocker de nombreuses versions d'un fichier dans un répertoire à la fois, mais cela ne vous permet pas d'inclure include user.php à partir du code - vous devez spécifier une version spécifique. Ajoutez à cela les différents bugs qui pourraient bien rester dans le code du système de mise en page, le nouvel algorithme de mise en page, qui était plus compliqué que l'ancien, et on comprendra pourquoi nous avons décidé d'implémenter le nouveau système par petites étapes. Nous avons commencé littéralement avec un ou deux serveurs et avons progressivement étendu leur liste, corrigeant simultanément les problèmes qui se posent.

Étant donné que le passage à un nouveau système aurait dû prendre beaucoup de temps, nous avons dû réfléchir à la façon dont nos correctifs fonctionneraient pendant la période de transition. À cette époque, pour la disposition des correctifs, nous utilisions l'utilitaire auto-écrit mscp, qui disposait les fichiers un par un. Nous lui avons appris à remplacer les fichiers actuels sur les serveurs par MDK à l'avance, mais nous ne pouvions pas ajouter un nouveau fichier à ces serveurs (parce que je devais changer la carte des fichiers). Je ne voulais pas introduire une solution intermédiaire très compliquée - parce que nous allions vers un avenir brillant, où mscp n'est pas nécessaire. En conséquence, j'ai dû supporter ce problème. En général, pendant la période de transition, les développeurs ont réussi à souffrir, mais maintenant il nous semble que cela en valait la peine.

Ne fais confiance à personne



Image: source

Probablement, la question sera logique, mais y aura-t-il une collision de versions dans MDK (c'est-à-dire une situation où deux fichiers avec un contenu différent se voient attribuer la même version)?

En fait, nous sommes assez bien protégés contre ce genre d'erreur. Nous { }.{} fichiers comme ceci: { }.{} , ce qui signifie que plus de huit caractères doivent correspondre pour qu'une erreur se produise.

Mais une fois, quelque chose s'est mal passé. Après le prochain calcul, nous avons remarqué un nombre croissant d'erreurs avec le code HTTP 404 (fichier introuvable). Une petite enquête a montré que certains fichiers statiques manquaient. Il s'est avéré que nous avons présenté une très ancienne carte statique et donné des liens vers des fichiers qui ne devraient pas déjà être sur les serveurs. Mais d'où vient cette carte? Dans la première partie de l'article, j'ai noté que la statique est décomposée par un processus distinct, et seule la carte de version laisse le code PHP. Lorsque nous générons une nouvelle version de MDK, nous signalons les versions manquantes des fichiers au référentiel, dont rien n'est supprimé (il y a beaucoup d'espace, cela ne nous dérange pas). Et nous donnons souvent le meilleur de la mise en scène, et donc la carte de version statique est l'un de ces fichiers qui changent plus souvent que les autres. Tout cela a conduit au fait que nous étions confrontés à une collision. Après avoir vérifié la version, MDK a décidé que tout allait bien, car un fichier d'une telle version existe déjà, et l'a disposé sur les serveurs. C'est bien que nous ayons découvert l'erreur rapidement.

Maintenant, en plus de la version, nous vérifions la taille du fichier: si c'est la même dans le référentiel, alors c'est probablement le même fichier. Dans le pire des cas, nous aurons une histoire pour un nouvel article.

MDK - Voleur de Noël



Image: source

Et je veux vous parler d'une autre erreur, car c'est au moins drôle. Il est facile de deviner que nous avions un processus de nettoyage des anciennes versions des fichiers sur les serveurs de destination. Afin de résoudre rapidement l'un des problèmes, nous avons pris une décision fatidique: définir la période de nettoyage à un jour (au lieu de sept, comme c'était le cas auparavant). Cela a fonctionné - et le problème a disparu. Nous avons même vécu un moment.

Dimanche, vers cinq heures du matin, un téléphone a sonné dans ma chambre et le moniteur de garde a sonné: «Les scripts ne fonctionnent pas pour nous. Ils disent que vous savez ce qui se passe. " Pour moi, cela ressemblait à «Au bureau, l'extracteur de jus a grillé. Ils disent que vous savez ce qui se passe. " Je ne connaissais les principes de notre framework de script que par des articles et des histoires, je n'avais pas de «relations personnelles» avec lui, et plus encore, je ne l'ai jamais réparé. Mais je suis monté sur les serveurs pour savoir ce qui se passait et j'ai découvert que le problème était vraiment «de notre côté»: il n'y avait tout simplement pas de code sur les serveurs.

J'ai à nouveau téléchargé le code - et cela a fonctionné. Soit dit en passant, l'erreur s'est avérée primitive: samedi, aucune nouvelle version de MDK n'a été présentée, et le script de nettoyage, comme il s'est avéré, n'a effectué aucune vérification pour ne pas supprimer la version actuelle. En conséquence, à cinq heures du matin, il (selon un calendrier) a supprimé le code de tous les serveurs. Après cette histoire, nous avons réalisé qu'avec les anciens paramètres, cela arriverait pendant des vacances de 7 jours, par exemple, les vacances du Nouvel An, juste la veille de Noël. «Le Christ est né - le code a disparu» - pendant longtemps nous avons pu entendre cette blague.

Nouveau système de patchs


Au final, nous avons introduit un nouveau système de mise en page - et il est temps de refaire le système de patchs. Il n'y avait plus besoin de mscp et pas besoin d'éviter de générer de nouvelles versions. Tout d'abord, nous avons changé le cycle de vie du patch. Maintenant, après avoir confirmé les modifications, il revient au développeur, qui prend une décision lorsque le patch est prêt pour le calcul. Il clique sur le bouton Déployer, après quoi nous ajoutons le patch à maîtriser, générons et déployons une nouvelle version de MDK. L'implication des développeurs à ce stade n'est plus requise.

Nous avons atteint une très bonne vitesse de mise en page: les changements arrivent aux serveurs en une minute. Pour ce faire, cependant, nous avons dû recourir à quelques astuces: par exemple, nous ne générons toujours pas de statistiques ou de traductions - à la place, nous prenons la version de la dernière version décomposée. Pour cette raison, nous maintenons une restriction sur les correctifs pour les fichiers JS et CSS.

Les expériences


Nous avons vraiment réussi à résoudre tous les problèmes que nous avions auparavant. Vous n'avez plus besoin de réfléchir à la façon de former correctement les modifications, ce qui ne causera pas de problèmes avec la mise en page fichier par fichier - ne touchez pas à la statique, et tout fonctionnera.

Mais une nouvelle difficulté est apparue. Auparavant, nous autorisions les développeurs à publier leurs modifications sur un ou plusieurs serveurs, juste pour nous assurer que tout fonctionnera avec eux. Avec le nouveau système, cette fonctionnalité a disparu, car master est devenu la version actuelle pour tous les serveurs, sans exception.


Image: source

Pour cette raison, une nouvelle exigence pour le système de correctifs est apparue: vous devez pouvoir vérifier vos modifications sur un petit nombre de serveurs sans ajouter de modifications au maître. Nous avons appelé les nouvelles expériences de fonctionnalité.

Pour le développeur, le processus ressemble à ceci: après avoir reçu la mise à niveau, une nouvelle page devient disponible dans l'interface du système de correctifs où vous pouvez sélectionner les serveurs sur lesquels vous souhaitez expérimenter. Il peut s'agir d'un groupe de serveurs, d'un serveur ou de toute combinaison que notre système comprendra. Le système déploie le correctif et avertit le développeur. Dans le même temps, un journal des dernières erreurs des serveurs concernés apparaît sur la page.

Nous ne limitons en aucune façon les développeurs, ils peuvent créer des expériences sur les mêmes serveurs. L'un peut expérimenter sur un cluster à 10%, l'autre sur l'ensemble du cluster.

Cela est devenu possible grâce au fait que nous avions la «version des correctifs» qui nous manquait tant. Il s'agit d'une version qui, en théorie, peut être unique pour chaque serveur. Il ressemble à une chaîne d'identifiants séparés par des virgules, par exemple, "32,45,79". Cela signifie que le serveur doit avoir toutes les modifications de l'assistant et les correctifs numérotés 32, 45 et 79. Pour chacune de ces versions, nous générons notre propre version de MDK. Nous prenons les dernières modifications de la branche principale, puis appliquons séquentiellement chacun des correctifs. Si un conflit survient lors de la génération de l'une des versions, nous annulons simplement l'expérience pour le dernier correctif et en informons le développeur.

Fichiers générés


Dès le premier jour de l'existence du système de patchs, nous sommes passés à l'astuce: nous avons refusé de générer de l'électricité statique afin que les modifications atteignent les serveurs le plus rapidement possible. Bien sûr, nous voulions vraiment avoir l'opportunité de changer le code JS de la même manière que nous changeons le code PHP, mais toutes les tentatives pour construire ce processus ont échoué.

Il y a environ six mois, nous sommes revenus sur ce problème. Objectif: vous devez changer la statique, mais vous ne pouvez pas sacrifier la vitesse de mise en page du code PHP. Le principal problème: un assemblage complet prend huit minutes. Que faire

Vous devez faire des compromis. Nous sommes partis du fait que le code JS ne peut pas être présenté dans le cadre des expériences. Cela devrait vous faire gagner beaucoup de temps: il suffit de garder à jour une version de la statique au lieu de générer des dizaines de versions différentes pour différents groupes de machines. Mais c'est encore long. Que pouvez-vous économiser d'autre? Nous n'avons pas compris comment réduire le temps, mais avons décidé qu'il n'y aurait aucun problème si l'assembly ne bloquait pas la mise en page du code PHP.

Nous avons commencé à générer de la statique de manière asynchrone. Avec les modifications apportées aux fichiers JS ou CSS, nous démarrons un processus distinct qui crée une nouvelle carte des versions statiques. Le processus d'assemblage du code PHP au début du travail vérifie s'il existe une nouvelle carte statique et, s'il y en a une, la récupère et la dépose sur tous les serveurs. Avez-vous résolu le problème? En pratique. Avec cette approche, nous avons opté pour une nouvelle limitation: vous ne pouvez pas modifier le code JS et PHP dans un seul correctif, car nous décomposons ces modifications de manière asynchrone et ne pouvons pas garantir qu'elles seront sur les machines en même temps.

Résumé


Nous sommes très satisfaits de la mise à jour. Ce n'était pas facile pour nous, mais cela a rendu notre système beaucoup plus fiable. Les développeurs ont trouvé une application alternative pour les expériences: avec eux, vous pouvez facilement collecter des journaux spécifiques à partir d'une paire de serveurs sans ajouter vos modifications au maître.

Nous avons encore des idées pour améliorer le système, pour la mise en œuvre duquel il n'y a pas encore assez de temps. Par exemple, nous voulons refaire le processus de création d'un patch et ajouter la possibilité de changer les fichiers JS en même temps que le code principal pour se débarrasser des dernières restrictions.

Chaque jour, nous publions environ 60 correctifs, parfois il y en a plusieurs fois, par exemple, pendant le développement de certaines fonctionnalités qui ne sont disponibles que pour les testeurs jusqu'à présent. Environ un tiers des correctifs passent par des expériences avant d'être présentés. Au total, pendant l'existence du système, nous avions environ 46 000 correctifs pour le maître.

Source: https://habr.com/ru/post/fr413991/


All Articles