Optimisation de la charge sur un projet Highload avec ElasticSearch

Bonjour, Habr! Je m'appelle Maxim Vasiliev, je travaille comme analyste et chef de projet chez FINCH. Aujourd'hui, je voudrais vous dire comment, grâce à ElasticSearch, nous avons pu traiter 15 millions de requêtes en 6 minutes et optimiser la charge quotidienne sur le site d'un de nos clients. Malheureusement, nous devrons nous passer de noms, puisque nous avons le NDA, nous espérons que le contenu de l'article ne sera pas affecté. Allons-y.

Comment le projet est organisé


Sur notre backend, nous créons des services qui assurent la performance des sites et des applications mobiles de notre client. La structure générale peut être vue dans le diagramme:

image

Dans le processus, nous traitons un grand nombre de transactions: achats, paiements, opérations avec des soldes d'utilisateurs, sur lesquels nous stockons beaucoup de journaux, et importons et exportons également ces données vers des systèmes externes.

Il existe également des processus inverses lorsque nous recevons des données d'un client et les transmettons à l'utilisateur. De plus, il existe encore des processus pour travailler avec les programmes de paiement et de bonus.

Contexte court


Au départ, nous avons utilisé PostgreSQL comme seul entrepôt de données. Ses avantages standards pour les SGBD: disponibilité des transactions, langage développé d'échantillonnage des données, larges outils d'intégration; couplé à de bonnes performances, des personnes satisfaites satisfont depuis longtemps nos besoins.

Nous avons stocké absolument toutes les données dans Postgres: des transactions aux nouvelles. Mais le nombre d'utilisateurs a augmenté, et avec lui le nombre de demandes.

Pour la compréhension, le nombre annuel de sessions en 2017 sur le seul site de bureau est de 131 millions. En 2018, 125 millions 2019 est à nouveau de 130 millions. Ajoutez-y 100 à 200 millions supplémentaires à partir de la version mobile du site et de l'application mobile, et vous obtiendrez un grand nombre de demandes.

Avec la croissance du projet, Postgres a cessé de faire face à la charge, nous n'avons pas eu le temps - un grand nombre de requêtes diverses sont apparues, sous lesquelles nous n'avons pas pu créer un nombre suffisant d'index.

Nous avons réalisé qu'il y avait un besoin pour d'autres entrepôts de données qui répondraient à nos besoins et allégeraient PostgreSQL. Elasticsearch et MongoDB ont été considérés comme des options possibles. Ce dernier a perdu sur les points suivants:

  1. Vitesse d'indexation lente avec augmentation du volume de données dans les index. La vitesse d'Elastic est indépendante de la quantité de données.
  2. Pas de recherche plein texte

Nous avons donc choisi Elastic pour nous-mêmes et préparé la transition.

Passer à l'élastique


1. Nous avons entamé la transition avec un service de recherche de points de vente. Notre client dispose d'un total d'environ 70 000 points de vente, et il nécessite plusieurs types de recherches sur le site et dans l'application:

  • Recherche de texte par nom de ville
  • Géo-recherche dans un rayon donné à partir d'un certain point. Par exemple, si un utilisateur souhaite voir quels points de vente sont les plus proches de son domicile.
  • Recherche par un carré donné - l'utilisateur dessine un carré sur la carte, et on lui montre tous les points dans ce rayon.
  • Recherchez des filtres supplémentaires. Les points de vente diffèrent les uns des autres dans l'assortiment

En ce qui concerne l'organisation, à Postgres, nous avons une source de données à la fois sur la carte et sur les actualités, et dans Elastic Snapshots sont faites à partir des données originales. Le fait est qu'au départ, Postgres ne pouvait pas faire face à la recherche selon tous les critères. Non seulement il y avait de nombreux index, mais ils pouvaient également se croiser, de sorte que l'ordonnanceur Postgres s'est perdu et n'a pas compris quel index utiliser pour cela.

2. Ensuite, la section des nouvelles. Chaque jour, des publications apparaissent sur le site afin que l'utilisateur ne se perde pas dans le flux d'informations, les données doivent être triées avant d'être publiées. Pour cela, vous avez besoin d'une recherche: sur le site, vous pouvez rechercher par correspondance de texte, et en même temps connecter des filtres supplémentaires, car ils sont également créés via Elastic.

3. Ensuite, nous avons déplacé le traitement des transactions. Les utilisateurs peuvent acheter un produit spécifique sur le site et participer au tirage au sort. Après de tels achats, nous traitons une grande quantité de données, en particulier le week-end et les jours fériés. À titre de comparaison, si les jours ordinaires le nombre d'achats se situe entre 1,5 et 2 millions, les jours fériés peuvent atteindre 53 millions.

Dans le même temps, les données doivent être traitées en un minimum de temps - les utilisateurs n'aiment pas attendre un résultat pendant plusieurs jours. Vous n'atteindrez pas de tels délais grâce à Postgres - nous avons souvent des verrous, et même si nous traitons toutes les demandes, les utilisateurs ne peuvent pas vérifier s'ils ont reçu des prix ou non. Ce n'est pas très agréable pour l'entreprise, nous avons donc déplacé le traitement vers Elasticsearch.

