Corrigez-moi si vous le pouvez: comment nous déboguons sur la production. Partie 1

UPD: la deuxième partie de l'article est prête .

Bonjour, Habr! Je m'appelle Alexander Izmailov. Chez Badoo, je dirige une équipe d'ingénieurs de version. Je sais que dans de nombreuses entreprises, vous pouvez envoyer des modifications de code à une personne spécialement formée, il les regarde et les ajoute là où elles devraient (par exemple, c'est exactement ce qui se passe avec le code Git). Et je veux parler de la façon dont nous avons automatisé ce processus avec nous.

Mon histoire se composera de deux parties. Dans cette partie, je vais parler de ce que nous voulions réaliser du nouveau système, à quoi il ressemblait dans sa première version, et pourquoi finalement nous avons dû le refaire. Dans la deuxième partie, nous parlerons du processus de refonte du système et des bonus inattendus qu'il nous a apporté.


Image: source

Il était une fois dans notre entreprise tout le monde pouvait apporter ses modifications directement à la branche principale et les disposer de ses propres mains. Pour ce faire, nous avons écrit un utilitaire MSCP spécial qui fonctionnait assez primitivement: il copiait les modifications d'une machine à l'autre et définissait les droits nécessaires.

Au fil du temps, l'entreprise a grandi - et nous avons dû penser à l'automatisation des processus, y compris le processus de mise en place de petits changements. Nous avons donc eu l'idée de créer un système de patchs. Tout d'abord, nous voulions qu'il permette à tout développeur d'envoyer ses modifications à Git et de les disposer sur des serveurs. Pour notre part, nous avons exigé qu'un autre développeur examine les changements et qu'ils soient liés à la tâche de notre système de suivi des bogues (nous utilisons Jira).

Collecteur de patch 6000
Je dois dire que ces exigences n'ont pas séduit tous les développeurs. Il nous a semblé que consacrer quelques minutes à la création d'une tâche n'est pas une chose, mais pour nous, cela signifierait une utilisation plus délibérée du système. Mais les développeurs ont commencé à résister, arguant que la présentation des modifications prenait plusieurs fois moins de temps que la création d'un nouveau ticket. En conséquence, nous avons encore des tâches "universelles", auxquelles des centaines de correctifs sont attachés.

De plus, le système a été conçu dans le but de résoudre les problèmes urgents et il peut être difficile de trouver un examinateur pour un patch à trois heures du matin.

De quoi avons-nous besoin?


Oui, juste une lumière dans la fenêtre ... Notre problème pourrait être conditionnellement divisé en deux parties: nous avions besoin d'un moyen d'accepter les modifications du référentiel et d'une manière de les présenter.

Nous avons décidé la première question assez rapidement: nous avons fait un formulaire auquel nous devions joindre nos modifications et indiquer les détails (réviseur et tâche).


Sur la deuxième page, vous pouvez voir les modifications, les rejeter ou les accepter.



Après confirmation, les changements sont passés au maître.

Deuxième question: comment ces modifications peuvent-elles être apportées rapidement aux serveurs? Aujourd'hui, beaucoup utilisent l'intégration continue, et cela pourrait bien faire le travail si nos constructions et mises en page «honnêtes» ne prenaient pas autant de temps.

Assemblage équitable


Notre montage a toujours été assez compliqué. Le principe général était le suivant: dans un répertoire séparé, nous avons disposé les fichiers tels qu'ils seraient sur les serveurs de destination; puis nous avons enregistré cet état dans un instantané (instantané du système de fichiers) et l'avons présenté.

Nous avons mis le code PHP dans le répertoire, que nous avons pris du référentiel tel quel, y avons ajouté les fichiers générés (par exemple, les modèles et les traductions). Nous avons présenté la statique séparément. C'est un processus assez compliqué, et vous pouvez y consacrer un article entier, mais en conséquence, nous avons eu une carte de version pour générer des liens de fichiers pour les utilisateurs qui sont partis avec le code principal.

Ensuite, l'état du répertoire devait être enregistré quelque part. Pour ce faire, nous avons utilisé un périphérique bloc , que nous avons appelé une boucle. L'ensemble du répertoire a été copié sur un appareil vide, qui a ensuite été archivé et livré sur des serveurs «principaux» distincts. De ces serveurs, nous avons pris des archives en cours de mise en page. Chaque archive avait une taille de 200 Mo et, une fois déballées, les boucles pesaient 1 Go. Il nous a fallu environ cinq minutes pour construire sans statique.

Disposition juste


Nous devions d'abord livrer l'archive aux serveurs de destination. Nous en avons des milliers, donc la question de livraison pour nous a toujours été un gros problème: nous avons plusieurs plates-formes (centres de données), et sur les mille serveurs les plus "épais" avec un code. Dans le but d'obtenir de meilleures performances (temps et ressources minimum), nous avons essayé différentes méthodes: du simple SCP aux torrents. Au final, nous avons opté pour l'utilisation de l'UFTP. La méthode a été rapide (par beau temps - une minute), mais malheureusement pas sans problème. Périodiquement, quelque chose se brisait et nous devions courir vers les administrateurs et les networkers.

Après que l'archive (en quelque sorte) se soit retrouvée sur les serveurs, elle doit être décompressée, ce qui n'est pas non plus gratuit. Cette procédure semble particulièrement coûteuse si vous vous souvenez qu'elle est effectuée des milliers de fois, mais en parallèle sur différentes machines.

Pas de montage


Donc, honnêtement, publier des modifications prenait beaucoup de temps et la vitesse de livraison était très importante pour le système de correctifs, car on supposait qu'ils l'utilisaient lorsque quelque chose ne fonctionnait plus. Par conséquent, nous sommes revenus à l'idée d'utiliser MSCP: rapide et facile à mettre en œuvre. Ainsi, après que les modifications soient apparues dans l'assistant, sur une page séparée, il a été possible de décomposer les fichiers modifiés tour à tour.



C'est vivant


Le système fonctionne. Malgré une certaine insatisfaction à l'égard des petites choses, les développeurs pouvaient faire leur travail, et pour cela, ils n'avaient pas besoin d'accéder au maître ni aux serveurs.

Mais, bien sûr, avec cette méthode de mise en page, nous avons eu des problèmes. Certains étaient prévisibles, certains nous avons même décidé d'une manière ou d'une autre. La plupart d'entre eux étaient liés à l'édition de fichiers en parallèle.

Un patch pour plusieurs fichiers


Un exemple d'un problème prévisible. De nouveaux dossiers ont été disposés tour à tour. Que faire si vous devez modifier plusieurs fichiers et que les modifications y sont liées? Par exemple, je veux ajouter une nouvelle méthode dans un fichier et l'utiliser immédiatement dans d'autres. Tant qu'il n'y a pas de bouclage utilisant des méthodes (voir récurrence mutuelle ), il suffit de se souvenir de l'ordre de mise en page des fichiers correct.

Décision honnête
Pour résoudre le problème, nous devions remplacer plusieurs fichiers atomiquement. Dans le cas d'un seul fichier, la solution est connue: vous devez utiliser l'opération de fichier renommer. Supposons que nous ayons un fichier F et que nous devions remplacer son contenu. Pour ce faire, créez un fichier TMP, écrivez-y les informations nécessaires, puis faites renommer TMP F.

Compliquons la tâche. Supposons que nous ayons un répertoire D et que nous ayons besoin de remplacer son contenu. L'opération de renommage ne nous aidera pas, car elle ne peut pas remplacer un répertoire non vide. Cependant, il existe une solution de contournement: vous pouvez pré-remplacer le répertoire D par un lien dit symbolique (lien symbolique). Ensuite, le contenu lui-même se trouvera ailleurs, par exemple dans le répertoire D_1, et D sera un lien vers D_1. Au moment où le remplacement est requis, le nouveau contenu est écrit dans le répertoire D_2, vers lequel un nouveau lien TMP est créé. Maintenant, renommer TMP D fonctionnera car cette opération peut être appliquée aux liens.

Cette solution semble appropriée: vous pouvez modifier le répertoire entier avec le code, en copiant les anciens fichiers et en écrivant de nouveaux sur le dessus. Le problème est que la copie de tout le code est longue et coûteuse. Vous pouvez uniquement remplacer le sous-répertoire où les fichiers ont changé, mais tous les sous-répertoires avec le code doivent être des liens, car nous ne pouvons pas remplacer le répertoire rempli par quoi que ce soit pendant le processus de mise en page. Non seulement cette solution semble très compliquée - vous devez vous rappeler d'ajouter quelques restrictions afin que les deux processus ne puissent pas simultanément changer le même répertoire ou répertoire et ses sous-répertoires.

En conséquence, nous n'avons pas pu trouver de solution technique, mais nous avons compris comment simplifier un peu la vie: nous avons fait la mise en page de plusieurs fichiers en une seule action dans l'interface. Le développeur a spécifié la disposition des fichiers et le système les a fournis.

Plusieurs correctifs par fichier


C’est plus difficile s’il n’ya qu’un seul fichier et plusieurs développeurs souhaitent le changer. Nous avons appliqué le premier patch, mais ne l'avons pas décomposé. À ce stade, le deuxième patch arrive et est invité à se décomposer. Que faire Encore plus intéressant, si le deuxième patch est appliqué, et à ce moment on nous demande de décomposer le premier.

Probablement, nous devons préciser que nous n'avons toujours présenté que la dernière version de l'assistant. Sinon, d'autres problèmes pourraient survenir. Par exemple, disposer l'ancienne version par-dessus la nouvelle.

Nous n'avons pas trouvé une très bonne solution à ce problème. Nous avons montré aux développeurs la différence entre ce qu'ils présentent et ce qui se trouve sur les machines à un moment donné, mais cela n'a pas toujours fonctionné. Par exemple, il pourrait y avoir beaucoup de changements, et le développeur pourrait être pressé ou simplement être paresseux (tout peut arriver).

Beaucoup de correctifs et tout le monde change les mêmes fichiers


C'est la pire option sur laquelle vous ne voulez même pas vous attarder. Si les changements de plusieurs développeurs affectaient plusieurs des mêmes fichiers, notre système de correctifs ne pouvait pas particulièrement aider - il restait à compter sur l'attention des développeurs et leur capacité à communiquer entre eux. Mais en théorie, il est tout à fait possible d’obtenir du «poisson» lorsque, dans n’importe quel ordre de disposition, à un moment donné du serveur, le code sera partiellement rompu.


Image: source

Problèmes de fer


Un autre problème est survenu lorsque, pour une raison quelconque, l'un des serveurs est devenu indisponible. Nous avions un mécanisme pour exclure ces serveurs de la mise en page, ce qui fonctionnait assez bien; des difficultés sont apparues après leur retour au travail. Le fait est que les versions des configs et du code sur les serveurs qui fonctionnent sont vérifiées avec nous (il y a tout un département de surveillance!), Et nous nous assurons que toutes les versions sont à jour lorsque le serveur est de nouveau opérationnel. Mais nous n'avions pas de version pour les correctifs - nous venons de copier de nouveaux fichiers dans le code actuel.

Nous n'avons pas trouvé de moyen précis de versionner les correctifs décomposés, mais nous avons essayé de résoudre le problème par des solutions de contournement. Par exemple, rsync à partir d'une machine voisine à la fin du processus de mise en page. Mais d'une manière ou d'une autre, nous ne pouvions pas vérifier d'une manière ou d'une autre.

Nous avons examiné plusieurs solutions à ce problème, par exemple, nous voulions également appliquer des correctifs sur les serveurs «principaux» (il est important de se rappeler que nous déployons la version packagée, c'est-à-dire que nous devons appliquer le correctif et reconditionner la version), mais c'était assez difficile à mettre en œuvre.

Une cuillère de miel


Mais, en plus des problèmes, il y avait des aspects positifs.

Premièrement, les développeurs ont rapidement compris qu'en plus de réparer les choses, avec l'aide du système de correctifs, vous pouvez parfois télécharger de nouvelles fonctionnalités, par exemple lorsque vous en avez besoin de toute urgence. Comme dans toute entreprise, nous avons un cas de force majeure. Mais si auparavant nous devions créer une version extraordinaire, sur laquelle les testeurs et les ingénieurs de publication étaient distraits, le développeur pouvait désormais décomposer certains changements par lui-même.

Deuxièmement, une personne spéciale avec des droits n'était plus nécessaire pour réparer quelque chose. Tout développeur lui-même pouvait publier ses modifications. Mais ce n'est pas tout: les builds en général sont devenus plus faciles, maintenant les problèmes étaient divisés en critiques et ceux qui peuvent être corrigés à l'aide de correctifs. Cela a permis de revenir en arrière moins souvent et de décider plus rapidement si nous avons réussi.

Autrement dit, nous avons aimé le système et gagné en popularité. Nous avons continué à essayer de l'améliorer, mais avec les problèmes décrits, nous avons dû vivre encore quelques années. Et comment nous les avons décidés, comment le système fonctionne maintenant et comment nous avons presque tué les vacances du Nouvel An pendant le processus de mise à jour, je le dirai dans la deuxième partie de l'article.

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


All Articles