Comment nous avons implémenté le cache sur la base de données Tarantool

Bonjour!

Je veux partager avec vous une histoire sur l'implémentation du cache sur la base de données Tarantool et mes fonctionnalités de travail.
Je travaille en tant que développeur Java dans une entreprise de télécommunications. La tâche principale: la mise en œuvre de la logique métier pour la plateforme que l'entreprise a achetée au vendeur. Parmi les premières fonctionnalités, il s'agit du travail de savon et de l'absence presque totale de mise en cache, sauf dans la mémoire JVM. Tout cela est bien sûr bon jusqu'à ce que le nombre d'instances d'application dépasse deux douzaines ...

Au fil des travaux et de l'émergence d'une compréhension des fonctionnalités de la plateforme, une tentative de mise en cache a été tentée. A cette époque, MongoDB était déjà lancé, et en conséquence, nous n'avons pas obtenu de résultats positifs spéciaux comme dans le test.

Dans une nouvelle recherche d'alternatives et de conseils de mon bon ami mr_elzor , il a été décidé d'essayer la base de données Tarantool.

Dans une étude superficielle, seul le doute est apparu en lua, car je n'y avais pas écrit du mot «complètement». Mais repoussant tous les doutes, il se mit à installer. Concernant les réseaux fermés et les pare-feu, je pense que peu de gens sont intéressés, mais je vous conseille d'essayer de les contourner et de tout mettre à partir de sources publiques.

Serveurs de test avec configuration: 8 CPU, 16 Go de RAM, 100 Go de disque dur, Debian 9.4.

L'installation était conforme aux instructions du site. Et donc j'ai eu un exemple d'option. L'idée est immédiatement apparue d'une interface visuelle avec laquelle le support fonctionnerait commodément. Lors d'une recherche rapide, j'ai trouvé et configuré tarantool-admin . Fonctionne chez Docker et couvre à 100% les tâches de support, du moins pour l'instant.

Mais parlons de plus intéressant.

L'idée suivante a été de configurer ma version dans la configuration maître-esclave au sein du même serveur, car la documentation ne contient que des exemples avec deux serveurs différents.

Après avoir passé un peu de temps à comprendre lua et à décrire la configuration, je lance l'assistant.

# systemctl start tarantool@master Job for tarantool@master.service failed because the control process exited with error code. See "systemctl status tarantool@master.service" and "journalctl -xe" for details. 

Je tombe immédiatement dans une stupeur et je ne comprends pas pourquoi l’erreur est, mais je vois qu’elle est en état de «chargement».

 # systemctl status tarantool@master ● tarantool@master.service - Tarantool Database Server Loaded: loaded (/lib/systemd/system/tarantool@.service; enabled; vendor preset: enabled) Active: activating (start) since Tue 2019-02-19 17:03:24 MSK; 17s ago Docs: man:tarantool(1) Process: 20111 ExecStop=/usr/bin/tarantoolctl stop master (code=exited, status=0/SUCCESS) Main PID: 20120 (tarantool) Status: "loading" Tasks: 5 (limit: 4915) CGroup: /system.slice/system-tarantool.slice/tarantool@master.service └─20120 tarantool master.lua <loading> Feb 19 17:03:24 tarantuldb-tst4 systemd[1]: Starting Tarantool Database Server... Feb 19 17:03:24 tarantuldb-tst4 tarantoolctl[20120]: Starting instance master... Feb 19 17:03:24 tarantuldb-tst4 tarantoolctl[20120]: Run console at unix/:/var/run/tarantool/master.control Feb 19 17:03:24 tarantuldb-tst4 tarantoolctl[20120]: started 

Je lance l'esclave:

 # systemctl start tarantool@slave2 Job for tarantool@slave2.service failed because the control process exited with error code. See "systemctl status tarantool@slave2.service" and "journalctl -xe" for details. 

