Wir beschleunigen PHP-Connectoren fĂŒr Tarantool mit Async, Swoole und Parallel

Wir beschleunigen PHP-Connectoren fĂŒr Tarantool mit Async, Swoole und Parallel

In der PHP-Ökosystem gibt es derzeit zwei Connectoren fĂŒr die Arbeit mit dem Tarantool-Server – dies sind die offizielle PECL-Erweiterung tarantool/tarantool-php, geschrieben in C, und tarantool-php/client, geschrieben in PHP. Ich bin der Autor letzterer.

In diesem Artikel möchte ich die Testergebnisse von beiden Bibliotheken teilen und zeigen, wie man mit minimalen Änderungen im Code eine Leistungssteigerung von 3-5 % erreichen kann (bei synthetischen Tests!).

Was werden wir testen?

Wir werden die oben genannten synchronen Connectoren testen, die asynchron, parallel und asynchron-parallel ausgefĂŒhrt werden. 🙂 Außerdem möchten wir den Code der Connectoren selbst nicht berĂŒhren. Derzeit stehen mehrere Erweiterungen zur VerfĂŒgung, die das gewĂŒnschte Ziel erreichen:

  • Swoole – ein leistungsstarker asynchroner Framework fĂŒr PHP. Wird von Internet-Giganten wie Alibaba und Baidu verwendet. Seit Version 4.1.0 gibt es die magische Methode SwooleRuntime::enableCoroutine(), die es ermöglicht, "mit einer einzigen Codezeile synchronen Netzwerkbibliotheken in PHP asynchrone zu verwandeln".
  • Async – bis vor kurzem eine vielversprechende Erweiterung fĂŒr asynchrone Arbeiten in PHP. Warum bis vor kurzem? Leider hat der Autor aus mir unbekannten GrĂŒnden das Repository gelöscht und die weitere Zukunft des Projekts ist ungewiss. Wir mĂŒssen auf eine der Forks zurĂŒckgreifen. Wie Swoole ermöglicht diese Erweiterung mit Leichtigkeit, die AsynchronitĂ€t zu aktivieren, indem die Standardimplementierung der TCP- und TLS-Streams durch ihre asynchronen Versionen ersetzt wird. Dies erfolgt ĂŒber die Option "async.tcp = 1«.
  • Parallel – eine relativ neue Erweiterung vom nicht unbekannten Joe Watkins, dem Autor solcher Bibliotheken wie phpdbg, apcu, pthreads, pcov, uopz. Die Erweiterung bietet eine API fĂŒr die Multithread-Arbeit in PHP und positioniert sich als Ersatz fĂŒr pthreads. Eine wesentliche EinschrĂ€nkung der Bibliothek ist, dass sie nur mit der ZTS (Zend Thread Safe) Version von PHP funktioniert.

Wie werden wir testen?

Wir werden eine Tarantool-Instanz ohne Aktivierung des Write-Ahead-Logs starten (wal_mode = none) und mit einem erhöhten Netzwerkpuffer (readahead = 1 * 1024 * 1024). Die erste Option schließt die Arbeit mit der Festplatte aus, die zweite ermöglicht es, mehr Anfragen aus dem Betriebssystempuffer zu lesen und damit die Anzahl der Systemaufrufe zu minimieren.

FĂŒr Benchmarks, die mit Daten arbeiten (EinfĂŒgen, Löschen, Lesen usw.), wird vor Beginn des Benchmarks ein memtx-Space erstellt oder (wieder)hergestellt, in dem die Werte des PrimĂ€rindexes durch einen Generator fortlaufender Ganzzahlen (Sequenz) erzeugt werden.
Das DDL des Spaces sieht folgendermaßen aus:

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}})

Falls erforderlich, wird der Space vor dem Start des Benchmarks mit 10.000 Tupeln der Form

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

Der Zugriff auf die Tupel erfolgt ĂŒber einen zufĂ€lligen SchlĂŒsselwert.

