Accélération des connecteurs PHP pour Tarantool en utilisant Async, Swoole et Parallel

Accélération des connecteurs PHP pour Tarantool en utilisant Async, Swoole et Parallel

Dans l'écosystème PHP, il existe actuellement deux connecteurs pour travailler avec le serveur Tarantool - il s'agit de l'extension officielle PECL tarantool/tarantool-php, écrit en C, et tarantool-php/client, écrit en PHP. Je suis l'auteur de ce dernier.

Dans cet article, je voudrais partager les résultats des tests de performances des deux bibliothèques et montrer comment, avec des modifications minimes du code, vous pouvez obtenir une augmentation des performances de 3 à 5 (sur des tests synthétiques!).

Que va-t-on tester ?

Nous allons tester ceux mentionnés ci-dessus synchrone connecteurs fonctionnant de manière asynchrone, en parallèle et de manière asynchrone-parallèle. 🙂 Nous ne voulons pas non plus toucher au code des connecteurs eux-mêmes. Il existe actuellement plusieurs extensions disponibles pour réaliser ce que vous souhaitez :

  • Swoole ― un framework asynchrone hautes performances pour PHP. Utilisé par des géants de l'Internet comme Alibaba et Baidu. Depuis la version 4.1.0 une méthode magique est apparue SwooleRuntime ::enableCoroutine(), qui vous permet de « convertir des bibliothèques réseau PHP synchrones en bibliothèques asynchrones avec une seule ligne de code ».
  • Async était jusqu'à récemment une extension très prometteuse pour le travail asynchrone en PHP. Pourquoi jusqu'à récemment ? Malheureusement, pour une raison que je ne connais pas, l'auteur a supprimé le référentiel et le sort futur du projet n'est pas clair. je vais devoir l'utiliser un des fourchettes. Comme Swoole, cette extension vous permet d'allumer facilement votre pantalon d'un simple mouvement du poignet pour activer l'asynchrone en remplaçant l'implémentation standard des flux TCP et TLS par leurs versions asynchrones. Cela se fait via l'option "async.tcp = 1«.
  • Parallèle - une extension relativement nouvelle du célèbre Joe Watkins, auteur de bibliothèques telles que phpdbg, apcu, pthreads, pcov, uopz. L'extension fournit une API pour le multithreading en PHP et se positionne en remplacement des pthreads. Une limitation importante de la bibliothèque est qu'elle ne fonctionne qu'avec la version ZTS (Zend Thread Safe) de PHP.

Comment allons-nous tester ?

Lançons une instance Tarantool avec la journalisation en écriture anticipée désactivée (wal_mode = aucun) et une mémoire tampon réseau accrue (lecture anticipée = 1 * 1024 * 1024). La première option éliminera le travail avec le disque, la seconde permettra de lire plus de requêtes depuis le tampon du système d'exploitation et ainsi de minimiser le nombre d'appels système.

Pour les benchmarks qui fonctionnent avec des données (insertion, suppression, lecture, etc.), avant de démarrer le benchmark, un espace memtx sera (re)créé, dans lequel les valeurs d'index primaires sont créées par un générateur de valeurs entières ordonnées ​(séquence).
Le DDL spatial ressemble à ceci :

space = box.schema.space.create(config.space_name, {id = config.space_id, temporary = true})
space:create_index('primary', {type = 'tree', parts = {1, 'unsigned'}, sequence = true})
space:format({{name = 'id', type = 'unsigned'}, {name = 'name', type = 'string', is_nullable = false}})

Si nécessaire, avant d'exécuter le benchmark, l'espace est rempli de 10,000 XNUMX tuples du formulaire

{id, "tuplе_<id>"}

Les tuples sont accessibles à l'aide d'une valeur de clé aléatoire.

Le benchmark lui-même est une requête unique adressée au serveur, qui est exécutée 10,000 5 fois (tours), qui, à leur tour, sont exécutées par itérations. Les itérations sont répétées jusqu'à ce que tous les écarts de temps entre 3 itérations se situent dans une erreur acceptable de 1 %*. Après cela, le résultat moyen est pris. Il y a une pause d'une seconde entre les itérations pour empêcher le processeur de ralentir. Le garbage collector de Lua est désactivé avant chaque itération et est forcé de démarrer une fois celle-ci terminée. Le processus PHP est lancé uniquement avec les extensions nécessaires au benchmark, avec le buffering de sortie activé et le garbage collector désactivé.

* Le nombre de tours, d'itérations et le seuil d'erreur peuvent être modifiés dans les paramètres de référence.

Environnement de test