Et je vois la même erreur. Ici, je commence généralement à tendre et à ne pas comprendre ce qui se passe, car il n'y a absolument rien dans la documentation à ce sujet ... Mais en vérifiant le statut, je vois qu'il n'a pas du tout démarré, bien qu'il indique que le statut est "en cours d'exécution":

 # systemctl status tarantool@slave2 ● tarantool@slave2.service - Tarantool Database Server Loaded: loaded (/lib/systemd/system/tarantool@.service; enabled; vendor preset: enabled) Active: failed (Result: exit-code) since Tue 2019-02-19 17:04:52 MSK; 27s ago Docs: man:tarantool(1) Process: 20258 ExecStop=/usr/bin/tarantoolctl stop slave2 (code=exited, status=0/SUCCESS) Process: 20247 ExecStart=/usr/bin/tarantoolctl start slave2 (code=exited, status=1/FAILURE) Main PID: 20247 (code=exited, status=1/FAILURE) Status: "running" Feb 19 17:04:52 tarantuldb-tst4 systemd[1]: tarantool@slave2.service: Unit entered failed state. Feb 19 17:04:52 tarantuldb-tst4 systemd[1]: tarantool@slave2.service: Failed with result 'exit-code'. Feb 19 17:04:52 tarantuldb-tst4 systemd[1]: tarantool@slave2.service: Service hold-off time over, scheduling restart. Feb 19 17:04:52 tarantuldb-tst4 systemd[1]: Stopped Tarantool Database Server. Feb 19 17:04:52 tarantuldb-tst4 systemd[1]: tarantool@slave2.service: Start request repeated too quickly. Feb 19 17:04:52 tarantuldb-tst4 systemd[1]: Failed to start Tarantool Database Server. Feb 19 17:04:52 tarantuldb-tst4 systemd[1]: tarantool@slave2.service: Unit entered failed state. Feb 19 17:04:52 tarantuldb-tst4 systemd[1]: tarantool@slave2.service: Failed with result 'exit-code'. 

Mais en même temps, le maître a commencé à travailler:

 # ps -ef | grep taran taranto+ 20158 1 0 17:04 ? 00:00:00 tarantool master.lua <running> root 20268 2921 0 17:06 pts/1 00:00:00 grep taran 

Le redémarrage de l'esclave n'aide pas. Je me demande pourquoi?

J'arrête le maître. Et effectuez les actions dans l'ordre inverse.

Je vois que l'esclave essaie de démarrer.

 # ps -ef | grep taran taranto+ 20399 1 0 17:09 ? 00:00:00 tarantool slave2.lua <loading> 

Je lance l'assistant et constate qu'il n'a pas augmenté et est généralement passé au statut d'orphelin, tandis que l'esclave est généralement tombé.

 # ps -ef | grep taran taranto+ 20428 1 0 17:09 ? 00:00:00 tarantool master.lua <orphan> 

Cela devient encore plus intéressant.

Je vois dans les journaux de l'esclave qu'il a même vu le maître et essayé de se synchroniser.

 2019-02-19 17:13:45.113 [20751] iproto/101/main D> binary: binding to 0.0.0.0:3302... 2019-02-19 17:13:45.113 [20751] iproto/101/main I> binary: bound to 0.0.0.0:3302 2019-02-19 17:13:45.113 [20751] iproto/101/main D> binary: listening on 0.0.0.0:3302... 2019-02-19 17:13:45.113 [20751] iproto D> cpipe_flush_cb: locking &endpoint->mutex 2019-02-19 17:13:45.113 [20751] iproto D> cpipe_flush_cb: unlocking &endpoint->mutex 2019-02-19 17:13:45.113 [20751] main D> cbus_endpoint_fetch: locking &endpoint->mutex 2019-02-19 17:13:45.113 [20751] main D> cbus_endpoint_fetch: unlocking &endpoint->mutex 2019-02-19 17:13:45.113 [20751] main/101/slave2 I> connecting to 1 replicas 2019-02-19 17:13:45.113 [20751] main/106/applier/replicator@tarantuldb-t D> => CONNECT 2019-02-19 17:13:45.114 [20751] main/106/applier/replicator@tarantuldb-t I> remote master 825af7c3-f8df-4db0-8559-a866b8310077 at 10.78.221.74:3301 running Tarantool 1.10.2 2019-02-19 17:13:45.114 [20751] main/106/applier/replicator@tarantuldb-t D> => CONNECTED 2019-02-19 17:13:45.114 [20751] main/101/slave2 I> connected to 1 replicas 2019-02-19 17:13:45.114 [20751] coio V> loading vylog 14 2019-02-19 17:13:45.114 [20751] coio V> done loading vylog 2019-02-19 17:13:45.114 [20751] main/101/slave2 I> recovery start 2019-02-19 17:13:45.114 [20751] main/101/slave2 I> recovering from `/var/lib/tarantool/cache_slave2/00000000000000000014.snap' 2019-02-19 17:13:45.114 [20751] main/101/slave2 D> memtx_tuple_new(47) = 0x7f99a4000080 2019-02-19 17:13:45.114 [20751] main/101/slave2 I> cluster uuid 4035b563-67f8-4e85-95cc-e03429f1fa4d 2019-02-19 17:13:45.114 [20751] main/101/slave2 D> memtx_tuple_new(11) = 0x7f99a4004080 2019-02-19 17:13:45.114 [20751] main/101/slave2 D> memtx_tuple_new(17) = 0x7f99a4008068 

Et la tentative a réussi:

 2019-02-19 17:13:45.118 [20751] main/101/slave2 D> memtx_tuple_new(40) = 0x7f99a40004c0 2019-02-19 17:13:45.118 [20751] main/101/slave2 I> assigned id 1 to replica 825af7c3-f8df-4db0-8559-a866b8310077 2019-02-19 17:13:45.118 [20751] main/101/slave2 D> memtx_tuple_new(40) = 0x7f99a4000500 2019-02-19 17:13:45.118 [20751] main/101/slave2 I> assigned id 2 to replica 403c0323-5a9b-480d-9e71-5ba22d4ccf1b 2019-02-19 17:13:45.118 [20751] main/101/slave2 I> recover from `/var/lib/tarantool/slave2/00000000000000000014.xlog' 2019-02-19 17:13:45.118 [20751] main/101/slave2 I> done `/var/lib/tarantool/slave2/00000000000000000014.xlog' 