Der Benchmark selbst ist eine einzelne Anfrage an den Server, die 10.000 Mal (Revolutionen) ausgefĂŒhrt wird, die wiederum in Iterationen ausgefĂŒhrt werden. Die Iterationen werden wiederholt, bis alle Abweichungen in der Zeit zwischen 5 Iterationen innerhalb einer zulĂ€ssigen Toleranz von 3 %* liegen. Danach wird ein Durchschnittswert genommen. Zwischen den Iterationen gibt es eine Pause von 1 Sekunde, um zu verhindern, dass der Prozessor ins Throttling ĂŒbergeht. Der Lua-Garbage-Collector wird vor jeder Iteration deaktiviert und nach deren Abschluss gezwungen gestartet. Der PHP-Prozess wird nur mit den fĂŒr den Benchmark erforderlichen Erweiterungen gestartet, die Ausgabe-Pufferung ist aktiviert und der Garbage-Collector ist deaktiviert.

* Die Anzahl der Revolutionen, Iterationen und die Toleranzgrenze können in den Einstellungen des Benchmarks geÀndert werden.

Testumgebung

Die unten veröffentlichten Ergebnisse wurden auf einem MacBook Pro (2015) erstellt, Betriebssystem — Fedora 30 (Kernelversion 5.3.8-200.fc30.x86_64). Tarantool wurde in Docker mit dem Parameter "--network host".

Paketversionen:

Tarantool: 2.3.0-115-g5ba5ed37e
Docker: 19.03.3, Build a872fc2f86
PHP: 7.3.11 (cli) (gebaut: 22. Okt 2019 08:11:04)
tarantool/client: 0.6.0
rybakit/msgpack: 0.6.1
ext-tarantool: 0.3.2 (+ Patch fĂŒr 7.3)*
ext-msgpack: 2.0.3
ext-async: 0.3.0-8c1da46
ext-swoole: 4.4.12
ext-parallel: 1.1.3

* Leider funktioniert der offizielle Connector nicht mit PHP-Versionen > 7.2. Um die Erweiterung fĂŒr PHP 7.3 zu kompilieren und auszufĂŒhren, musste ein Patch.

Ergebnisse

Synchroner Modus

Das Protokoll von Tarantool verwendet ein BinĂ€rformat MessagePack zur Serialisierung von Nachrichten. Im PECL-Connector ist die Serialisierung tief in den Untiefen der Bibliothek verborgen und es ist nicht möglich, den Kodierungsprozess aus dem Userland-Code zu beeinflussen.. Der Connector in reinem PHP bietet im Gegensatz dazu die Möglichkeit, den Kodierungsprozess durch die Erweiterung des Standardkodierers oder die Nutzung eigener Implementierungen anzupassen. Aus der Box sind zwei Kodierer verfĂŒgbar, einer basiert auf msgpack/msgpack-php (offizielle MessagePack PECL-Erweiterung), der andere - auf rybakit/msgpack (in reinem PHP).

Vor dem Vergleich der Connectoren messen wir die Leistung der MessagePack-Kodierer fĂŒr den PHP-Connector und verwenden in den weiteren Tests den, der das beste Ergebnis zeigt:

Wir beschleunigen PHP-Connectoren fĂŒr Tarantool mit Async, Swoole und Parallel
Obwohl die PHP-Version (Pure) in der Geschwindigkeit hinter der PECL-Erweiterung zurĂŒckbleibt, wĂŒrde ich in realen Projekten dennoch empfehlen, genau diese zu verwenden, rybakit/msgpack, da die offizielle MessagePack-Erweiterung die Spezifikation des Formats nur teilweise implementiert (zum Beispiel gibt es keine UnterstĂŒtzung fĂŒr benutzerdefinierte Datentypen, ohne die Sie Decimal - den neuen Datentyp, der in Tarantool 2.3 eingefĂŒhrt wurde, nicht verwenden können) und hat eine Reihe anderer der Probleme (einschließlich KompatibilitĂ€tsprobleme mit PHP 7.4). Insgesamt wirkt das Projekt jedoch vernachlĂ€ssigt.

Lassen Sie uns daher die Leistung der Connectoren im synchronen Modus messen:

Wir beschleunigen PHP-Connectoren fĂŒr Tarantool mit Async, Swoole und Parallel
Wie aus dem Diagramm zu sehen ist, zeigt der PECL-Connector (Tarantool) eine bessere Leistung im Vergleich zum PHP-Connector (Client). Aber das ist auch nicht ĂŒberraschend, da letzterer, abgesehen davon, dass er in einer langsameren Sprache implementiert ist, im Grunde genommen mehr Arbeit erledigt: Bei jedem Aufruf wird ein neues Objekt erstellt Request und Response (im Fall von Select - auch noch Criteria, und im Fall von Update/Upsert - Operations), separate EntitĂ€ten Verbindung, Packer und Sie fĂŒgen mit Hilfe der Handler erhöhen ebenfalls die Overhead-Kosten. Offensichtlich muss man fĂŒr FlexibilitĂ€t bezahlen. Insgesamt zeigt der PHP-Interpreter jedoch eine gute Leistung, auch wenn es Unterschiede gibt, sind diese gering und werden mit der Nutzung von Preloading in PHP 7.4 wahrscheinlich noch geringer sein, ganz zu schweigen vom JIT in PHP 8.

Lassen Sie uns weitermachen. In Tarantool 2.0 wurde SQL-UnterstĂŒtzung eingefĂŒhrt. Lassen Sie uns versuchen, die Operationen Select, Insert, Update und Delete unter Verwendung des SQL-Protokolls auszufĂŒhren und die Ergebnisse mit den noSQL (binĂ€ren) Äquivalenten zu vergleichen:

Wir beschleunigen PHP-Connectoren fĂŒr Tarantool mit Async, Swoole und Parallel
Die SQL-Ergebnisse sind nicht besonders beeindruckend (ich erinnere daran, dass wir immer noch den synchronen Modus testen). Ich wĂŒrde mich jedoch nicht zu frĂŒh darĂŒber aufregen, denn die SQL-UnterstĂŒtzung befindet sich noch in aktiver Entwicklung (relativ neu wurde beispielsweise die UnterstĂŒtzung fĂŒr prepared statements) hinzugefĂŒgt, und laut der Liste issues, stehen dem SQL-Engine in Zukunft eine Reihe von Optimierungen bevor.

Async

Nun, sehen wir uns an, wie das Async-Extension uns helfen kann, die obigen Ergebnisse zu verbessern. FĂŒr das Schreiben asynchroner Programme bietet das Extension eine API auf Basis von Koroutinen (coroutines), die wir nutzen werden. Durch Experimente stellen wir fest, dass die optimale Anzahl an Koroutinen fĂŒr unsere Umgebung 25 betrĂ€gt:

Wir beschleunigen PHP-Connectoren fĂŒr Tarantool mit Async, Swoole und Parallel
Wir "verteilen" 10.000 Operationen auf 25 Koroutinen und schauen, was dabei herauskommt:

Wir beschleunigen PHP-Connectoren fĂŒr Tarantool mit Async, Swoole und Parallel
Die Anzahl der Operationen pro Sekunde ist um mehr als das Dreifache gestiegen fĂŒr tarantool-php/client!

Leider konnte der PECL-Connector nicht mit ext-async gestartet werden.

Und was ist mit SQL?

Wir beschleunigen PHP-Connectoren fĂŒr Tarantool mit Async, Swoole und Parallel
Wie Sie sehen können, ist der Unterschied zwischen dem binÀren Protokoll und SQL im asynchronen Modus vernachlÀssigbar geworden.

Swoole

Erneut ermitteln wir die optimale Anzahl an Koroutinen, jetzt fĂŒr Swoole:
Wir beschleunigen PHP-Connectoren fĂŒr Tarantool mit Async, Swoole und Parallel
Wir bleiben bei 25. Wir wiederholen den gleichen Trick wie mit dem Async-Extension – verteilen 10.000 Operationen auf 25 Koroutinen. DarĂŒber hinaus fĂŒgen wir einen weiteren Test hinzu, bei dem wir die gesamte Arbeit auf 2 Prozesse aufteilen (das bedeutet, dass jeder Prozess 5.000 Operationen in 25 Koroutinen ausfĂŒhrt). Die Prozesse werden mittels SwooleProcess.

Ergebnisse:

