Accélérer les connecteurs PHP pour Tarantool avec Async, Swoole et Parallel

Accélérer les connecteurs PHP pour Tarantool avec Async, Swoole et Parallel

Dans l'Ă©cosystĂšme PHP, il existe actuellement deux connecteurs pour travailler avec le serveur Tarantool ― c'est l'extension officielle PECL tarantool/tarantool-php, Ă©crite en C, et tarantool-php/client, Ă©crite en PHP. Je suis l'auteur de ce dernier.

Dans cet article, je voudrais partager les résultats des tests de performance des deux bibliothÚques et montrer comment, avec des modifications minimes du code, on peut atteindre une augmentation de 3 à 5 % de performance (sur des tests synthétiques !).

Qu'allons-nous tester ?

Nous testerons les connecteurs mentionnĂ©s ci-dessus synchrones , lancĂ©s de maniĂšre asynchrone, parallĂšlement et de maniĂšre asynchrone-parallĂšle. 🙂 De plus, nous ne voulons pas toucher le code des connecteurs eux-mĂȘmes. Actuellement, plusieurs extensions sont disponibles pour atteindre l'objectif souhaitĂ© :

  • Swoole ― un framework asynchrone haute performance pour PHP. UtilisĂ© par des gĂ©ants d'internet comme Alibaba et Baidu. Depuis la version 4.1.0, la mĂ©thode magique SwooleRuntime::enableCoroutine(), permet « en une ligne de code de transformer les bibliothĂšques rĂ©seau synchrones PHP en asynchrones ».
  • Async ― jusqu'Ă  rĂ©cemment, une extension trĂšs prometteuse pour le travail asynchrone en PHP. Pourquoi jusqu'Ă  rĂ©cemment ? Malheureusement, pour une raison qui m'est inconnue, l'auteur a supprimĂ© le dĂ©pĂŽt et l'avenir du projet est incertain. Il nous faudra utiliser un des forks. Comme Swoole, cette extension permet en un geste de remplacer l'implĂ©mentation standard des flux TCP et TLS par leurs versions asynchrones. Cela se fait via l'option «async.tcp = 1«.
  • Parallel ― une extension assez rĂ©cente de Joe Watkins, l'auteur de bibliothĂšques comme phpdbg, apcu, pthreads, pcov, uopz. L'extension fournit une API pour le travail multithreadĂ© en PHP et se positionne comme un remplacement pour 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 ?

Nous allons lancer une instance de Tarantool sans journal d'Ă©criture anticipĂ©e (wal_mode = none) et avec un tampon rĂ©seau agrandi (readahead = 1 * 1024 * 1024). La premiĂšre option exclura les opĂ©rations d'Ă©criture sur disque, la seconde permettra de lire plus de requĂȘtes Ă  partir du tampon du systĂšme d'exploitation, minimisant ainsi le nombre d'appels systĂšme.

Pour les benchmarks qui fonctionnent avec des donnĂ©es (insertion, suppression, lecture, etc.), un espace memtx sera (re)créé avant le dĂ©but du benchmark, oĂč les valeurs de l'index primaire sont gĂ©nĂ©rĂ©es par un gĂ©nĂ©rateur de valeurs entiĂšres sĂ©quentielles.
La DDL de l'espace est la suivante :

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 de lancer le benchmark, l'espace est rempli avec 10 000 tuples de la forme

{id, "tuplД_"}

L'accÚs aux tuples se fait par une valeur de clé aléatoire.

Le benchmark lui-mĂȘme est une seule requĂȘte au serveur qui est exĂ©cutĂ©e 10 000 fois (rĂ©volutions), qui, Ă  leur tour, sont effectuĂ©es en itĂ©rations. Les itĂ©rations se rĂ©pĂštent tant que toutes les dĂ©viations de temps entre 5 itĂ©rations ne se situent pas dans une marge d'erreur acceptable de 3 %*. AprĂšs cela, le rĂ©sultat moyen est pris. Entre les itĂ©rations, il y a une pause d'1 seconde, afin de ne pas permettre au processeur de passer en throttling. Le collecteur de dĂ©chets Lua est dĂ©sactivĂ© avant chaque itĂ©ration et est forcĂ© de s'exĂ©cuter aprĂšs sa terminaison. Le processus PHP est lancĂ© uniquement avec les extensions nĂ©cessaires pour le benchmark, avec la mise en tampon de sortie activĂ©e et le collecteur de dĂ©chets dĂ©sactivĂ©.