Les résultats publiés ci-dessous ont été réalisés sur un MacBookPro (2015), système d'exploitation - Fedora 30 (version du noyau 5.3.8-200.fc30.x86_64). Tarantool a été lancé dans docker avec le paramètre "--network host".

Versions du package :

Tarantool: 2.3.0-115-g5ba5ed37e
Docker : 19.03.3, version a872fc2f86
PHP : 7.3.11 (cli) (construit : 22 octobre 2019 08:11:04)
tarantool/client : 0.6.0
rybakit/msgpack : 0.6.1
ext-tarantool : 0.3.2 (+ patch pour 7.3)*
ext-msgpack : 2.0.3
ext-async : 0.3.0-8c1da46
ext-swoole : 4.4.12
ext-parallèle : 1.1.3

* Malheureusement, le connecteur officiel ne fonctionne pas avec la version PHP > 7.2. Pour compiler et exécuter l'extension sur PHP 7.3, j'ai dû utiliser correctif.

résultats

Mode synchrone

Le protocole Tarantool utilise un format binaire Pack de messages pour sérialiser les messages. Dans le connecteur PECL, la sérialisation est cachée au plus profond de la bibliothèque et affecte le processus d'encodage à partir du code de l'espace utilisateur. pas possible. Un connecteur PHP pur, au contraire, offre la possibilité de personnaliser le processus d'encodage en étendant l'encodeur standard ou en utilisant votre propre implémentation. Deux encodeurs sont disponibles immédiatement, l'un est basé sur msgpack/msgpack-php (extension officielle MessagePack PECL), l'autre est activé rybakit/msgpack (en PHP pur).

Avant de comparer les connecteurs, nous mesurerons les performances des encodeurs MessagePack pour le connecteur PHP et dans d'autres tests, nous utiliserons celui qui montre le meilleur résultat :

