Comment avons-nous survécu à la forte augmentation de la charge x10 sur le site distant et quelles conclusions

Bonjour, Habr! Les deux derniers mois, nous avons vécu une situation très intéressante et je voudrais partager notre histoire de mise à l'échelle des infrastructures. Pendant ce temps, SberMarket a multiplié par 4 ses commandes et a lancé un service dans 17 nouvelles villes. La croissance explosive de la demande de produits alimentaires nous a obligés à agrandir notre infrastructure. Lisez les découvertes les plus intéressantes et utiles sous le chat.



Je m'appelle Dima Bobylev, je suis le directeur technique de SberMarket. Comme il s'agit du premier article de notre blog, je vais dire quelques mots sur moi et sur l'entreprise. L'automne dernier, j'ai participé au concours des jeunes leaders du Runet. Pour le concours, j'ai écrit une courte histoire sur la façon dont nous, chez SberMarket, voyons la culture interne et l'approche du développement du service. Et bien qu'il n'ait pas été possible de gagner le concours, j'ai formulé pour 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 spécifique. Maintenant, SberMarket croît 13 fois d'année en année, ce qui affecte le produit, nécessitant une augmentation constante du volume et du rythme de développement. Malgré cela, nous consacrons suffisamment de temps aux développeurs pour l'analyse préliminaire et l'écriture de code de haute qualité. L'approche formée aide non seulement à créer un produit fonctionnel, mais également à poursuivre sa mise à l'échelle et son développement. Grâce à cette croissance, SberMarket est déjà devenu un leader des services de livraison de nourriture: nous livrons environ 18 000 commandes par jour chaque jour, même si début février, il y en avait environ 3


500. Une fois qu'un client a demandé au coursier SberMarket de lui livrer des produits sans contact - directement sur le balcon

Mais passons aux détails. Au cours des derniers mois, nous avons activement mis à l'échelle l'infrastructure de notre entreprise. Un tel besoin s'explique par des facteurs externes et internes. Parallèlement à l'expansion 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 avons préparé, réservé l'infrastructure principale et compté sur la possibilité de mise à l'échelle verticale et horizontale de toutes les machines virtuelles situées dans le cloud Yandex. Cependant, la pratique a montré: "Tout ce qui peut mal tourner va mal". Et aujourd'hui, je veux partager les situations les plus intéressantes qui se sont produites au cours de ces semaines. J'espère que notre expérience vous sera utile.

Esclave en pleine alerte


Même avant le début de la pandémie, nous étions confrontés à une augmentation du nombre de demandes adressées à nos serveurs principaux. La tendance à commander des produits avec livraison à domicile a commencé à prendre de l'ampleur, et avec l'introduction des premières mesures d'auto-isolement en rapport avec COVID-19, la charge a augmenté de façon spectaculaire sous nos yeux toute 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 demandes de lecture vers les serveurs de réplique (esclaves).

Nous nous préparions à l'avance pour cette étape, et pour une telle manœuvre, 2 serveurs esclaves avaient déjà été lancés. Ils ont principalement travaillé sur des tâches batch de génération de flux d'informations pour l'échange de données avec des partenaires. Ces processus ont créé une charge supplémentaire et, à juste titre, ont été mis «en dehors des supports» quelques mois plus tôt. 

Comme il y avait une réplication sur Slave, nous avons adhéré au concept selon lequel les applications ne peuvent fonctionner qu'avec elles en mode lecture seule. Le plan de reprise après sinistre a suggéré qu'en cas de catastrophe, nous pourrions simplement monter l'esclave à la place du maître et basculer toutes les demandes d'écriture et de lecture sur l'esclave. Cependant, nous voulions également utiliser des répliques pour les besoins du département analytique, de sorte que les serveurs n'étaient pas complètement transférés 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 avions suffisamment d'assistants pour écrire et lire lors du traitement des requêtes http. À la mi-mars, juste au moment où Sbermarket a décidé de passer complètement à un site distant, nous avons commencé une augmentation multiple du RPS. De plus en plus de nos clients ont opté pour l'auto-isolement ou le travail à domicile, comme en témoignent les indicateurs de charge.