Cela a même commencé:

 2019-02-19 17:13:45.119 [20751] main/101/slave2 D> systemd: sending message 'STATUS=running' 

Mais pour des raisons inconnues, il a perdu la connexion et est tombé:

 2019-02-19 17:13:45.129 [20751] main/101/slave2 D> SystemError at /build/tarantool-1.10.2.146/src/coio_task.c:416 2019-02-19 17:13:45.129 [20751] main/101/slave2 tarantoolctl:532 E> Start failed: /usr/local/share/lua/5.1/http/server.lua:1146: Can't create tcp_server: Input/output error 

Essayer de redémarrer l'esclave n'aide pas.

Supprimez maintenant les fichiers créés par les instances. Dans mon cas, je supprime tout du répertoire / var / lib / tarantool.

Je commence l'esclave d'abord, et ensuite seulement le maître. Et voilà ...

 # ps -ef | grep tara taranto+ 20922 1 0 17:20 ? 00:00:00 tarantool slave2.lua <running> taranto+ 20933 1 1 17:21 ? 00:00:00 tarantool master.lua <running> 

Je n'ai trouvé aucune explication à ce comportement, sauf en tant que «fonctionnalité de ce logiciel».
Cette situation apparaîtra à chaque fois si votre serveur a complètement redémarré.

Après une analyse plus approfondie de l'architecture de ce logiciel, il s'avère qu'il est prévu d'utiliser un seul vCPU pour une instance et de nombreuses autres ressources restent gratuites.

Dans l'idéologie de n vCPU, nous pouvons élever le maître et n-2 esclaves pour la lecture.

Étant donné que sur le serveur de test 8 vCPU, nous pouvons augmenter le maître et 6 instances pour la lecture.
Je copie le fichier pour esclave, corrige les ports et exécute, c'est-à-dire quelques esclaves supplémentaires sont ajoutés.

Important! Lors de l'ajout d'une autre instance, vous devez l'enregistrer sur l'assistant.
Mais vous devez d'abord démarrer un nouvel esclave, puis seulement redémarrer le maître.

Exemple


J'avais déjà une configuration en cours d'exécution avec un assistant et deux esclaves.

J'ai décidé d'ajouter un troisième esclave.

Je l'ai enregistré sur le maître et l'ai redémarré en premier, et voici ce que j'ai vu:

 # ps -ef | grep tara taranto+ 20922 1 0 Feb19 ? 00:00:29 tarantool slave2.lua <running> taranto+ 20965 1 0 Feb19 ? 00:00:29 tarantool slave3.lua <running> taranto+ 21519 1 0 09:16 ? 00:00:00 tarantool master.lua <orphan> 

C'est-à-dire notre maître est devenu un solitaire, et la réplication s'est effondrée.

Le démarrage d'un nouvel esclave n'aidera plus et entraînera une erreur:

 # systemctl restart tarantool@slave4 Job for tarantool@slave4.service failed because the control process exited with error code. See "systemctl status tarantool@slave4.service" and "journalctl -xe" for details. 

Et dans les journaux, j'ai vu une petite entrée informative:

 2019-02-20 09:20:10.616 [21601] main/101/slave4 I> bootstrapping replica from 3c77eb9d-2fa1-4a27-885f-e72defa5cd96 at 10.78.221.74:3301 2019-02-20 09:20:10.617 [21601] main/106/applier/replicator@tarantuldb-t I> can't join/subscribe 2019-02-20 09:20:10.617 [21601] main/106/applier/replicator@tarantuldb-t xrow.c:896 E> ER_READONLY: Can't modify data because this instance is in read-only mode. 2019-02-20 09:20:10.617 [21601] main/106/applier/replicator@tarantuldb-t D> => STOPPED 2019-02-20 09:20:10.617 [21601] main/101/slave4 xrow.c:896 E> ER_READONLY: Can't modify data because this instance is in read-only mode. 2019-02-20 09:20:10.617 [21601] main/101/slave4 F> can't initialize storage: Can't modify data because this instance is in read-only mode. 