* Le nombre de rĂ©volutions, d'itĂ©rations et le seuil d'erreur peuvent ĂȘtre modifiĂ©s dans les paramĂštres du benchmark.

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Ă© exĂ©cutĂ© dans Docker avec le paramĂštre--network host".

Versions des paquets :

Tarantool : 2.3.0-115-g5ba5ed37e
Docker : 19.03.3, build a872fc2f86
PHP : 7.3.11 (cli) (construit : 22 oct. 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-parallel : 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, il a fallu utiliser patch.

Résultats

Mode synchrone

Le protocole de Tarantool utilise un format binaire MessagePack pour la sérialisation des messages. Dans le connecteur PECL, la sérialisation est profondément cachée au sein de la bibliothÚque et il n'est pas possible d'influencer le processus d'encodage depuis le code userland .. Le connecteur en PHP pur, quant à lui, offre la possibilité de personnaliser le processus de codage en étendant le codeur standard ou en utilisant sa propre implémentation. Deux codeurs sont disponibles par défaut, l'un basé sur msgpack/msgpack-php (l'extension officielle MessagePack PECL), l'autre étant basé sur rybakit/msgpack (en PHP pur).

Avant de comparer les connecteurs, mesurons les performances des codeurs MessagePack pour le connecteur PHP, et lors des tests suivants, nous utiliserons celui qui montrera le meilleur résultat :

Accélérer les connecteurs PHP pour Tarantool avec Async, Swoole et Parallel
Bien que la version PHP (Pure) soit moins rapide que l'extension PECL, dans des projets rĂ©els, je recommanderais tout de mĂȘme d'utiliser rybakit/msgpack, car dans l'extension officielle MessagePack, la spĂ©cification du format n'est mise en Ɠuvre que partiellement (par exemple, il n'y a pas de support pour les 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 prĂ©sente plusieurs autres des problĂšmes (y compris des problĂšmes de compatibilitĂ© avec PHP 7.4). Dans l'ensemble, le projet semble abandonnĂ©.

Mesurons donc les performances des connecteurs en mode synchrone :

Accélérer les connecteurs PHP pour Tarantool avec Async, Swoole et Parallel
Comme le montre le graphique, le connecteur PECL (Tarantool) affiche de meilleures performances par rapport au connecteur en PHP (Client). Ce n'est pas surprenant, compte tenu du fait que ce dernier, en plus d'ĂȘtre implĂ©mentĂ© dans un langage plus lent, effectue en rĂ©alitĂ© plus de travail : Ă  chaque appel, un nouvel objet est créé Request et Response (dans le cas de Select — aussi Criteria, et dans le cas de Update/Upsert — Operations), des entitĂ©s distinctes Connexion, Packer et Handler ajoutent Ă©galement un surcoĂ»t. Il est Ă©vident que la flexibilitĂ© a un prix. Cependant, dans l'ensemble, l'interprĂ©teur PHP montre de bonnes performances, mĂȘme si la diffĂ©rence existe, elle est minime et sera probablement encore plus faible avec l'utilisation de preloading dans PHP 7.4, sans parler de JIT dans PHP 8.

Continuons. Dans Tarantool 2.0, le support de SQL a été ajouté. Essayons d'effectuer des opérations Select, Insert, Update et Delete en utilisant le protocole SQL et comparons les résultats avec leurs équivalents noSQL (binaires) :

Accélérer les connecteurs PHP pour Tarantool avec Async, Swoole et Parallel
Les résultats SQL ne sont pas trÚs impressionnants (je rappelle que nous testons toujours le mode synchrone). Cependant, je ne voudrais pas me décourager à ce sujet trop tÎt, car le support de SQL est encore en développement actif (récemment, par exemple, le support de prepared statements) a été ajouté, et d'aprÚs la liste issues, le moteur SQL attendra d'autres optimisations.

Async

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 allons utiliser. Par expérimentation, nous découvrons que le nombre optimal de coroutines pour notre environnement est de 25 :

Accélérer les connecteurs PHP pour Tarantool avec Async, Swoole et Parallel
Nous 'étalons' 10 000 opérations sur 25 coroutines et voyons ce que cela donne :

Accélérer les connecteurs PHP pour Tarantool avec Async, Swoole et Parallel
Le nombre d'opérations par seconde a plus que triplé pour tarantool-php/client!

Malheureusement, le connecteur PECL ne s'est pas lancé avec ext-async.

Qu'en est-il de SQL ?

Accélérer les connecteurs PHP pour Tarantool avec Async, Swoole et Parallel
Comme vous le voyez, en mode asynchrone, la différence entre le protocole binaire et SQL est dans les limites de l'erreur.

Swoole

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

Résultats :

Accélérer les connecteurs PHP pour Tarantool avec Async, Swoole et Parallel
Swoole montre légÚrement de moins bons résultats par rapport à Async lors de l'exécution dans un seul processus, mais avec 2 processus, la situation change radicalement (le nombre 2 n'est pas choisi au hasard, sur ma machine, 2 processus ont montré les meilleurs résultats).

D'ailleurs, l'extension Async a aussi une API pour travailler avec des processus, mais je n'ai pas remarqué de différences significatives lors de l'exécution des benchmarks dans un ou plusieurs processus (il est possible que j'aie fait une erreur quelque part).

SQL vs protocole binaire :

Accélérer les connecteurs PHP pour Tarantool avec Async, Swoole et Parallel
Tout comme avec Async, la différence entre les opérations binaires et SQL est atténuée en mode asynchrone.

Parallel

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

Accélérer les connecteurs PHP pour Tarantool avec Async, Swoole et Parallel
Il est de 16 sur ma machine. Lançons des benchmarks de connecteurs sur 16 threads parallÚles :

Accélérer les connecteurs PHP pour Tarantool avec Async, Swoole et Parallel
Comme vous le voyez, le rĂ©sultat est mĂȘme meilleur qu'avec les extensions asynchrones (Ă  l'exception de Swoole exĂ©cutĂ© sur 2 processus). Notez que pour le connecteur PECL, il n'y a rien sur les opĂ©rations Update et Upsert. Cela est dĂ» au fait que ces opĂ©rations ont Ă©chouĂ© avec une erreur - je ne sais pas si c'est Ă  cause de ext-parallel, ext-tarantool ou des deux.

Comparons maintenant les performances de SQL :

Accélérer les connecteurs PHP pour Tarantool avec Async, Swoole et Parallel
Avez-vous remarqué la similitude avec le graphique des connecteurs exécutés de maniÚre synchrone ?

Tout ensemble

Enfin, rassemblons tous les rĂ©sultats dans un seul graphique pour voir la vue d'ensemble des extensions testĂ©es. Nous allons ajouter un nouveau test que nous n'avons pas encore effectuĂ© : exĂ©cuter des coroutines Async en parallĂšle avec Parallel*. L'idĂ©e d'intĂ©grer les extensions mentionnĂ©es ci-dessus a dĂ©jĂ  Ă©tĂ© discutĂ©e par les auteurs, mais aucun consensus n'a Ă©tĂ© atteint, il va donc falloir le faire soi-mĂȘme.

* Lancer des coroutines Swoole avec Parallel n'a pas fonctionné, il semble que ces extensions soient incompatibles.

Voici donc les résultats finaux :

Accélérer les connecteurs PHP pour Tarantool avec Async, Swoole et Parallel

En conclusion

À mon avis, les rĂ©sultats sont assez remarquables, et j'ai l'impression que ce n'est pas encore la limite ! Il vous revient de dĂ©cider si cela vous est nĂ©cessaire dans un projet rĂ©el, je dirai seulement que pour moi, cela a Ă©tĂ© une expĂ©rience intĂ©ressante, permettant d'Ă©valuer combien on peut « tirer » d'un connecteur TCP synchronisĂ© avec un minimum d'efforts. Si vous avez des idĂ©es pour amĂ©liorer les benchmarks, je considĂ©rerai avec plaisir votre pull request. L'ensemble du code avec les instructions de lancement et les rĂ©sultats a Ă©tĂ© publiĂ© dans un dĂ©pĂŽts.

Source : habr.com

Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS đŸ”„ Acheter un hĂ©bergement fiable pour les sites avec protection DDoS, serveurs VPS VDS | ProHoster