Les performances du «maître» n'étaient plus suffisantes, nous avons donc commencé à subir certaines des demandes de lecture les plus lourdes pour une réplique. Pour envoyer de manière transparente des demandes d'écriture au maître et de lecture à l'esclave, nous avons utilisé ruby ​​gem « Octopus". Nous avons créé un utilisateur spécial avec le suffixe _readonly sans autorisation d'écriture. Mais en raison d'une erreur dans la configuration de l'un des hôtes, une partie des demandes d'écriture est allée au serveur esclave au nom d'un utilisateur disposant des droits appropriés.

Le problème ne s'est pas manifesté immédiatement, car une charge accrue a augmenté le décalage de l'esclave. L'incohérence des données a été révélée le matin lorsque, après les importations nocturnes, les esclaves n'ont pas «rattrapé» le maître. Nous avons attribué cela à la charge élevée sur le service lui-même et à l'importation associée au lancement de nouveaux magasins. Mais donner des informations sur les nombreuses heures de retard était inacceptable, et nous sommes passés au deuxième processus analytique l'esclave, car il avait utilisé sur des ressources lshie et n'était pas chargé de requêtes de lecture (et nous nous sommes expliqués à l'absence de retard de réplication).

Lorsque nous avons compris les raisons du «fluage» de l'esclave principal, l'analyse a déjà échoué pour la même raison. Malgré la présence de deux serveurs supplémentaires, sur lesquels nous avions prévu de transférer la charge en cas de crash principal, suite à une malheureuse erreur, il s'est avéré qu'à un moment critique il n'y en avait pas.

Mais comme nous n'avons pas seulement vidé la base de données (le reste à ce moment-là était d'environ 5 heures), mais aussi un serveur maître d'instantanés, nous avons réussi à démarrer la réplique dans les 2 heures. Certes, après cela, nous devions rouler le journal de réplication pendant une longue période (car le processus est en mode monothread, mais c'est une histoire complètement différente).

: , readonly . , .

« »


Bien que nous mettions constamment à jour le catalogue sur le site, les demandes que nous avons faites aux serveurs Slave ont permis un léger décalage de la part de Master. Le temps pendant lequel nous avons découvert et éliminé le problème des «abandons soudains de la distance» des esclaves était plus qu'une «barrière psychologique» (pendant ce temps, les prix auraient pu être mis à jour et les clients auraient vu des données obsolètes), et nous avons dû basculer toutes les demandes vers le serveur de base de données principal. . En conséquence, le site a fonctionné lentement ... mais au moins il a fonctionné. Et pendant que l'esclave récupérait, nous n'avions pas d'autre choix que d'optimiser. 

Pendant que les serveurs esclaves se rétablissaient, les minutes traînaient lentement, le maître restait surchargé et nous avons consacré tous nos efforts à l'optimisation des tâches actives selon la règle de Pareto: nous avons sélectionné les requêtes TOP qui donnent la majeure partie de la charge et avons commencé à régler. Cela a été fait directement "à la volée".

Un effet intéressant a été que MySQL chargé dans le globe oculaire répond même à une légère amélioration des processus. L'optimisation d'une paire de demandes, qui ne représentait que 5% de la charge totale, montrait déjà un déchargement tangible du processeur. En conséquence, nous avons pu fournir un approvisionnement acceptable en ressources pour que Master 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" pendant une surcharge pendant plusieurs heures. C'était juste assez pour nous lors de la récupération des serveurs avec des répliques. Soit dit en passant, nous discuterons du côté 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 des performances des services partenaires


Nous sommes engagés dans le traitement des commandes des clients, et donc nos services interagissent constamment avec des API tierces - ce sont des passerelles pour envoyer des SMS, des plates-formes de paiement, des systèmes de routage, un géocodeur, le Federal Tax Service et de nombreux autres systèmes. Et lorsque la charge a commencé à augmenter rapidement, nous avons commencé à nous reposer sur les limitations API de nos partenaires de service, auxquelles nous n'avions même pas pensé auparavant.

Un excès inattendu de quotas pour les services d'affiliation peut entraîner des temps d'arrêt de votre choix. De nombreuses API bloquent les clients qui dépassent les limites et, dans certains cas, un excès de demandes peut surcharger la production avec un partenaire. 