Accélération des connecteurs PHP pour Tarantool en utilisant Async, Swoole et Parallel
Bien que la version PHP (Pure) soit inférieure à l'extension PECL en termes de vitesse, dans des projets réels, je recommanderais quand même de l'utiliser rybakit/msgpack, car dans l'extension officielle MessagePack, la spécification de format n'est que partiellement implémentée (par exemple, il n'y a pas de prise en charge des types de données personnalisés, sans lesquels vous ne pourrez pas utiliser Decimal - un nouveau type de données introduit dans Tarantool 2.3) et a un nombre d'autres проблем (y compris des problèmes de compatibilité avec PHP 7.4). Eh bien, en général, le projet semble abandonné.

Mesurons donc les performances des connecteurs en mode synchrone :

Accélération des connecteurs PHP pour Tarantool en utilisant Async, Swoole et Parallel
Comme le montre le graphique, le connecteur PECL (Tarantool) affiche de meilleures performances par rapport au connecteur PHP (Client). Mais ce n'est pas surprenant, étant donné que ce dernier, en plus d'être implémenté dans un langage plus lent, fait en réalité plus de travail : un nouvel objet est créé à chaque appel. Demande и Réponse (dans le cas de Select - également Critères, et dans le cas de Update/Upsert ― Opérations), entités distinctes La connexion, Emballeur и Maître ils ajoutent également des frais généraux. Évidemment, la flexibilité a un prix. Cependant, en général, l'interpréteur PHP affiche de bonnes performances, bien qu'il y ait une différence, elle est insignifiante et, peut-être, le sera encore moins lors de l'utilisation du préchargement en PHP 7.4, sans parler du JIT en PHP 8.

Allons-nous en. Tarantool 2.0 a ajouté la prise en charge de SQL. Essayons d'effectuer les opérations de sélection, d'insertion, de mise à jour et de suppression à l'aide du protocole SQL et comparons les résultats avec les équivalents noSQL (binaires) :

Accélération des connecteurs PHP pour Tarantool en utilisant Async, Swoole et Parallel
Les résultats SQL ne sont pas très impressionnants (je vous rappelle que nous testons encore le mode synchrone). Cependant, je ne m'en soucierais pas à l'avance ; le support SQL est toujours en cours de développement actif (relativement récemment, par exemple, le support a été ajouté déclarations préparées) et, à en juger par la liste vous aider à faire face aux problèmes qui vous perturbent, le moteur SQL fera l'objet de nombreuses optimisations à l'avenir.

Async

Eh bien, voyons maintenant comment l'extension Async peut nous aider à améliorer les résultats ci-dessus. Pour écrire des programmes asynchrones, l'extension fournit une API basée sur des coroutines, que nous utiliserons. Nous découvrons empiriquement que le nombre optimal de coroutines pour notre environnement est de 25 :

Accélération des connecteurs PHP pour Tarantool en utilisant Async, Swoole et Parallel
« Répartissez » 10,000 25 opérations sur XNUMX coroutines et voyez ce qui se passe :

Accélération des connecteurs PHP pour Tarantool en utilisant Async, Swoole et Parallel
Le nombre d'opérations par seconde a augmenté de plus de 3 fois pour tarantool-php/client!

Malheureusement, le connecteur PECL n'a pas démarré avec ext-async.

Et SQL ?

Accélération des connecteurs PHP pour Tarantool en utilisant Async, Swoole et Parallel
Comme vous pouvez le constater, en mode asynchrone, la différence entre le protocole binaire et SQL se situe dans la marge d'erreur.

Swoole

Nous découvrons à nouveau le nombre optimal de coroutines, cette fois pour Swoole :
Accélération des connecteurs PHP pour Tarantool en utilisant Async, Swoole et Parallel
Arrêtons-nous à 25. Répétons la même astuce qu'avec l'extension Async : répartissez 10,000 25 opérations entre 2 coroutines. De plus, nous ajouterons un autre test dans lequel nous diviserons tout le travail en 5,000 deux processus (c'est-à-dire que chaque processus effectuera 25 XNUMX opérations dans XNUMX coroutines). Les processus seront créés à l'aide Processus Swoole.

Résultats:

Accélération des connecteurs PHP pour Tarantool en utilisant Async, Swoole et Parallel
Swole affiche un résultat légèrement inférieur à celui d'Async lorsqu'il est exécuté dans un seul processus, mais avec 2 processus, l'image change radicalement (le numéro 2 n'a pas été choisi par hasard ; sur ma machine, ce sont 2 processus qui ont montré le meilleur résultat).

À propos, l'extension Async dispose également d'une API pour travailler avec des processus, mais là, je n'ai remarqué aucune différence par rapport à l'exécution de benchmarks dans un ou plusieurs processus (il est possible que j'aie fait une erreur quelque part).

Protocole SQL vs binaire :

Accélération des connecteurs PHP pour Tarantool en utilisant Async, Swoole et Parallel
Comme avec Async, la différence entre les opérations binaires et SQL est éliminée en mode asynchrone.

Parallèle

Puisque l'extension Parallel ne concerne pas les coroutines, mais les threads, mesurons le nombre optimal de threads parallèles :

Accélération des connecteurs PHP pour Tarantool en utilisant Async, Swoole et Parallel
Il est 16 sur ma machine. Exécutons des tests de connecteurs sur 16 threads parallèles :

Accélération des connecteurs PHP pour Tarantool en utilisant Async, Swoole et Parallel
Comme vous pouvez le constater, le résultat est encore meilleur qu'avec des extensions asynchrones (sans compter Swoole fonctionnant sur 2 processus). Notez que pour le connecteur PECL, les opérations Update et Upsert sont vides. Cela est dû au fait que ces opérations ont échoué avec une erreur - je ne sais pas si c'était la faute d'ext-parallel, d'ext-tarantool ou des deux.

Comparons maintenant les performances SQL :

Accélération des connecteurs PHP pour Tarantool en utilisant Async, Swoole et Parallel
Remarquez-vous la similitude avec le graphique des connecteurs fonctionnant de manière synchrone ?

Ensemble

Et enfin, résumons tous les résultats dans un seul graphique pour avoir une vue d’ensemble des extensions testées. Ajoutons juste un nouveau test au graphique, ce que nous n'avons pas encore fait : exécutons les coroutines Async en parallèle en utilisant Parallel*. L'idée d'intégrer les extensions ci-dessus est déjà discuté auteurs, mais aucun consensus n’a été atteint, vous devrez le faire vous-même.

* Il n'a pas été possible de lancer les coroutines Swoole avec Parallel ; il semble que ces extensions soient incompatibles.

Alors, les résultats finaux :

Accélération des connecteurs PHP pour Tarantool en utilisant Async, Swoole et Parallel

Au lieu d'une conclusion

À mon avis, les résultats se sont avérés tout à fait dignes, et pour une raison quelconque, je suis sûr que ce n'est pas la limite ! Que vous deviez décider de cela dans un projet réel uniquement pour vous-même, je dirai seulement que pour moi, c'était une expérience intéressante qui vous permet d'évaluer combien vous pouvez « extraire » d'un connecteur TCP synchrone avec un minimum d'effort. Si vous avez des idées pour améliorer les benchmarks, je serai heureux de considérer votre pull request. Tout le code avec les instructions de lancement et les résultats est publié dans un document séparé référentiels.

Source: habr.com

Ajouter un commentaire