Übertakten der Magento Rest API mit RoadRunner

Beschleunigen Sie Magento mit RoadRunner
PHP erstellt, um zu sterben. Und alles wäre in Ordnung, aber er hat in letzter Zeit keine Chance dazu bekommen. Vor einem Jahr fand auf dem Hub die Ankündigung des RoadRunner-Tools statt , die den PHP-Prozess dazu zwang, den endlosen Kreis von Tod und Auferstehung zu verlassen.


Das Prinzip der Arbeit von RoadRunner besteht darin, den laufenden Prozess beizubehalten und eingehende Anforderungen darin zu werfen, was es den Entwicklern zufolge ermöglicht, die Anwendungsleistung zu steigern (manchmal sogar 40-mal).


Da ich schon lange mit Magento zusammenarbeite, schien es mir eine gute Idee zu sein, das Tool nicht in einem mythischen Framework, sondern in einer realen Anwendung zu testen, für die Magento Open Source hervorragend funktioniert.


Initialisierungskosten der Magento-Anwendung


Um die RoadRunner-Anwendung zu beschleunigen, müssen Sie die Reaktionszeit (nach einem Aufwärmstart) verkürzen, indem Sie den Aufwand für die Initialisierung der Anwendung verringern.


Screenshot aus Anton Tsitous Präsentation "Entwerfen hybrider Go / PHP-Anwendungen mit RoadRunner"
Screenshot aus Anton Tsitous Präsentation "Entwerfen hybrider Go / PHP-Anwendungen mit RoadRunner"


Im Fall von Magento fällt die Hauptzeit für den Start auf:


  • Autoloading des Komponisten
  • Bootstrapping

Das automatische Laden von Composer fällt nicht auf, da es für eine PHP-Anwendung Standard ist.


Profilerstellung für Composer.
Profilerstellung für Composer.


Das Bootstraping von Magento-Anwendungen umfasst das Initialisieren eines Fehlerbehandlers, das Überprüfen des Anwendungsstatus usw.


Der schwierigste Teil ist die Initialisierung des IoC-Containers („ObjectManager“ in Bezug auf Magento) und die rekursive Erstellung von Abhängigkeitsinstanzen durch ihn, um das Anwendungsobjekt zu erhalten.


Profilerstellungsergebnisse im Zusammenhang mit Bootstraping.
Profilerstellungsergebnisse im Zusammenhang mit Bootstraping.


RoadRunner-Implementierung


Um RoadRunner zu starten, müssen Sie einen Worker erstellen, der einen Zyklus zum Akzeptieren eingehender Anforderungen und zum Senden von Antworten enthält. Darüber hinaus arbeitet das Tool mit Anfragen und Antworten, die PSR-7 implementieren. Aus der offiziellen Dokumentation geht es ungefähr so:


while ($req = $psr7->acceptRequest()) { $resp = new \Zend\Diactoros\Response(); $resp->getBody()->write("hello world"); $psr7->respond($resp); } 

Magento und PSR-7


Magento hat das PSR-7 noch nicht implementiert und verwendet sofort seine Anforderungs- und Antwortimplementierungen, die Ansätze, bei denen sie hauptsächlich aus der vorherigen Version stammen.


Um RoadRunner zu implementieren, müssen Sie einen Einstiegspunkt finden, der die Anforderung in irgendeiner Form akzeptiert und eine Antwort zurückgibt ( Symfony-Beispiel ).


Es gibt einen solchen Punkt in Magento , \ Magento \ Framework \ AppInterface . Es gibt nur ein Problem. Diese Schnittstelle ist nicht dafür ausgelegt, die Anforderung anzunehmen. Aber warte, woher kommt es in die Anwendung? Es lohnt sich, zum Anfang zurückzukehren und das Mantra - PHP ist geboren, um zu sterben . Dementsprechend geht die überwiegende Mehrheit der Bibliotheken, Pakete und Frameworks beim Entwerfen und Teilen in Ebenen einfach nicht davon aus, dass die Anforderung mehr als eine globale Anforderung darstellt.


Die Magento-Transportschicht basiert auf dem gleichen Prinzip. Obwohl in der Dokumentation die Unterschiede zwischen injizierbaren / newable-Objekten beschrieben werden , wird die Anforderung tatsächlich als globaler Statefull-Service verwendet, der sich aus globalen Variablen ($ _GET, $ _POST) initialisiert. Darüber hinaus kann die Einspeisung dieses Dienstes auf allen Ebenen der Anwendung im Kernel selbst gesehen werden, geschweige denn in der Qualität von Modulen von Drittanbietern.