Par exemple, au moment d'augmenter le nombre de livraisons, les services d'accompagnement ne pouvaient pas faire face aux tâches de leur distribution, détermination des itinéraires. En conséquence, il s'est avéré que les commandes ont été passées et le service créant l'itinéraire ne fonctionne pas. Je dois dire que nos logisticiens ont rendu cela presque impossible dans ces conditions, et l'interaction claire de l'équipe a aidé à compenser les pannes de service temporaires. Mais un tel volume d'applications est impossible à traiter manuellement manuellement, et après un certain temps, nous rencontrerions un écart inacceptable entre les ordres et leur exécution. 

Un certain nombre de mesures organisationnelles ont été prises et le travail coordonné de l'équipe a permis de gagner du temps pendant que nous convenions de nouvelles conditions et attendions la modernisation des services de certains partenaires. Il existe d'autres API qui vous plairont avec une endurance élevée et des tarifs impies en cas de trafic élevé. Par exemple, au début, nous avons utilisé une API de mappage bien connue pour déterminer l'adresse d'un point de livraison. Mais à la fin du mois, ils ont reçu une bonne facture de près de 2 millions de roubles. Après cela, ils ont décidé de le remplacer rapidement. Je ne ferai pas de publicité, mais je dirai que nos dépenses ont considérablement diminué.

: . , « », , . , ,   . 

, « » ()


Nous sommes habitués à «brancher» la base de données principale ou les serveurs d'applications, 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. Avec une augmentation de la charge, nous avons noté une diminution du temps de réponse, et la charge du processeur serveur a atteint 100%. Quoi de plus simple - nous donnerons plus de ressources au conteneur avec Solr.

Au lieu du gain de performances attendu, 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 (exactement comment et pourquoi - nous le dirons dans un article séparé). 

Pendant plusieurs 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 n'est pas seulement en termes de clients, mais aussi en nombre de magasins connectés - sur 2 mois leur nombre a doublé. 

Conclusion: les méthodes standard telles que «ajouter plus de fer» ne fonctionnent pas toujours. Ainsi, lors de l'extension d'un service, vous devez bien comprendre comment il utilise les ressources et pré-tester son fonctionnement dans de nouvelles conditions. 

Sans état - la clé d'une mise à l'échelle horizontale facile


En général, notre équipe adhère à une approche bien connue: les services ne doivent pas avoir d'état sans état et doivent être indépendants de l'environnement d'exécution. Cela nous a permis de survivre à la croissance 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 engagé dans l'envoi d'emails 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 que cela dépendait du stockage de fichiers local et était en une seule copie. 

Lorsque le nombre de tâches dans la file d'attente du processeur a augmenté (et cela s'est naturellement produit avec une augmentation du nombre de commandes), les performances de l'hôte hébergeant le processeur et le stockage de fichiers sont devenues un facteur limitant. En conséquence, la mise à jour de l'assortiment et des prix, l'envoi de notifications aux utilisateurs et de nombreuses autres fonctions critiques bloquées dans la file d'attente ont cessé. 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 adapter le gestionnaire de tâches en arrière-plan.

Conclusion: La règle des apatrides doit être respectée pour tous les composants, sans exception, même s'il semble "que nous ne dérangions pas du tout". Il vaut mieux consacrer un peu de temps à la bonne organisation du travail de tous les systèmes que de réécrire le code à la hâte et de réparer le service qui subit une surcharge.

7 principes pour une croissance intense


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 notre géographie - au premier semestre 2020, le service devrait être lancé dans toute la Russie. Afin de faire face à la charge croissante, en tenant compte des bosses déjà pleines, nous avons développé pour nous-mêmes 7 principes de base du travail dans des conditions de croissance constante:

  1. -. Jira,   . . — . , , , , .
  2. . « » . , , . , .
  3. . -, . -, , .
  4. stateless. , . . , , S3. https://12factor.net. , .
  5. . , . , , - . , . 
  6. . , . , SMS . , .
  7. . , . , , . API, -. .


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

Dans les articles suivants, nous partagerons notre expérience en matière d'enquête sur la subsidence des performances dans Apache Solr, ainsi que sur l'optimisation des requêtes et la façon dont l'interaction avec le FTS permet à l'entreprise d'économiser de l'argent. Abonnez-vous à notre blog pour ne rien manquer et dites-nous dans les commentaires si vous avez eu de tels problèmes pendant la croissance du trafic.


All Articles