Comment nous avons survécu à l'augmentation de la charge de travail x10 à distance et quelles conclusions en avons-nous tirées

Hé Habr ! Au cours des deux derniers mois, nous avons vécu une situation très intéressante, et j'aimerais partager notre histoire de mise à l'échelle des infrastructures. Pendant ce temps, SberMarket a quadruplé ses commandes et lancé le service dans 4 nouvelles villes. La croissance explosive de la demande de livraison d'épicerie nous a obligés à faire évoluer notre infrastructure. Découvrez les conclusions les plus intéressantes et les plus utiles sous la coupe.

Comment nous avons survécu à l'augmentation de la charge de travail x10 à distance et quelles conclusions en avons-nous tirées

Je m'appelle Dima Bobylev, je suis le directeur technique de SberMarket. Comme il s'agit du premier article sur notre blog, je vais dire quelques mots sur moi et sur l'entreprise. L'automne dernier, j'ai participé au concours des jeunes leaders de Runet. Pour le concours, j'ai écrit une petite histoire sur la façon dont nous, chez SberMarket, voyons la culture interne et l'approche du développement des services. Et même si je n'ai pas réussi à gagner le concours, j'ai formulé moi-même les principes de base pour le développement de l'écosystème informatique.

Lors de la gestion d'une équipe, il est important de comprendre et de trouver un équilibre entre les besoins de l'entreprise et les besoins de chaque développeur individuel. Désormais, SberMarket croît 13 fois par an, ce qui affecte le produit, nécessitant une augmentation constante du volume et du rythme de développement. Malgré cela, nous accordons suffisamment de temps aux développeurs pour une analyse préliminaire et un codage de haute qualité. L'approche formée aide non seulement à créer un produit fonctionnel, mais également à sa mise à l'échelle et à son développement ultérieurs. Grâce à cette croissance, SberMarket est déjà devenu un leader parmi les services de livraison d'épicerie : nous livrons environ 18 3500 commandes par jour, alors qu'il y en avait environ XNUMX XNUMX début février.

Comment nous avons survécu à l'augmentation de la charge de travail x10 à distance et quelles conclusions en avons-nous tirées
Un jour, un client a demandé à un coursier de SberMarket de lui livrer des courses sans contact, directement sur le balcon.

Mais venons-en aux détails. Au cours des derniers mois, nous avons activement fait évoluer l'infrastructure de notre entreprise. Ce besoin s'explique par des facteurs externes et internes. Parallèlement à l'élargissement de la clientèle, le nombre de magasins connectés est passé de 90 en début d'année à plus de 200 à la mi-mai. Bien sûr, nous nous sommes préparés, avons réservé l'infrastructure principale et compté sur la possibilité d'une mise à l'échelle verticale et horizontale de toutes les machines virtuelles hébergées dans le cloud Yandex. Cependant, la pratique a montré: "Tout ce qui peut mal tourner ira mal." Et aujourd'hui, je veux partager les situations les plus curieuses qui se sont produites au cours de ces semaines. J'espère que notre expérience vous sera utile.

Esclave en pleine préparation au combat

Avant même le début de la pandémie, nous étions confrontés à une augmentation du nombre de requêtes adressées à nos serveurs backend. La tendance à commander de la nourriture avec livraison à domicile a commencé à prendre de l'ampleur, et avec l'introduction des premières mesures d'auto-isolement en lien avec le COVID-19, la charge a considérablement augmenté sous nos yeux tout au long de la journée. Il était nécessaire de décharger rapidement les serveurs maîtres de la base de données principale et de transférer une partie des requêtes de lecture vers les serveurs répliques (esclaves).

Nous préparions cette étape à l'avance, et 2 serveurs esclaves étaient déjà en cours d'exécution pour une telle manœuvre. Ils ont principalement travaillé sur des tâches batch pour générer des flux d'informations pour échanger des données avec des partenaires. Ces processus ont créé une charge supplémentaire et, à juste titre, ont été retirés des supports quelques mois plus tôt. 