Auf der Grundlage des Vorstehenden wurde die Hoffnung geweckt, RoadRunner nur durch die Konvertierung von Anforderungen von PSR-7-Stil in Magento-Stil zu implementieren.


Implementieren Sie den PSR-7-Adapter


Wir formulieren das Problem unter Berücksichtigung der erhaltenen Informationen.
Ich hätte gerne eine bestimmte Anwendungsschnittstelle, die eine PSR-7-Anfrage akzeptiert und eine PSR-7-Antwort zurückgibt. Es ist auch erforderlich, eine Implementierung der erstellten Schnittstelle zu erstellen, die dieses Interaktionsformat an die Magento-Anwendung anpasst.


PSR-7 Adapter
PSR-7 Adapter


Wie oben erwähnt, gibt die Magento-Anwendung bereits eine Antwort zurück, sodass wir sie nur in das PSR-7-Format konvertieren müssen.


Für die Anfrage benötigen Sie eine Klasse, die alle Aufrufe an das aktuelle Anfrageobjekt weiterleitet, die wir in ein spezielles Register eintragen (ja, die Götter der Architektur werden diese Perversion vergeben). Darüber hinaus wurde festgestellt, dass für die Anforderungsklasse nicht eine, sondern 3 verwendet wird. Daher müssen sie über die IoC-Konfiguration des Containers neu registriert werden.


Die Klassen, die zum Arbeiten mit Abfragen in Magento verwendet wurden
Die Klassen, die zum Arbeiten mit Abfragen in Magento verwendet wurden


Probleme einer unsterblichen PHP-Anwendung