Nous arrêtons l'assistant et démarrons un nouvel esclave. Il y aura également une erreur, comme au premier démarrage, mais nous verrons qu'il est en cours de chargement.

 # ps -ef | grep tara taranto+ 20922 1 0 Feb19 ? 00:00:29 tarantool slave2.lua <running> taranto+ 20965 1 0 Feb19 ? 00:00:30 tarantool slave3.lua <running> taranto+ 21659 1 0 09:23 ? 00:00:00 tarantool slave4.lua <loading> 

Mais lorsque vous démarrez master, le nouvel esclave se bloque et master ne suit pas l'état en cours d'exécution.

 # ps -ef | grep tara taranto+ 20922 1 0 Feb19 ? 00:00:29 tarantool slave2.lua <running> taranto+ 20965 1 0 Feb19 ? 00:00:30 tarantool slave3.lua <running> taranto+ 21670 1 0 09:23 ? 00:00:00 tarantool master.lua <orphan> 

Dans cette situation, il n'y a qu'une seule issue. Comme je l'ai écrit plus tôt, je supprime les fichiers créés par les instances et exécute d'abord les esclaves, puis le maître.

 # ps -ef | grep tarantool taranto+ 21892 1 0 09:30 ? 00:00:00 tarantool slave4.lua <running> taranto+ 21907 1 0 09:30 ? 00:00:00 tarantool slave3.lua <running> taranto+ 21922 1 0 09:30 ? 00:00:00 tarantool slave2.lua <running> taranto+ 21931 1 0 09:30 ? 00:00:00 tarantool master.lua <running> 

Tout a commencé avec succès.

C'est ainsi que, par essais et erreurs, j'ai compris comment configurer et démarrer correctement la réplication.

En conséquence, la configuration suivante a été assemblée:

2 serveurs.
2 maître. Réserve chaude.
12 esclaves. Tous sont actifs.

Dans la logique de tarantool, http.server a été utilisé pour ne pas bloquer l' adaptateur supplémentaire (rappelez-vous le fournisseur, la plate-forme et le savon) ou attacher la bibliothèque à chaque processus métier.

Afin d'éviter une divergence entre les masters, sur l'équilibreur (NetScaler, HAProxy ou tout autre votre favori), nous fixons la règle de réserve, c'est-à-dire les opérations d'insertion, de mise à jour et de suppression ne vont qu'au premier maître actif.

À ce moment, le second réplique simplement les enregistrements du premier. Les esclaves eux-mêmes sont connectés au premier maître spécifié à partir de la configuration, ce dont nous avons besoin dans cette situation.

Sur lua, implémentation des opérations CRUD pour la valeur-clé. Pour le moment, cela suffit pour résoudre le problème.

Compte tenu des caractéristiques de l'utilisation de soap, un processus métier proxy a été mis en œuvre, dans lequel la logique de travailler avec une tarentule via http a été posée.

Si les données clés sont présentes, elles sont retournées immédiatement. Sinon, une demande est envoyée au système maître et stockée dans la base de données Tarantool.

En conséquence, un processus métier dans les tests traite jusqu'à 4 000 requêtes. Dans ce cas, le temps de réponse de la tarentule est d'environ 1 ms. Le temps de réponse moyen peut atteindre 3 ms.

Voici quelques informations issues des tests:



Il y avait 50 processus métier qui vont à 4 systèmes maîtres et mettent en cache les données dans leur mémoire. Duplication des informations en pleine croissance à chaque instance. Étant donné que java aime déjà la mémoire ... la perspective n'est pas la meilleure.

Maintenant


50 processus métier demandent des informations via le cache. Désormais, les informations de 4 instances de l'assistant sont stockées au même endroit et ne sont pas mises en cache dans chaque instance. Il a été possible de réduire considérablement la charge sur le système maître, il n'y a pas de doublons d'informations et la consommation de mémoire sur les instances avec logique métier a diminué.

Un exemple de la taille du stockage d'informations dans la mémoire de la tarentule:



À la fin de la journée, ces chiffres peuvent doubler, mais il n'y a pas de «rabattement» des performances.

Au combat, la version actuelle crée 2k - 2,5k requêtes par seconde de charge réelle. Le temps de réponse moyen est similaire aux tests jusqu'à 3 ms.

Si vous regardez htop sur l'un des serveurs avec tarantool, nous verrons qu'ils "refroidissent":



Résumé


Malgré toutes les subtilités et nuances de la base de données Tarantool, vous pouvez obtenir d'excellentes performances.

J'espère que ce projet se développera et que ces moments inconfortables seront résolus.

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


All Articles