Périodicité


Les mises à jour sont désormais configurées par événement, dans les conditions suivantes:

  1. Point de vente. Dès que des données provenant d'une source externe nous parviennent, nous commençons immédiatement la mise à jour.
  2. Nouvelles. Dès qu'une nouvelle est éditée sur le site, elle est automatiquement envoyée à Elastic.

Là encore, il convient de mentionner les avantages d'Elastic. Dans Postgres, lors de l'envoi d'une demande, vous devez attendre jusqu'à ce qu'il traite honnêtement tous les enregistrements. Vous pouvez envoyer 10 000 enregistrements à Elastic et commencer immédiatement à travailler, sans attendre que les enregistrements soient distribués sur tous les fragments. Bien sûr, certains fragments ou répliques peuvent ne pas voir les données tout de suite, mais très bientôt, tout sera disponible.

Méthodes d'intégration


Il y a 2 façons d'intégrer avec Elastic:

  1. Via le client natif sur TCP. Le pilote natif s'éteint progressivement: il n'est plus supporté, il a une syntaxe très gênante. Par conséquent, nous ne l'utilisons pratiquement pas et essayons de l'abandonner complètement.
  2. Via une interface HTTP dans laquelle vous pouvez utiliser à la fois les requêtes JSON et la syntaxe Lucene. Ce dernier est un moteur de texte qui utilise Elastic. Dans cette option, nous avons la possibilité de regrouper des requêtes JSON via HTTP. C'est l'option que nous essayons d'utiliser.

Grâce à l'interface HTTP, nous pouvons utiliser des bibliothèques qui fournissent une implémentation asynchrone du client HTTP. Nous pouvons profiter de Batch et de l'API asynchrone, qui au final donne des performances élevées, ce qui a beaucoup aidé pendant les jours d'une grande action (plus de détails ci-dessous)

Quelques chiffres à comparer:

  • Enregistrement des utilisateurs qui ont reçu des prix dans Postgres en 20 flux sans regroupements: 460 713 entrées en 42 secondes
  • Client élastique + réactif pour 10 threads + batch pour 1000 éléments: 596749 enregistrements en 11 secondes
  • Client élastique + réactif pour 10 threads + batch pour 1000 éléments: 23801684 enregistrements en 4 minutes

Maintenant, nous avons écrit un gestionnaire de requêtes HTTP qui construit JSON comme Batch / not Batch et l'envoie via n'importe quel client HTTP, quelle que soit la bibliothèque. Vous pouvez également choisir d'envoyer des demandes de manière synchrone ou asynchrone.

Dans certaines intégrations, nous utilisons toujours le client de transport officiel, mais ce n'est qu'une question de refactoring à venir. Dans le même temps, un client personnalisé construit sur la base de Spring WebClient est utilisé pour le traitement.

image

Grande promotion


Une fois par an, une grande campagne pour les utilisateurs a lieu sur le projet - c'est le même Highload, car à ce moment nous travaillons avec des dizaines de millions d'utilisateurs en même temps.

Habituellement, les pics de charge se produisent pendant les vacances, mais cette promotion est d'un niveau complètement différent. L'année précédente, le jour de la promotion, nous avons vendu 27 580 890 unités de marchandises. Les données ont été traitées pendant plus d'une demi-heure, ce qui a gêné les utilisateurs. Les utilisateurs ont reçu des prix pour leur participation, mais il est devenu clair que le processus devait être accéléré.

Début 2019, nous avons décidé que nous avions besoin d'ElasticSearch. Pendant toute une année, nous avons organisé le traitement des données reçues dans Elastic et leur sortie dans l'api de l'application mobile et du site. En conséquence, l'année suivante pendant la campagne, nous avons traité 15 131 783 enregistrements en 6 minutes.

Puisque nous avons beaucoup de gens qui veulent acheter des marchandises et participer au tirage au sort dans les promotions, il s'agit d'une mesure temporaire. Nous envoyons maintenant des informations pertinentes à Elastic, mais à l'avenir, nous prévoyons de transférer les informations d'archives des derniers mois vers Postgres en tant que référentiel permanent. Afin de ne pas obstruer l'indice élastique, qui a aussi ses limites.

Conclusion / Conclusions


Pour le moment, nous avons transféré à Elastic tous les services que nous voulions et avons suspendu pour l'instant. Nous construisons maintenant un index dans Elastic au-dessus du stockage persistant principal dans Postgres, qui prend la charge de l'utilisateur.

À l'avenir, nous prévoyons de transférer des services si nous comprenons que la demande de données devient trop diversifiée et est recherchée par un nombre illimité de colonnes. Ce n'est plus une tâche pour Postgres.

Si nous avons besoin d'une recherche en texte intégral dans la fonctionnalité, ou si nous avons beaucoup de critères de recherche différents, alors nous savons déjà que cela doit être traduit en Elastic.

⌘⌘⌘


Merci d'avoir lu. Si votre entreprise utilise également ElasticSearch et possède ses propres cas d'implémentation, dites-le nous. Il sera intéressant de savoir comment les autres ont :-)

All Articles