Wir bei Badoo stellen aktiv auf PHP 7.4 um und sind sehr begeistert von der Möglichkeit, die neue Preload-Funktion zu nutzen. Vor nicht allzu langer Zeit haben wir über unsere Experimente mit ihr gesprochen.
Anscheinend ist die Community genauso aufgeregt wie wir. Framework-Entwickler
diskutieren aktiv
die Möglichkeit der Einführung eines Preloads (und einige haben dies bereits
unterstützt ). Jetzt ist der Abhängigkeitsmanager von Composer an der Reihe.
Italo Baeza schrieb
einen Artikel, in dem er seine Meinung darüber äußerte, wie Composer mit der Vorspannung arbeiten sollte. Ich beschloss, eine Übersetzung dieses Textes und gleichzeitig eine Übersetzung
seines anderen Artikels darüber zu teilen, wie die Composer-Entwickler selbst auf den Vorschlag geantwortet haben, sowie über ein neues Tool, das die Arbeit mit dem Preload erleichtert.
Wie sollte Composer in PHP 7.4 vorinstalliert werden?
Preload ist eine der wichtigen Funktionen, die PHP 7.4 Entwicklern bietet, die eine bessere Leistung benötigen. Diese Funktion kann als "Aufwärmen" bezeichnet werden, bevor die JIT-Engine implementiert wird, die in PHP 8 angezeigt wird (oder angezeigt werden sollte). Vorher reicht das Vorabladen aus, und wer weiß, vielleicht können sie zusammenarbeiten.
Was die Vorladefunktion ist, wird in
diesem Artikel erklärt . Das Fazit ist sehr einfach: php.ini gibt ein PHP-Skript an, für das beim Start des Prozesses Dateien in den Speicher geladen werden (Preload). In Kombination mit OPCache und der Autoloader-Funktion
können Composer-Dateien auch einmal kompiliert und verknüpft werden. Danach stehen sie für alle nachfolgenden Anforderungen zur Verfügung. Dadurch muss PHP nicht bei jeder Anforderung Dateien herunterladen und kompilieren.
Die Composer-Entwickler haben sich jedoch nicht darauf geeinigt, wie das Vorladen zusätzlich zu den Startfunktionen unterstützt werden soll. Die Fakten sind wie folgt:
- Preloading wurde erstmals in PHP 7.4 angekündigt;
- Es gibt keine Composer-Direktive, mit deren Hilfe Dateien vorab geladen werden können.
- Zum Vorabladen benötigen Sie Zugriff auf die php.ini, dh auf den Prozess selbst.
- Durch das Vorladen aller Dateien wird die Leistung nicht unbedingt verbessert, verglichen mit dem Vorladen nur der am häufigsten angeforderten Dateien.
Mit anderen Worten, nur diejenigen, die vollen Zugriff auf die Server haben, können das Preloading verwenden. Dies schließt gemeinsam genutzte Server und einige PaaS-Lösungen aus, bei denen nicht mit php.ini gearbeitet wird.
Wie kann Composer beim Vorladen helfen, da dies eine Innovation ist? Hier ist meine Meinung.
Wie sollte die Vorspannung funktionieren?
Der Mechanismus zum Vorabladen sollte auf einer Liste von Dateien basieren, die beim Start
geladen und im Speicher abgelegt werden. Und da dies eine Liste ist, müssen wir mit einem Array von Dateien arbeiten und Composer die ganze Arbeit überlassen, anstatt jede Datei manuell zu
laden .
Composer sollte die Liste der von der Anwendung angegebenen Dateien (das Stammprojekt) nehmen und alles in Dateien kompilieren, die PHP problemlos verwenden kann.
Gleichzeitig müssen wir in der Lage sein, Pakete zum Preload-Mechanismus hinzuzufügen und daraus zu entfernen.
Das Vorladen sollte niemals auf Paketebene funktionieren, da es in der Verantwortung des Entwicklers liegt, das Vorladen jedes Pakets zu aktivieren oder zu deaktivieren.
Das Vorladen in Composer sollte optional sein. Der Entwickler muss in der Lage sein, es zu deaktivieren, damit PHP seinen eigenen Preloader verwendet, der auf der Grundlage der OPCache-Analyse arbeiten kann. Er hängt von der Anwendungslast ab und arbeitet wesentlich effizienter als das einfache Vorladen aller Dateien.
Alles beginnt bei preload.json
Um das System nicht zu komplizieren, legen Sie die Datei preload.json im Stammverzeichnis des Projekts ab. Daraufhin werden die Vorladedateien aufgelistet, die Composer auswählen kann. Da es sich um eine JSON-Datei handelt, kann der Entwickler sie mithilfe eines speziellen Befehls generieren. Ich denke, es wäre großartig, wenn Composer ein Hilfsprogramm zum Erstellen einer solchen skriptbasierten JSON-Datei hätte.
{ "pre-compile": [ "my-script.php", "my-other-script.php" ], "extensions": [ "php" ], "files": [ "app/*", "config/", "helpers.php", "app/Models/*", "app/Controllers/*/Http/*", "app/Views/Compiled*.php" ], "namespace": [ "App\\Models", "App\\Controllers\\", "App\\Views\\MainView", "Vendor\\Package\\*", ], "packages": { "symfony/http-client": true, "robert/*-client": true, "vendor/package": { "files": true, "namespace": true }, "foo/bar": { "files": [ "helpers.php", "loaders/*" ], "namespace": [ "Foo\\Bar\\DynamicLoaders\\*", "Foo\\Bar\\Clients" ] } }, "output": "preload-compiled.php" }
Mit preload.json können Sie schnell überprüfen, ob das Vorladen im Projekt enthalten ist: Wenn die Datei fehlt, wird das Vorladen nicht unterstützt oder ist unerwünscht.
Mal sehen, was die Tasten tun.
vorkompilierenDiese Dateien werden von Composer ausgeführt. Jedes Skript muss ein Array absoluter Dateipfade zurückgeben, um sie der Preload-Liste hinzuzufügen, die die Rolle der Hauptliste übernimmt.
"pre-compile": [ "my-script.php", "my-other-script.php" ]
Diese Dateien werden in der angegebenen Reihenfolge ausgeführt.
Ziel ist es, dass der Entwickler eine Liste von Dateien erstellt, die er für richtig hält, anstatt sich auf eine einzelne JSON-Datei zu verlassen. Diese Dateien werden zuerst ausgeführt. Und ja, Sie können preload.json nur mit diesem Schlüssel implementieren. Da es sich um PHP-Dateien handelt, können Sie beim Kompilieren eines Arrays sogar andere Dateien hinzufügen.
ErweiterungenDies ist eine Liste der Dateierweiterungen, die vorab geladen werden müssen. Standardmäßig werden nur Dateien mit der PHP-Erweiterung verwendet.
"extensions": ["php", "php5", "php7"]
Sie können beispielsweise ein Verzeichnis hinzufügen, das mit * .phtml-Dateien gefüllt ist, einschließlich einiger nützlicher PHP-Dateien, und Composer wählt nur diese und nicht den gesamten Inhalt des Verzeichnisses aus.
Wie Sie verstehen, kann dieser Vorgang durch manuelles Hinzufügen von Dateien ersetzt werden.
DateienDieser Schlüssel weist Composer an, alle Dateien aus der Liste herunterzuladen, deren Pfade sich auf den Speicherort von composer.json beziehen.
"files": [ "helpers.php", "app/Models/*", "app/Controllers/*/Http/*", "app/Views/Compiled*.php", ]
Die Liste herauszufinden ist einfach:
- Verwenden Sie relative Pfade, um Dateien und Verzeichnisse hinzuzufügen.
- Aus Verzeichnissen werden nur untergeordnete Dateien hinzugefügt (nicht rekursiv).
- rekursive Pfade werden durch ein Sternchen (*) gekennzeichnet;
- Mit diesem Symbol können Sie beispielsweise auch bestimmte Dateien und Verzeichnisse hinzufügen:
src/Clients/*/Stores
oder src/Model*.php
.
Das Hinzufügen von Dateien per Maske ohne manuelle Auswahl oder Erstellung von anwendungsspezifischen Skripten ist besonders nützlich, wenn Sie große Anwendungen entwickeln.
Wenn Sie nur alle Dateien mit
dem Autoload-Schlüssel in der Composer-JSON-Datei vorab laden müssen, setzen Sie ihn auf
true
.
NamespaceDieser Schlüssel weist Composer an, Dateien mit einem bestimmten Namespace oder Klassennamen wie
file
oder
directory
zu laden. Mit demselben Mechanismus können Sie Space-Namen aus anderen installierten Paketen dynamisch aufrufen.
"namespaces": [ "App\\Models", "App\\Controllers\\", "App\\Views\\MainView", "Vendor\\Package\\*", ]
Dies ist auch praktisch, wenn Sie mit großen Anwendungen arbeiten, die stärker von Namespaces abhängig sind, als von Dateien, die sich jederzeit ändern können. Composer extrahiert Dateien automatisch gemäß dem Namespace und fügt sie in eine Liste ein.
PaketeMit diesem Schlüssel können Sie andere Dateien laden, die aus externen Paketen registriert wurden, z. B. Hilfsdateien oder Klassen, die einem Namespace zugeordnet sind.
"packages": { "symfony/http-client": true, "robert/*-client": true, "vendor/package": { "files": true, "namespace": true }, "foo/bar": { "files": { "helpers.php", "loaders/*" }, "namespace": [ "Foo\\Bar\\DynamicLoaders\\*", "Foo\\Bar\\Clients" ] } }
Hier ist alles ganz einfach: Wenn der Wert true ist, wird der gesamte Inhalt
des Autoload-Schlüssels in der Datei composer.json dieses Pakets geladen. Andernfalls können Sie die Vorspannungsaddition genauer steuern.
Wenn der Schlüsselwert true ist, werden alle beim
autoload
Laden registrierten Dateien heruntergeladen. Der Standardwert ist
false
. Dies gilt auch für den
namespace
Schlüssel.
Sie können mit dieser Regel auch einzelne Dateien oder Namespaces auswählen. In diesem Fall wird der
autoload
Schlüssel jedoch nicht verwendet.
AusgabeDies ist einfach der Name der kompilierten Preload-Listendatei.
"output": "preload-compiled.php"
Einfache Montage
Unsere Preload-Liste ist fertig und wir können Composer aufrufen, um das Haupt-Preload-Skript zu kompilieren.
composer preload
Infolgedessen wird preload-compiled.php mit allen Dateien erstellt, die PHP vorladen muss. Natürlich können Sie den Dateinamen beliebig ändern.
Sie müssen auch die
preload
Schlüssel
preload
Parametern überschreiben.
composer preload \ --input=my-custom-preload-list.json \ --output=my-preload.php
Standardmäßig deaktiviert
Projekte ohne preload.json geben einen Fehler zurück, wenn Sie versuchen, eine Datei zum Vorladen zu kompilieren. Der Grund dafür ist, dass Composer nicht erraten wird (und sollte), was vorinstalliert werden soll.
Ich möchte Sie daran erinnern, dass das Vorladen die normale Funktionalität von Composer nicht beeinträchtigt. Da dies ein Konsolenbefehl ist, können Sie bei lokaler Entwicklung das Vorladen vollständig abbrechen. Das einzige, was der Composer-Vorlademechanismus benötigt, ist eine Autoload-Datei, die generiert werden sollte, wenn sie fehlt. Immerhin ist fast das 2020. Jahr in der Werft, PSR-4 wird überall eingesetzt, oder?
Ergebnis
Sie sollten eine PHP-Datei mit so etwas bekommen:
<?php
Tatsächlich ist dies nur eine Liste von Dateien, die mithilfe der Autoloader-Funktion in Composer vorgeladen werden. PHP wird diese Datei einmal ausführen und es wird Geschichte.
Ich hoffe aufrichtig, dass Composer die Möglichkeit hat, Dateien vorab zu laden, ohne einen Hack schreiben zu müssen.
Da die oben beschriebene Methode nicht Teil des Composer-Kernels ist, können Sie dennoch die wichtigsten Dateien für das Vorladen auf der Grundlage der OPCache-Analyse auswählen, ohne die weniger benötigten zu berühren. Anstatt 1.500 Dateien mit einer Kapazität von 100 MB vorab zu laden, können Sie nur 150 Dateien mit einer Kapazität von 10 MB herunterladen und dabei 99% der ursprünglichen Leistung beibehalten.
Wir laden das PHP 7.4-Projekt in einer Zeile vor
Kurz nachdem ich einen Artikel darüber geschrieben hatte, wie Composer Sie beim
Vorabladen eines Projekts unterstützen kann, hat
Seldaek (ein Mitglied des Composer-Entwicklungsteams)
die Hoffnung zunichte gemacht , dass Composer eine einfache Option zum Vorabladen des Projekts in den PHP-Prozess vom Paket-Manager aus haben würde.
(...) Ich werde erklären: Ich bin mir sicher, dass wir in naher Zukunft nichts hinzufügen werden, was mit dem Vorladen von Composer zu tun hat.
Warum? Das Vorabladen in PHP ist eher ein Entwicklungsproblem (als ein Abhängigkeitsproblem) und wird durch manuelles Bearbeiten der Datei php.ini gelöst. Dies können nur Entwickler, die PHP selbst verwalten.
Dies hindert mich jedoch nicht daran, ein eigenes Paket zum Vorabladen des Projekts zu erstellen. Und du auch.
Vorspannung und Metriken
Das Vorladen kann ein gutes Werkzeug für eine
einfache und kostengünstige Steigerung der Produktivität ohne ernsthafte Verarbeitung sein.
Aber das Problem ist nicht,
wie man vorlädt, sondern
was . Durch das Vorladen ganzer Frameworks und Tausender von Dateien wird der Arbeitsspeicher schnell erschöpft, sodass es zumindest in großen Projekten nicht möglich ist, dies blind zu tun. Es wird empfohlen, nur die am häufigsten angeforderten Dateien herunterzuladen. Aber wie definiert man sie?
Glücklicherweise ermöglicht
OPCache opcache_get_status () , Daten darüber zu sammeln, auf welche Dateien am häufigsten zugegriffen wird. Sie können nicht nur herausfinden, welche Dateien am meisten nachgefragt werden, sondern auch, wie viel Speicher sie einige Zeit nach dem Start der Anwendung verbrauchen.
Es wird empfohlen, entweder eine Woche oder bis zu dem Zeitpunkt zu warten, an dem OPCache eine bestimmte Anzahl von Treffern registriert. Es hängt alles von der Anwendung ab, aber Sie bekommen den Punkt.
Erstellen wir also eine Preload-Liste basierend auf den Statistiken der beliebtesten Dateien. Ich habe ein Paket dafür gemacht.
Stellen Sie sich vor ... Preloader!
Dieses Paket erstellt automatisch eine Vorladeliste für Ihre Anwendung. Es werden OPCache-Nutzungsstatistiken erfasst, die Dateien nach der Anzahl der Treffer sortiert und eine Liste erstellt, sodass die Gesamtdateigröße den angegebenen Schwellenwert nicht überschreitet.

Ich habe lange nach der besten Strategie für die Erstellung einer Liste gesucht. Und ich bin zu dem Schluss gekommen, dass es am besten ist, alle Dateien hinzuzufügen, bis das Speicherlimit erreicht ist, das für Pakete standardmäßig 32 MB beträgt. Dateien werden nach der Anzahl der Treffer sortiert und das Paket wird automatisch ausgeschlossen.
Mit anderen Worten, PHP verbessert die Anwendungsleistung bei der Verarbeitung der meisten Anfragen.
Und wie benutzt man es? Teilen Sie Composer Autoloader mit, wo das Preloader-Skript geschrieben werden soll, und fertig.
use DarkGhostHunter\Preloader\Preloader; Preloader::make() ->autoload('vendor/autoload.php') ->output('preload.php') ->generate();
Natürlich müssen Sie auswählen, wann generiert werden soll, aber das ist der springende Punkt. Sie können dies sogar nach dem Zufallsprinzip tun und die Liste beispielsweise für jede 100. Anforderung neu schreiben.
use DarkGhostHunter\Preloader\Preloader; Preloader::make() ->whenOneIn(100) ->autoload('vendor/autoload.php') ->output('preload.php') ->overwrite() ->generate();
Sie erhalten ein fertiges Preload-Skript, das Sie in die php.ini einfügen können.
<?php require_once '/www/app/vendor/autoload.php'; $files = [ '/www/app/ClassFoo.php', '/www/app/ClassBar.php', '/www/app/ClassBaz.php', '/www/app/ClassQuz.php', '/www/app/ClassQux.php', '/www/app/vendor/author/package/src/Example.php',
Und alle. Probieren Sie es aus:
darkghosthunter / preloader - Packagist .