Eine über RoadRunner gestartete Anwendung hat die gleichen Probleme wie jeder langlebige PHP-Prozess. Sie werden in der Dokumentation beschrieben ( https://roadrunner.dev/docs/usage-production ).


Die Hauptprobleme der Anwendungsebene, die der Entwickler überwachen sollte, sind:



Besondere Aufmerksamkeit sollte im Zusammenhang mit Magento der Statusverwaltung gewidmet werden, da sowohl im Kernel als auch in Modulen von Drittanbietern das Zwischenspeichern des aktuellen Benutzers / Produkts / der aktuellen Kategorie innerhalb des Dienstes ein sehr verbreiteter Ansatz ist.


  protected function getCustomer(): ?CustomerInterface { if (!$this->customer) { if ($this->customerSession->isLoggedIn()) { $this->customer = $this->customerRepository->getById($this->customerSession->getCustomerId()); } else { return null; } } return $this->customer; } 

Ein Beispiel für eine Methode aus dem Kernel, die den Status eines Objekts verwendet.


Ausführen von Magento Rest API Server über RoadRunner


Angesichts der potenziellen Probleme mit dem globalen Staat, basierend auf den Erfahrungen bei der Entwicklung des Front-End-Teils von Magento, wurde der am besten geeignete und schmerzloseste WebApi-Teil für den Start ausgewählt.


Das erste, was Sie tun müssen, ist, unseren Mitarbeiter zu erstellen, der RoadRunner durchläuft und endlos (fast) lebt. Nehmen Sie dazu einen Code aus den RoadRunner-Handbüchern und fügen Sie dort unsere Anwendung hinzu, die in einen PSR-7-Adapter eingewickelt ist.


 $relay = new StreamRelay(STDIN, STDOUT); $psr7 = new PSR7Client(new Worker($relay)); $bootstrap = \Magento\Framework\App\Bootstrap::create(BP, []); /** @var \Magento\Framework\App\Http $app */ $app = $bootstrap->createApplication(\Magento\Framework\App\Http::class); /** @var ApplicationInterface $psr7Application */ $psr7Application = $bootstrap->getObjectManager()->create( \Isxam\M2RoadRunner\Application\MagentoAppWrapper::class, [ 'magentoApp' => $app ] ); while ($request = $psr7->acceptRequest()) { try { $response = $psr7Application->handle($request); $psr7->respond($response); } catch (\Throwable $e) { $psr7->getWorker()->error((string)$e); } } 

Der Code vor der while-Schleife wird zu Beginn des Workers ausgeführt, alles, was sich in der Schleife befindet - bei jeder neuen Anforderung.


Wenn unser Mitarbeiter bereit ist, konfigurieren wir den in Go geschriebenen RoadRunner-Server. Hier ist alles schön und schnell, nur das Composer-Paket, das die ausführbare Datei herunterlädt, muss nicht installiert werden, was nicht angenehm sein kann. Wir erstellen die Konfiguration unseres Servers - der einfachste sieht ungefähr so ​​aus.


 http: address: 0.0.0.0:8086 workers: command: "php worker.php" pool: numWorkers: 1 

RoadRunner-Konfiguration.


Die Dokumentation enthält eine Vielzahl von Einstellungen, mit denen Sie den Server flexibel konfigurieren können, sodass der Wunsch, Ihre Binärdatei zu kompilieren, nicht genau entsteht.


 ./rr serve -v -d 

Serverstart


Lösungstest


Die Werkzeuge


Zum bequemen Testen nehmen wir etwas Einfaches, zum Beispiel artillery.io.


Wir werden die Leistung mit Hilfe eines Benutzers testen, der Abfragen nacheinander ausführt (RoadRunner unterstützt auch die Ausführung von Abfragen in mehreren Threads, wir werden diese Frage anderen Forschern überlassen).


Am Eingang haben wir die Artillerie-Konfigurationsdatei mit zwei Umgebungen - Apache und RoadRunner. Beide arbeiten mit derselben Magento-Instanz, daher sind sie hier gleichberechtigt.


Testszenarien


Die folgenden Szenarien wurden verwendet, um die Leistung der beiden Lösungen zu messen.


Szenario 1. Erstellen einer Kategorie
  - name: "S1. Create category" flow: - loop: - post: url: "/rest/V1/categories" json: category: name: "name-{{prefix}}-{{ $loopCount }}" parent_id: 2 is_active: true count: 100 

Szenario 2. Eine Liste der Länder abrufen
  - name: "S2. Countries list" flow: - loop: - get: url: "/rest/V1/directory/countries" count: 100 

Szenario 3: Auflisten der Produkttypen
  - name: "S3. Product types list" flow: - loop: - get: url: "/rest/V1/products/types" count: 100 

Szenario 4. Eine Liste der Attributgruppen abrufen
  - name: "S4. Product attribute sets list" flow: - loop: - get: url: "/rest/V1/products/attribute-sets/sets/list?searchCriteria" count: 100 

Szenario 5. Eine Kategorie abrufen
  - name: "S5. Category get" flow: - loop: - get: url: "/rest/V1/categories/2" count: 100 

Szenario 6. Produkterstellung
  - name: "S6. Create product" flow: - loop: - post: url: '/rest/V1/products' json: product: sku: "sku-{{prefix}}-{{ $loopCount }}" name: "name-{{prefix}}-{{ $loopCount }}" attribute_set_id: 4 price: 100 type_id: "simple" count: 100 

Szenario 7. Abrufen einer Produktliste
  - name: "S7. Get product list" flow: - loop: - get: url: "/rest/V1/products?searchCriteria[pageSize]=20" count: 100 

Ergebnis


Nachdem alle Skripte abwechselnd über RoadRunner und Apache ausgeführt wurden, wurden Mediane für die Dauer der Abfrage ermittelt. Laut Median unterscheidet sich die Geschwindigkeit aller Szenarien um ungefähr den gleichen Wert von ~ 50 ms.


Leistungstestergebnis.
Leistungstestergebnis.


Zusammenfassung


Ein praktisches Experiment bestätigte die Annahmen über die Konstanz des Anstiegs der RoadRunner-Leistung für eine bestimmte Anwendung. Mit diesem Tool können Sie die Verarbeitung von Anwendungsanforderungen für eine Konstante beschleunigen, die der Initialisierungszeit der Umgebung und der Abhängigkeiten entspricht.


Bei leichten Handlern können Sie die Anwendung manchmal beschleunigen, bei schweren Handlern bewirkt dies fast keinen spürbaren Effekt. Wenn Ihr Code langsam ist, hilft ihm der Wegerich höchstwahrscheinlich nicht.


Wenn Ihre Anwendung gut geschrieben ist, gibt es höchstwahrscheinlich keine Probleme mit dem Betrieb über RoadRunner. Wenn die Anwendung jedoch für die Verwendung mit RoadRunner angepasst werden muss, wäre dies höchstwahrscheinlich ohne RoadRunner erforderlich gewesen, um die Architekturschichten klarer zu beobachten und Befolgen von Entwicklungsstandards auf dem Gebiet.


Magento Open Source eignet sich im Allgemeinen für den Start in der angegebenen Umgebung. Es erfordert jedoch Verbesserungen an der Transportschicht und eine Korrektur der Geschäftslogik, um ein falsches Verhalten bei wiederholten Anforderungen innerhalb desselben Prozesses zu verhindern. Die Verwendung von RoadRunner unterwirft den Entwicklungsansätzen gewisse Einschränkungen, widerspricht jedoch nicht den etablierten Praktiken.


Endlich ein schöner Screenshot. Wann werden Magento-Anfragen mit dieser Antwortzeit noch angezeigt?

Schock


Referenzen


  1. Beispiel aus dem Artikel
  2. Offizielle RoadRunner-Website

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


All Articles