Nous aimons tous les histoires. Nous aimons nous asseoir près du feu et parler de nos victoires passées, de nos batailles ou simplement de notre expérience de travail.
Aujourd'hui est un tel jour. Et même si vous n'êtes pas au feu maintenant, mais nous avons une histoire pour vous. L'histoire de la façon dont nous avons commencé à travailler avec le stockage dans Tarantool.
Il était une fois dans notre entreprise une paire de «monolithes» et un «plafond» pour tous, vers lesquels ces monolithes se rapprochaient lentement mais sûrement, limitant le vol de notre entreprise, notre développement. Et il y avait une compréhension sans ambiguïté: un jour, nous toucherons durement ce plafond.
C'est maintenant que nous sommes dominés par l'idéologie de diviser tout et tout le monde, de l'équipement à la logique métier. En conséquence, nous avons, par exemple, deux DC qui sont pratiquement indépendants au niveau du réseau. Et puis tout était complètement différent.
Aujourd'hui, il existe un tas d'outils et d'outils pour faire des changements sous forme de CI / CD, K8S, etc. A l'époque «monolithique», nous n'avions pas besoin d'autant de mots étrangers. Il suffisait juste de réparer le "stockage" dans la base de données.
Mais le temps passait et le nombre de demandes allait de l'avant, déclenchant parfois des RPS au-delà de nos capacités. Avec l'entrée sur le marché des pays de la CEI, la charge sur le processeur de base de données du premier monolithe n'est pas tombée en dessous de 90%, et le RPS est resté au niveau de 2400. Et il ne s'agissait pas seulement de petits sélecteurs, mais de requêtes lourdes avec un tas de vérifications et de JOINs qui pouvaient être exécutés presque la moitié des données sur le fond d'un grand IO.
Lorsque les ventes à part entière du Black Friday ont commencé à apparaître sur la scène - et Wildberries a commencé à en tenir l'une des premières en Russie - la situation est devenue assez triste. Après tout, la charge de ces jours est multipliée par trois.
Oh, ces «temps monolithiques»! Je suis sûr que vous avez également rencontré quelque chose de similaire et que vous ne comprenez toujours pas comment cela pourrait vous arriver.
Que pouvez-vous faire - la mode est inhérente à la technologie. Il y a encore 5 ans, nous avons dû repenser l'un de ces mods sous la forme d'un site existant sur .NET et MS SQL-server, qui gardait soigneusement toute la logique du site lui-même. Il l'a gardé si soigneusement que scier un tel monolithe s'est avéré être un plaisir long et assez difficile.
Une petite digression.
Lors de divers événements, je dis: "Si vous n'avez pas vu le monolithe, alors vous n'avez pas grandi!" Je suis intéressé par votre avis à ce sujet, écrivez-le, s'il vous plaît, dans les commentaires.
Un bruit de tonnerre
Revenons à notre "feu de joie". Pour répartir la charge de fonctionnalités «monolithiques», nous avons décidé de diviser le système en microservices basés sur des technologies open source. Parce qu'à tout le moins, ils sont moins chers à l'échelle. Et la compréhension que nous aurions à évoluer (et beaucoup) nous avions 100%. En effet, déjà à cette époque, il s'est avéré entrer sur les marchés des pays voisins, et le nombre d'enregistrements, ainsi que le nombre de commandes, ont commencé à augmenter encore plus.
Après avoir analysé les premiers candidats à quitter le monolithe dans les microservices, nous nous sommes rendu compte que dans 80% d'entre eux, 99% d'entre eux écrivent à partir des systèmes de back-office et lisent à partir des systèmes frontaux. Tout d'abord, cela concernait quelques sous-systèmes qui étaient importants pour nous - les données des utilisateurs et un système de calcul du coût final des marchandises sur la base d'informations sur les remises et coupons clients supplémentaires.
Retrait. Maintenant, il est effrayant d'imaginer, mais en plus des sous-systèmes susmentionnés, des catalogues de produits, un panier d'utilisateurs, un système de recherche de produits, un système de filtrage des catalogues de produits et divers systèmes de recommandation ont également été retirés de notre monolithe. Pour le fonctionnement de chacun d'eux, il existe des classes distinctes de systèmes étroitement affûtés, mais à un moment donné, ils vivaient tous dans une «petite maison».
Nous avions prévu de transférer des données sur nos clients vers un système fragmenté. La suppression de la fonctionnalité de calcul du coût final des marchandises nécessitait une bonne évolutivité en lecture, car elle créait la plus grande charge RPS et était la plus difficile à implémenter pour la base de données (beaucoup de données sont impliquées dans le processus de calcul).
En conséquence, nous avons un système qui fonctionne bien avec Tarantool.
À cette époque, des schémas de travail avec plusieurs centres de données sur des machines virtuelles et matérielles ont été choisis pour le fonctionnement des microservices. Comme le montrent les figures, les options de réplication Tarantool ont été appliquées dans les modes maître-maître et maître-esclave.
Architecture. Option 1. Service utilisateur
À l'heure actuelle, il existe 24 fragments, dont chacun a 2 instances (une pour chaque contrôleur de domaine), toutes en mode maître-maître.
Au-dessus de la base de données se trouvent des applications qui accèdent aux répliques de base de données. Les applications fonctionnent avec Tarantool via notre bibliothèque personnalisée, qui implémente l'interface du pilote Tarantool Go. Elle voit toutes les répliques et peut travailler avec le maître pour lire et écrire. En fait, il implémente le modèle de jeu de répliques, qui ajoute la logique de sélection des répliques, d'effectuer des tentatives, un disjoncteur et une limite de débit.
Dans le même temps, il est possible de configurer la politique de choix d'un réplica dans le contexte d'un fragment. Par exemple, roundrobin.
Architecture. Option 2. Service de calcul du coût final des marchandises Il y a
plusieurs mois, la plupart des demandes de calcul du coût final des marchandises ont été adressées à un nouveau service, qui, en principe, fonctionne sans bases de données, mais il y a quelque temps, il a été traité à 100% par le service avec Tarantool sous le capot.
La base de données de service est composée de 4 maîtres dans lesquels le synchroniseur collecte des données, et chacun de ces maîtres de réplication distribue les données à des répliques en lecture seule. Chaque maître a environ 15 de ces lignes.
Dans le premier et dans le second schéma, si un contrôleur de domaine n'est pas disponible, l'application peut recevoir des données dans le second.
Il convient de noter que la réplication dans Tarantool est assez flexible et configurable à l'exécution. Dans d'autres systèmes, il y a eu des difficultés. Par exemple, la modification des paramètres max_wal_senders et max_replication_slots dans PostgreSQL nécessite le redémarrage de l'assistant, ce qui, dans certains cas, peut conduire à une déconnexion entre l'application et le SGBD.
Cherchez et vous trouverez!
Pourquoi ne l'avons-nous pas fait "comme des gens normaux", mais avons-nous choisi une voie atypique? Cela dépend de ce qui est considéré comme normal. De nombreuses personnes créent généralement un cluster à partir de Mongo et le répartissent sur trois DC géo-distribués.
A cette époque, nous avions déjà deux projets sur Redis. Le premier est un cache et le second est un stockage persistant pour des données pas trop critiques. C'était assez difficile avec lui, en partie à cause de notre faute. Parfois, des volumes assez importants étaient en jeu et de temps en temps, le site se sentait mal. Nous avons utilisé ce système dans la version maître-esclave. Et il y a eu de nombreux cas où quelque chose est arrivé au maître et la réplication s'est interrompue.
Autrement dit, Redis convient aux tâches sans état, pas aux tâches avec état. En principe, cela permettait de résoudre la plupart des problèmes, mais seulement s'il s'agissait de solutions clé-valeur avec une paire d'indices. Mais à l'époque, Redis était assez triste avec la persistance et la réplication. De plus, il y a eu des plaintes concernant la performance.
Penser à MySQL et PostgreSQL. Mais le premier n'a pas pris racine avec nous, et le second est un produit assez sophistiqué en soi, et il serait inapproprié de construire des services simples dessus.
Nous avons essayé RIAK, Cassandra, même une base de données de graphes. Ce sont toutes des solutions de niche qui ne correspondaient pas au rôle d'outil universel général de création de services.
Finalement, nous nous sommes installés sur Tarantool.
Nous l'avons contacté lorsqu'il était en version 1.6. Nous nous sommes intéressés à cela par la symbiose clé-valeur et la fonctionnalité d'une base de données relationnelle. Il existe des index, des transactions et des espaces secondaires, ils sont comme des tables, mais pas simples, vous pouvez y stocker un nombre différent de colonnes. Mais les fonctionnalités tueuses de Tarantool étaient des index secondaires combinés avec des valeurs-clés et des transactions.
La communauté russophone réactive a également joué un rôle, prête à aider dans le chat. Nous l'avons activement utilisé et avons vécu directement dans le chat. Et n'oubliez pas une décente persistante sans gaffes et montants évidents. Si vous regardez notre histoire avec Tarantool, nous avons eu beaucoup de difficultés et de faux problèmes avec la réplication, mais nous n'avons jamais perdu de données à cause de sa faute!
La mise en œuvre a bien commencé
À cette époque, notre principale pile de développement était .NET, auquel il n'y avait pas de connecteur pour Tarantool. Nous avons immédiatement commencé à faire quelque chose dans Go. Lua fonctionnait plutôt bien aussi. Le principal problème à l'époque était le débogage: dans .NET tout est magnifique avec cela, et après cela, il était difficile de plonger dans le monde de Lua embarqué, quand vous, en plus des journaux, n'avez pas de débogage, c'était difficile. De plus, pour une raison quelconque, la réplication s'effondrait périodiquement, j'ai donc dû me plonger dans la structure du moteur Tarantool. Le chat a aidé avec cela, dans une moindre mesure - la documentation, parfois regardé le code. A cette époque, la documentation était médiocre.
Ainsi, en quelques mois, j'ai réussi à remplir les plans et à obtenir des résultats décents en travaillant avec Tarantool. Nous avons formalisé les développements de référence dans git, ce qui a aidé à la formation de nouveaux microservices. Par exemple, lorsque la tâche est survenue: pour créer un autre microservice, le développeur a regardé le code source de la solution de référence dans le référentiel, et il n'a pas fallu plus d'une semaine pour en créer un nouveau.
C'étaient des moments spéciaux. Classiquement, il était alors possible d'aller voir l'administrateur à la table suivante et de demander: «Donnez-moi une machine virtuelle». Trente minutes plus tard, vous aviez déjà la voiture. Vous vous êtes connecté, vous avez tout installé et vous avez du trafic.
Aujourd'hui, cela ne fonctionnera pas comme ça: vous devez terminer la surveillance, vous connecter au service, couvrir la fonctionnalité avec des tests, commander une machine virtuelle ou fournir à Kuber, etc. En général, ce sera mieux, bien que plus long et plus gênant.
Diviser pour régner. Et Lua?
Il y avait un sérieux dilemme: certaines équipes ne pouvaient pas déployer de manière fiable des changements dans un service avec beaucoup de logique dans Lua. Cela s'accompagnait souvent de l'inopérabilité du service.
Autrement dit, les développeurs préparent une sorte de changement. Tarantool démarre la migration et la réplique a toujours l'ancien code; du DDL, autre chose, y arrive par réplication, et le code s'effondre simplement, car il n'est pas pris en compte. En conséquence, la procédure de mise à jour pour les administrateurs a été planifiée sur la feuille A4: arrêter la réplication, la mettre à jour, activer la réplication, la désactiver ici, la mettre à jour là. Cauchemar!
En conséquence, maintenant, nous essayons le plus souvent de ne rien faire à Lua. Il suffit d'utiliser iproto (un protocole binaire pour communiquer avec le serveur), et c'est tout. C'est peut-être un manque de connaissances chez les développeurs, mais de ce point de vue, le système est complexe.
Nous ne suivons pas toujours aveuglément ce scénario. Aujourd'hui, nous n'avons pas le noir et blanc: soit tout est en Lua, soit tout est en Go. Nous comprenons déjà comment vous pouvez les combiner pour ne pas avoir de problèmes de migration plus tard.
Où est Tarantool maintenant?
Tarantool est utilisé dans le service pour calculer le coût final des marchandises, en tenant compte des coupons de réduction, alias «Promoteur». Comme je l'ai dit plus tôt, maintenant il prend sa retraite: il est remplacé par un nouveau service de catalogue avec des prix pré-calculés, mais il y a six mois, tous les calculs ont été effectués dans le Promoteur. Auparavant, la moitié de sa logique était écrite en Lua. Il y a deux ans, un stockage a été fait à partir du service, et la logique a été réécrite en Go, car la mécanique des remises a légèrement changé et le service manquait de performances.
L'un des services les plus critiques est le profil utilisateur. Autrement dit, tous les utilisateurs de Wildberries sont stockés dans Tarantool, et il y en a environ 50 millions. Un système partagé par ID utilisateur, réparti sur plusieurs DC avec une connexion aux services Go.
Selon RPS, "Promoter" était autrefois le leader, atteignant 6 000 demandes. À un moment donné, nous avions entre 50 et 60 exemplaires. Aujourd'hui, le leader du RPS est les profils d'utilisateurs, environ 12 000. Ce service utilise le partitionnement personnalisé avec une division par plages d'ID utilisateur. Le service dessert plus de 20 machines, mais c'est trop, nous prévoyons de réduire les ressources allouées, car la capacité de 4-5 machines est suffisante pour cela.
Le service de session est notre premier service sur vshard et cartouche. La configuration de vshard et la mise à jour de Cartridge ont nécessité un peu de travail de notre part, mais à la fin, tout a fonctionné.
Le service d'affichage des différentes bannières sur le site et dans l'application mobile a été l'un des premiers à être diffusé directement sur Tarantool. Ce service se distingue par le fait qu'il a 6-7 ans, il est toujours en service et n'a jamais redémarré. La réplication était maître-maître. Jamais rien cassé.
Il existe un exemple d'utilisation de Tarantool pour une fonctionnalité de référence rapide dans un système d'entrepôt pour vérifier rapidement les informations dans certains cas. Nous avons essayé d'utiliser Redis pour cela, mais les données en mémoire prenaient plus de place que Tarantool.
Les services de liste d'attente, les abonnements clients, les histoires à la mode et les produits mis en rayon fonctionnent également avec Tarantool. Le dernier service en mémoire est d'environ 120 Go. C'est le service le plus complet de ce qui précède.
Conclusion
Les index secondaires combinés à des propriétés de valeur-clé et de transaction font de Tarantool un outil idéal pour les architectures de microservices. Cependant, nous avons rencontré des difficultés lors du déploiement des modifications des services avec beaucoup de logique dans Lua - les services ont souvent cessé de fonctionner. Nous n'avons pas pu vaincre cela, et avec le temps, nous sommes arrivés à différentes combinaisons de Lua et Go: nous savons où utiliser une langue et où en utiliser une autre.
Que lire d'autre sur le sujet
- Nous créons à partir de zéro une application très chargée sur Tarantool habr.com/ru/company/mailru/blog/510440
- Le choix du leader de confiance de Tarantool Cartridge habr.com/ru/company/mailru/blog/513912
- Chaîne Tarantool Telegram avec actualités produits t.me/tarantool_news
- Discutez de Tarantool dans le chat communautaire t.me/tarantoolru