Étant donné que la réplication a eu lieu sur l'esclave, nous avons adhéré au concept selon lequel les applications ne peuvent fonctionner avec eux qu'en mode lecture seule. Le plan de reprise après sinistre supposait qu'en cas de sinistre, nous pouvions simplement monter l'esclave à la place du maître et transférer toutes les demandes d'écriture et de lecture vers l'esclave. Cependant, nous voulions également utiliser des répliques pour les besoins du service d'analyse, de sorte que les serveurs n'étaient pas complètement configurés pour être en lecture seule, et chaque hôte avait son propre ensemble d'utilisateurs, et certains avaient des autorisations d'écriture pour enregistrer les résultats de calcul intermédiaires.

Jusqu'à un certain niveau de charge, nous disposions de suffisamment de master pour l'écriture et la lecture lors du traitement des requêtes http. À la mi-mars, juste au moment où Sbermarket a décidé de passer complètement au travail à distance, nous avons commencé à multiplier la croissance du RPS. De plus en plus de nos clients se sont isolés ou ont travaillé à domicile, ce qui s'est reflété dans les indicateurs de charge.

Les performances du "maître" n'étant plus suffisantes, nous avons commencé à transférer certaines des requêtes de lecture les plus lourdes vers la réplique. Pour diriger de manière transparente les requêtes d'écriture vers le maître et les requêtes de lecture vers l'esclave, nous avons utilisé la gemme ruby ​​"Octopus". Nous avons créé un utilisateur spécial avec le suffixe _readonly sans autorisation d'écriture. Mais à cause d'une erreur dans la configuration d'un des hosts, une partie des requêtes en écriture est allée au serveur esclave pour le compte d'un utilisateur qui avait les droits appropriés.

Le problème ne s'est pas manifesté immédiatement, car. l'augmentation de la charge a augmenté l'arriéré des esclaves. L'incohérence des données a été découverte le matin, lorsque, après les importations nocturnes, les esclaves n'ont pas « rattrapé » le maître. Nous avons attribué cela à une charge élevée sur le service lui-même et aux importations associées au lancement de nouveaux magasins. Mais il était inacceptable de fournir des données avec un retard de plusieurs heures, et nous avons basculé les processus sur le deuxième esclave analytique, car il avaitоDes ressources plus importantes et n'étaient pas chargées de requêtes de lecture (c'est ainsi que nous nous sommes expliqués l'absence de décalage de réplication).

Lorsque nous avons compris les raisons de la "propagation" de l'esclave principal, l'analytique avait déjà échoué pour la même raison. Malgré la présence de deux serveurs supplémentaires, vers lesquels nous avions prévu de transférer la charge en cas de plantage du maître, suite à une malencontreuse erreur, il s'est avéré qu'il n'y en avait pas à un moment critique.