Wir beschleunigen PHP-Connectoren fĂŒr Tarantool mit Async, Swoole und Parallel
Swole zeigt einen etwas niedrigeren Wert im Vergleich zu Async, wenn es in einem Prozess gestartet wird, aber mit 2 Prozessen Àndert sich das Bild grundlegend (die Zahl 2 wurde nicht zufÀllig gewÀhlt, auf meinem Rechner haben genau 2 Prozesse das beste Ergebnis gezeigt).

Übrigens gibt es im Async-Extension auch eine API fĂŒr die Arbeit mit Prozessen, jedoch habe ich dort keinen Unterschied bei der AusfĂŒhrung der Benchmarks in einem oder mehreren Prozessen bemerkt (es ist möglich, dass ich irgendwo einen Fehler gemacht habe).

SQL vs. binÀres Protokoll:

Wir beschleunigen PHP-Connectoren fĂŒr Tarantool mit Async, Swoole und Parallel
Wie auch bei Async wird der Unterschied zwischen binÀren und SQL-Operationen im asynchronen Modus nivelliert.

Parallel

Da das Parallel-Extension nicht um Koroutinen, sondern um Threads geht, messen wir die optimale Anzahl an parallelen Threads:

Wir beschleunigen PHP-Connectoren fĂŒr Tarantool mit Async, Swoole und Parallel
Sie betrĂ€gt 16 auf meinem Rechner. Lassen Sie uns die Benchmarks der Connectoren auf 16 parallelen Threads ausfĂŒhren:

Wir beschleunigen PHP-Connectoren fĂŒr Tarantool mit Async, Swoole und Parallel
Wie Sie sehen, ist das Ergebnis sogar besser als bei den asynchronen Erweiterungen (abgesehen von Swoole, das in 2 Prozessen gestartet wurde). Beachten Sie, dass fĂŒr den PECL-Connector an der Stelle von Update- und Upsert-Operationen nichts steht. Das liegt daran, dass diese Operationen fehlerhaft ausgefallen sind – ich weiß nicht, ob es an ext-parallel, ext-tarantool oder an beiden liegt.

Jetzt vergleichen wir die Leistung von SQL:

Wir beschleunigen PHP-Connectoren fĂŒr Tarantool mit Async, Swoole und Parallel
Haben Sie die Ähnlichkeit mit dem Diagramm fĂŒr die Connectoren bemerkt, die synchron ausgefĂŒhrt wurden?

Alles zusammen

Und schließlich fassen wir alle Ergebnisse in einem einzigen Diagramm zusammen, um das Gesamtbild der getesteten Erweiterungen zu sehen. Wir fĂŒgen dem Diagramm nur einen neuen Test hinzu, den wir noch nicht durchgefĂŒhrt haben – wir starten die Async-Koroutinen parallel mit Hilfe von Parallel*. Die Idee, die oben genannten Erweiterungen zu integrieren, wurde bereits diskutiert von den Autoren, jedoch wurde kein Konsens erreicht, das mĂŒssen wir selbst erledigen.

* Es gelang nicht, die Swoole-Koroutinen mit Parallel zu starten; anscheinend sind diese Erweiterungen nicht kompatibel.

Also, die finalen Ergebnisse:

Wir beschleunigen PHP-Connectoren fĂŒr Tarantool mit Async, Swoole und Parallel

Zum Abschluss

Meiner Meinung nach sind die Ergebnisse ziemlich ansprechend ausgefallen, und ich bin mir aus irgendeinem Grund sicher, dass dies noch nicht das Ende ist! Ob Sie das in Ihrem echten Projekt benötigen, liegt ganz bei Ihnen; ich sage nur, dass es fĂŒr mich ein interessantes Experiment war, das es ermöglichte zu bewerten, wie viel man aus einem synchronen TCP-Connector mit minimalem Aufwand „herausquetschen“ kann. Wenn Sie Ideen zur Verbesserung der Benchmarks haben, freue ich mich ĂŒber Ihren Pull-Request. Der gesamte Code mit Anweisungen zum Start und den Ergebnissen ist in einem separaten das Repository.

Quelle: habr.com

ZuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz kaufen, VPS VDS Server đŸ”„ ZuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz kaufen, VPS VDS Server - ProHoster