Mais comme nous n'avons pas seulement vidé la base de données (la restauration à ce moment-là était d'environ 5 heures), mais aussi un instantané du serveur maître, nous avons réussi à lancer la réplique en 2 heures. Certes, après cela, nous étions censés rouler le journal de réplication pendant longtemps (car le processus est en mode monothread, mais c'est une toute autre histoire).

Conclusion: Après un tel incident, il est devenu clair que la pratique consistant à restreindre les écritures pour les utilisateurs devait être abandonnée et que le serveur entier devait être déclaré en lecture seule. Avec cette approche, vous pouvez être sûr que les répliques seront disponibles à un moment critique.

L'optimisation d'une seule requête lourde peut redonner vie à la base de données

Bien que nous mettions constamment à jour le catalogue sur le site, les requêtes que nous faisions aux serveurs Esclaves permettaient un léger décalage par rapport au Maître. Le temps pendant lequel nous avons découvert et éliminé le problème des esclaves «soudainement sortis de la piste» était plus que la «barrière psychologique» (pendant ce temps, les prix pouvaient être mis à jour et les clients verraient des données obsolètes), et nous avons été obligés de changer toutes les requêtes au serveur de base de données principal. Du coup, le site était lent... mais au moins ça marchait. Et pendant que le Slave récupérait, il ne nous restait plus qu'à l'optimiser. 

Pendant que les serveurs Slave récupéraient, les minutes s'éternisaient lentement, le Master restait surchargé, et nous avons concentré tous nos efforts sur l'optimisation des tâches actives selon la règle de Pareto : nous avons choisi les requêtes TOP qui donnent le plus de charge et avons commencé le réglage. Cela a été fait à la volée.

Un effet intéressant était que MySQL, chargé jusqu'aux yeux, répond même à une légère amélioration des processus. L'optimisation de quelques requêtes qui n'ont donné que 5 % de la charge totale a déjà montré un déchargement notable du processeur. En conséquence, nous avons réussi à fournir une réserve de ressources acceptable pour que le maître puisse travailler avec la base de données et obtenir le temps nécessaire pour restaurer les répliques. 

Conclusion: Même une petite optimisation vous permet de "survivre" à la surcharge pendant plusieurs heures. C'était juste assez pour nous permettre de restaurer des serveurs avec des répliques. Soit dit en passant, nous discuterons de l'aspect technique de l'optimisation des requêtes dans l'un des articles suivants. Alors abonnez-vous à notre blog si cela peut vous être utile.

Organiser le suivi de la santé des services partenaires

Nous traitons les commandes des clients, et donc nos services interagissent constamment avec des API tierces - ce sont des passerelles pour l'envoi de SMS, des plateformes de paiement, des systèmes de routage, un géocodeur, le Service fédéral des impôts et de nombreux autres systèmes. Et lorsque la charge a commencé à croître rapidement, nous avons commencé à nous heurter aux limites de l'API de nos services partenaires, auxquelles nous n'avions même pas pensé auparavant.

Un dépassement inattendu des quotas de service des partenaires peut entraîner votre propre temps d'arrêt. De nombreuses API bloquent les clients qui dépassent les limites et, dans certains cas, un excès de requêtes peut surcharger la production du partenaire. 

Par exemple, au moment de la croissance du nombre de livraisons, les services d'accompagnement ne pouvaient pas faire face aux tâches de leur distribution et de détermination des itinéraires. En conséquence, il s'est avéré que les commandes avaient été passées, mais le service qui a créé l'itinéraire ne fonctionnait pas. Je dois dire que nos logisticiens ont fait le quasi-impossible dans ces conditions, et l'interaction claire de l'équipe a permis de compenser les défaillances temporaires du service. Mais il n'est pas réaliste de traiter manuellement un tel volume de demandes en permanence, et au bout d'un certain temps on se heurterait à un écart inacceptable entre les commandes et leur exécution. 

Plusieurs mesures organisationnelles ont été prises et le travail bien coordonné de l'équipe a permis de gagner du temps en s'entendant sur de nouvelles conditions et en attendant la modernisation des services de certains partenaires. Il existe d'autres API qui offrent une endurance élevée et des tarifs impies en cas de trafic élevé. Par exemple, au début, nous avons utilisé une API de cartographie bien connue pour déterminer l'adresse du point de livraison. Mais à la fin du mois, ils ont reçu une facture ronde de près de 2 millions de roubles. Après cela, nous avons décidé de le remplacer rapidement. Je ne ferai pas de publicité, mais je dirai que nos dépenses ont considérablement diminué.
Comment nous avons survécu à l'augmentation de la charge de travail x10 à distance et quelles conclusions en avons-nous tirées

Conclusion: Il est impératif de surveiller les conditions de travail de tous les services partenaires et de les garder à l'esprit. Même s'il semble aujourd'hui qu'ils sont « avec une grande marge » pour vous, cela ne signifie pas que demain ils ne deviendront pas un obstacle à la croissance. Et, bien sûr, il vaut mieux convenir à l'avance des conditions financières des demandes accrues de service. 

Il s'avère parfois queBesoin de plus d'or"(c) n'aide pas

Nous sommes habitués à "gags" dans la base de données principale ou sur les serveurs d'application, mais lors de la mise à l'échelle, des problèmes peuvent apparaître là où ils n'étaient pas attendus.Pour la recherche en texte intégral sur le site, nous utilisons le moteur Apache Solr. Au fur et à mesure que la charge augmentait, nous avons remarqué une diminution du temps de réponse et la charge du processeur du serveur a atteint 100 %. Quoi de plus simple - donnez plus de ressources au conteneur Solr.

Au lieu de l'augmentation attendue des performances, le serveur "est simplement mort". Il s'est immédiatement chargé à 100 % et a répondu encore plus lentement. Au départ, nous avions 2 cœurs et 2 Go de RAM. Nous avons décidé de faire ce qui aide habituellement - nous avons donné au serveur 8 cœurs et 32 ​​Go. Tout est devenu bien pire (nous vous dirons exactement comment et pourquoi dans un article séparé). 

En quelques jours, nous avons compris les subtilités de ce problème et atteint des performances optimales avec 8 cœurs et 32 ​​Go. Cette configuration nous permet de continuer à augmenter la charge aujourd'hui, ce qui est très important, car la croissance ne se fait pas seulement en termes de clients, mais aussi en nombre de magasins connectés - en 2 mois leur nombre a doublé. 

Conclusion: Les méthodes standard comme "ajouter plus de fer" ne fonctionnent pas toujours. Ainsi, lors de la mise à l'échelle d'un service, vous devez bien comprendre comment il utilise les ressources et le tester à l'avance, son travail dans de nouvelles conditions. 

L'état sans état est la clé d'une mise à l'échelle horizontale simple

En général, notre équipe adhère à une approche bien connue : les services ne doivent pas avoir d'état interne (sans état) et doivent être indépendants de l'environnement d'exécution. Cela nous a permis de survivre à l'augmentation de la charge par une simple mise à l'échelle horizontale. Mais nous avions une exception de service - un gestionnaire pour les longues tâches en arrière-plan. Il était impliqué dans l'envoi d'e-mails et de SMS, le traitement d'événements, la génération de flux, l'importation de prix et de stocks et le traitement d'images. Il se trouve qu'il dépendait du stockage de fichiers local et était en un seul exemplaire. 

Lorsque le nombre de tâches dans la file d'attente du processeur augmentait (et cela se produisait naturellement avec une augmentation du nombre de commandes), les performances de l'hôte qui hébergeait le processeur et le stockage de fichiers devenaient un facteur limitant. En conséquence, la mise à jour de la gamme et des prix, l'envoi de notifications aux utilisateurs et de nombreuses autres fonctions critiques bloquées dans la file d'attente se sont arrêtées. L'équipe Ops a rapidement migré le stockage de fichiers vers un stockage réseau de type S3, ce qui nous a permis d'élever plusieurs machines puissantes pour faire évoluer le gestionnaire de tâches en arrière-plan.

Conclusion: La règle Stateless doit être respectée pour tous les composants sans exception, même s'il semble "que nous n'allons définitivement pas nous reposer ici". Il vaut mieux passer un peu de temps sur la bonne organisation du travail de tous les systèmes que de réécrire le code à la hâte et de réparer un service surchargé.

7 principes pour une croissance intensive

Malgré la disponibilité de capacités supplémentaires, dans le processus de croissance, nous avons marché sur quelques râteaux. Pendant ce temps, le nombre de commandes a augmenté de plus de 4 fois. Maintenant, nous livrons déjà plus de 17 000 commandes par jour dans 62 villes et prévoyons d'étendre encore la géographie - au premier semestre 2020, le service devrait être lancé dans toute la Russie. Afin de faire face à la charge de travail croissante, compte tenu des bosses déjà pleines, nous nous sommes inspirés de 7 principes de base pour travailler dans un environnement en croissance constante :

  1. La gestion des incidents. Nous avons créé un tableau dans Jira, où chaque incident est reflété sous la forme d'un ticket. Cela vous aidera à hiérarchiser et à accomplir les tâches liées à l'incident. En effet, au fond, ce n'est pas terrible de se tromper - c'est terrible de se tromper deux fois à la même occasion. Pour les cas où les incidents se reproduisent avant que la cause ne puisse être corrigée, des instructions d'action doivent être préparées, car lors d'une charge lourde, il est important de réagir avec une rapidité fulgurante.
  2. Surveillance requis pour tous les éléments d'infrastructure sans exception. C'est grâce à lui que nous avons pu prédire la croissance de la charge et choisir correctement les « goulots d'étranglement » pour prioriser l'élimination. Très probablement, sous une charge élevée, tout ce à quoi vous n'avez même pas pensé se cassera ou commencera à ralentir. Il est donc préférable de créer de nouvelles alertes immédiatement après l'apparition des premiers incidents afin de les surveiller et de les anticiper.
  3. Alertes correctes juste nécessaire avec une forte augmentation de la charge. Tout d'abord, ils doivent signaler exactement ce qui est cassé. Deuxièmement, il ne devrait pas y avoir beaucoup d'alertes, car l'abondance d'alertes non critiques conduit à ignorer toutes les alertes en général.
  4. Les candidatures doivent être sans état. Nous avons veillé à ce qu'il n'y ait aucune exception à cette règle. Vous avez besoin d'une indépendance totale vis-à-vis de l'environnement d'exécution. Pour ce faire, vous pouvez stocker les données partagées dans une base de données ou, par exemple, directement dans S3. Mieux encore, suivez les règles. https://12factor.net. Lors d'une forte augmentation du temps, il n'y a tout simplement aucun moyen d'optimiser le code, et vous devrez faire face à la charge en augmentant directement les ressources de calcul et la mise à l'échelle horizontale.
  5. Quotas et performance des services externes. Avec une croissance rapide, le problème peut survenir non seulement dans votre infrastructure, mais également dans un service externe. La chose la plus ennuyeuse est lorsque cela se produit non pas à cause d'un échec, mais à cause de l'atteinte de quotas ou de limites. Les services externes doivent donc évoluer aussi bien que vous-même. 
  6. Séparez les processus et les files d'attente. Cela aide beaucoup lorsqu'une prise se produit sur l'une des passerelles. Nous n'aurions pas rencontré de retards dans la transmission des données si les files d'attente pleines pour l'envoi de SMS n'interféraient pas avec l'échange de notifications entre les systèmes d'information. Et il serait plus facile d'augmenter le nombre de travailleurs s'ils travaillaient séparément.
  7. réalités financières. Quand il y a une croissance explosive des flux de données, on n'a pas le temps de penser aux tarifs et aux abonnements. Mais il faut s'en souvenir, surtout si vous êtes une petite entreprise. Une facture importante peut être fixée par le propriétaire de n'importe quelle API, ainsi que par votre fournisseur d'hébergement. Lisez donc attentivement les contrats.

Conclusion

Non sans pertes, mais nous avons survécu à cette étape, et aujourd'hui nous essayons de respecter tous les principes trouvés, et chaque machine a la capacité d'augmenter facilement les performances x4 pour faire face à certaines surprises. 

Dans les articles suivants, nous partagerons notre expérience d'enquête sur la baisse des performances dans Apache Solr, ainsi que sur l'optimisation des requêtes et sur la manière dont l'interaction avec le Service fédéral des impôts aide l'entreprise à économiser de l'argent. Abonnez-vous à notre blog pour ne rien rater, et dites-nous en commentaire si vous avez eu des soucis similaires lors de la croissance du trafic.

Comment nous avons survécu à l'augmentation de la charge de travail x10 à distance et quelles conclusions en avons-nous tirées

Seuls les utilisateurs enregistrés peuvent participer à l'enquête. se connecters'il te plait.

Avez-vous déjà eu un ralentissement/baisse de service lors d'une forte augmentation de charge due à :

  • 55,6%Incapacité à ajouter rapidement des ressources informatiques10

  • 16,7%Limites de l'infrastructure de l'hébergeur3

  • 33,3%Limites API6 tierces

  • 27,8%Violations des principes d'apatridie leurs applications5

  • 88,9%Code non optimal des services propres16

18 utilisateurs ont voté. 6 utilisateurs se sont abstenus.

Source: habr.com

Ajouter un commentaire