Composer: [RFC] Unterstützung beim Vorladen

Erstellt am 7. Nov. 2018  ·  77Kommentare  ·  Quelle: composer/composer

Da eine allgemeine Preloading-Datei in PHP 7.4 (🎉) eine Sache zu werden scheint, sollten wir die Diskussion darüber beginnen, wie dies in Composer implementiert werden könnte. Ich bin bereit, dafür an einer PR zu arbeiten, aber zuerst sind einige Dinge zu klären.
Hier sind nur ein paar Gedanken, die mir in den Sinn kommen, wenn ich über die Umsetzung nachdenke:

  • Sollte der Vorladeabschnitt getrennt vom Autoload-Abschnitt behandelt werden?
  • Ist es überhaupt sinnvoll, sie zu trennen? Ich meine, wenn Sie den optimierten Autoloader ausgeben, warum sollten Sie dann nicht alle Klassen vorab laden? Gibt es sogar Szenarien, in denen Sie nicht alle Ihre Dateien vorab laden möchten?
  • Ist es überhaupt sinnvoll alle Dateien vorab zu laden oder schadet das der Performance? Sollten wir uns für Hot-Path-Preloading entscheiden, was wiederum bedeuten würde, dass Autoloading und Preloading tatsächlich getrennt werden müssen?
  • vendor/preload.php ?
  • Wenn das Vorladen als Erweiterung des optimierten Autoloads angesehen werden kann, wie würde dann der Befehl aussehen? composer dump-autoload -o -p ( -p würde dann auch die preload.php generieren )

Ich bin sicher, es gibt noch mehr zu bedenken und zu diskutieren. Es gibt einige sehr schlaue Cookies in unserer Community, also lasst uns zuerst gemeinsam die beste Lösung ausarbeiten und erst dann mit dem Codieren beginnen 😊

Feature

Hilfreichster Kommentar

Ich habe einen Benchmark mit einem mittelgroßen Projekt von mir (90 Paketabhängigkeiten) durchgeführt, das bei jeder Anfrage ein ziemlich umfangreiches Bootstrap-Skript enthält, das Klassen für die Abhängigkeitsinjektion einrichtet; Dies macht es zu einem guten Kandidaten für das Benchmarking der Klassenbelastung unter realen Bedingungen.

Ich habe eine einfache Seite der Website einem Benchmarking unterzogen, die die Datenbank sehr wenig nutzt, aber allein das automatische Laden von 380 Klassen auslöst. Ich habe folgende Konfigurationen getestet:

Kein Vorspannen

Ich habe den optimierten Autoloader von Composer verwendet: composer install --optimize-autoloader . Der Opcache wurde durch manuelles Laden der Seite aufgewärmt.

Nur "heiße" Klassen vorladen

Ich habe den Server neu gestartet, genügend Seiten von der Website geladen und dann dieses Skript verwendet, um eine Preload-Datei aus zwischengespeicherten Dateien zu generieren, wie von opcache berichtet:

<?php

header('Content-Type: text/plain');

echo '<?php', PHP_EOL;

$status = opcache_get_status(true);

foreach ($status['scripts'] as $script) {
        $path = $script['full_path'];
        echo 'opcache_compile_file(', var_export($path, true), ');', PHP_EOL;
}

Dieses Skript lädt 878 Dateien vorab.

Alle Klassen vorladen

Ich habe das folgende Preload-Skript verwendet, das die gesamte Composer Classmap vorlädt:

<?php

$files = require 'vendor/composer/autoload_classmap.php';

foreach (array_unique($files) as $file) {
    opcache_compile_file($file);
}

Dieses Skript lädt 14.541 Dateien vorab .

Ergebnisse

| Benchmark | Vorinstallierte Dateien | Startzeit des Servers | Verwendeter Opcache-Speicher | Pro Anfrage verwendeter Speicher | Anfragen pro Sekunde |
| --- | --- | --- | --- | --- | --- |
| Keine Vorspannung | 0 | 0,06 s | 16 MB nach dem Aufwärmen | 1,825 KB | 596 rq/s |
| Heiße Klassen vorladen | 878 | 0,26 s | 21 MB | 869 KB | 695 rq/s |
| Alles vorladen | 14541 | 1,56 s | 105 MB | 881 KB | 675 rq/s |

Wir können interessante Leistungsvorteile sehen, wenn wir das Vorladen verwenden:

  • + 13% wenn alles vorgeladen wird
  • + 16% wenn nur heiße Klassen vorab geladen werden

Wie von @dstogov vorhergesagt, ist die Ausführung etwas schneller, wenn nur die von einem bestimmten Projekt verwendeten Klassen

Die Startzeit des Servers ist für mich kein Thema, und der Overhead für das Vorladen von allem im Vergleich zum Vorladen von heißen Klassen beträgt hier nur 84 MB, also auf moderner Hardware vernachlässigbar.

Interessant ist auch, dass die Verwendung von Preloading (alles oder nur heiße Klassen, egal) den Speicherverbrauch pro Anfrage halbiert !

Einpacken

  • alles vorzuladen ist keine große Sache und kann ohne Konfiguration durchgeführt werden;
  • Nur heiße Klassen vorab zu laden ist etwas optimierter und es lohnt sich, wenn Sie sich die Zeit nehmen können, Ihren Opcache so weit aufzuwärmen, dass er so viele Klassen wie möglich abdeckt, bevor Sie das Preloader-Generatorskript ausführen.

Wenn ich mir die obigen Skripte anschaue, sind


Benchmark-Informationen:

  • VM mit 4 Kernen, 4GB RAM auf meinem i7 Laptop mit NVMe SSD
  • Fedora 29, neuestes PHP master aus Quellcode kompiliert
  • Apache + PHP-FPM
  • opcache.memory_consumption=1000
  • opcache.max_accelerated_files=20000

Benchmarks wurden mit Apache Bench ausgeführt, 1000 Anfragen mit 10 gleichzeitigen Anfragen. Alle Benchmarks wurden 50 Mal durchlaufen und das beste Ergebnis wurde verwendet.

Alle 77 Kommentare

Meine erste Idee, wie dies funktionieren würde, wäre der files Autoloader, ein neuer preload Autoloading-Typ. Auf diese Weise kann jedes Paket Dateien deklarieren, die vorab geladen werden müssen, und wir generieren eine einzelne Datei mit allen Include-Dateien. Diese Dateien können dann eine intelligentere Logik haben, was vorab geladen werden soll. Ich würde erwarten, dass Symfony zum Beispiel gemäß der Containerkonfiguration und so weiter vorlädt.

Ich denke nicht, dass es immer eine gute Idee ist, alle Klassen vorab zu laden, da dies nur die Speicherauslastung ohne Grund in die Höhe treibt.

Dies ist auch sehr billig zu generieren, ähnlich wie das automatische Laden von Dateien. Es wird einfach ein Array von Dateien in preload.php abgelegt, sodass es immer erstellt werden kann, ohne wie ein optimierter Autoloader optional zu sein.

Ich verstehe. Das ist auch eine schöne Idee!

Ich denke nicht, dass es immer eine gute Idee ist, alle Klassen vorab zu laden, da dies nur die Speicherauslastung ohne Grund in die Höhe treibt.

Ich stimme zu, es macht keinen Sinn, alle Klassen zu laden, wenn nicht alle verwendet werden. Als Entwickler einer App möchte ich dies jedoch selbst optimieren können, daher halte ich es nicht für sinnvoll, die Verantwortung für die Definition der Klassen, die vorab geladen werden müssen, an den Entwickler der Bibliothek zu übertragen. Nehmen wir die Symfony-Komponente VarDumper als Beispiel: In 99,5 % aller Fälle wird diese nur zu Debugging-Zwecken verwendet, daher macht es wahrscheinlich keinen Sinn, Klassen davon vorzuladen. Aber was ist, wenn jemand einen API-Dienst erstellt, der diese Komponente verwendet, um eine Ausgabe zu gestalten? Vorladen wäre da dann sinnvoll.
Mit anderen Worten: Ob das Vorladen einer Klasse sinnvoll ist oder nicht, hängt davon ab, wie sie verwendet wird und meistens kann der Entwickler der Bibliothek nicht sagen, wie sie verwendet werden soll.

Ich habe mich auch gefragt, über wie viel RAM-Auslastung wir sprechen. Hier sind also einige Statistiken für alle:

  • Ich habe meinen Opcode-Cache zurückgesetzt. Es verwendet standardmäßig 18,07 MB (nicht sicher, woher diese Standardnutzung kommt, aber jedes Mal, wenn ich sie zurücksetze, war es wieder bei 18,07, also denke ich, dass es fair ist, dies als Ausgangspunkt zu nehmen)
  • Ich habe composer create-project symfony/skeleton und die Willkommensseite in der Umgebung prod aufgerufen ( debug auf true ).
  • Danach lag die Speicherauslastung bei 19,56 MB (157 zwischengespeicherte Dateien).

Dann habe ich composer dump-autoload -o --no-dev und mein index.php bearbeitet, um ein einfaches Vorladen basierend auf dem autoload_classmap.php . Also habe ich wirklich nur die _preload() Funktion aus dem RFC verwendet und dies zu meinem index.php hinzugefügt:

$classmap = include './../vendor/composer/autoload_classmap.php';
$classmap = array_unique($classmap); // Needed because we have multiple classes in some files
_preload($classmap);

Ich habe den Cache zurückgesetzt und erneut die Willkommensseite besucht: Die Speicherauslastung stieg auf 27,74 MB (919 zwischengespeicherte Dateien).

Also ja, die Speicherauslastung nimmt zu, aber ist sie wirklich so bedeutend? Ich meine, wenn Sie das Vorladen überhaupt aktivieren, wollen Sie eine gute Leistung, oder? Ist es dann ein Problem, dass Ihre App ständig viel RAM verwendet?

Alles, was ich hier versuche, ist, einfach ein paar Zahlen einzubringen, damit wir die Vor- und Nachteile abwägen können.

| Variante | Profis | Nachteile |
|--------------------------------|---------------- ----------------------------------------|--------- -------------------------------------------------- ------------------------------------------------|
| Klassenkarte vorladen | Super einfach;
Einfach zu implementieren;
Einfach zu verwenden; | Benötigt mehr RAM; |
| Neuer "Preload"-Autoload-Abschnitt | Mehr Speichereffizienz; | Paketentwickler müssen es lernen;
Keine Kontrolle für App-Entwickler;
Verpasst wahrscheinlich Dateien auf dem Hot-Pfad; |

Vielleicht gibt es noch mehr Varianten? 😄

Hier sind die Nummern eines größeren Projekts mit ApiPlatform, Doctrine, Guzzle, Enqueue, Symfony Translator, Redis, Symfony Console usw.):

Indexseite (docs endpoint) ohne alles vorab zu laden: 33,36 MB (15,29 MB netto)
Indexseite (docs endpoint) mit Vorladen von allem: 75,31 (57,24 MB netto)

Sie benötigen also mehr als die doppelte Menge an RAM. Mit anderen Worten, Sie können nur weniger als die Hälfte der Benutzer bedienen im Vergleich zu nicht vorinstallierten mit demselben Server

Nun, das ist kein fairer Vergleich. Ich habe nur einen Endpunkt angerufen. Ich müsste die anderen Endpunkte, die andere Komponenten verwenden, nacheinander aufrufen, wenn wir den Prozentsatz der "nutzlos zwischengespeicherten Dateien" herausfinden wollten. Ich glaube, ich würde den 57,24 MB viel näher kommen, wenn ich das täte

Immer noch viel Overhead. Mehr als ich möchte bezahlen, um die Funktion beim Laden all der Dinge nützlich zu nennen

IMO alles laden funktioniert nur für kleine Apps

Ich weiß Ihren Enthusiasmus zu schätzen, aber ich glaube nicht, dass der Komponist dafür verantwortlich ist. Ich stimme voll und ganz zu, dass es höchstwahrscheinlich app-spezifisch ist, was Sie vorab laden möchten, aber in meinem Vorschlag sind zwei Dinge zu berücksichtigen:

  • das preload Autoload muss nicht von jedem Paket definiert werden. Normalerweise würde ich erwarten, dass Symfony das definiert, oder vielleicht eine Krypto-Bibliothek, die stark vom Vorladen profitiert, vorausgesetzt, wir erhalten JIT-Optimierungen.
  • Sie müssen Ihre php.ini nicht auf die Datei preload.php verweisen, die der Composer generiert. Wenn Sie einen benutzerdefinierten möchten, erstellen Sie einen benutzerdefinierten. Frameworks sollten auf jeden Fall Tools dafür bieten.

Zu guter Letzt, was die Option betrifft, die gesamte Classmap vorab zu laden, das ist eine 3-zeilige foreach-Schleife, die Sie als Ihr eigenes Preload-Skript schreiben können, das alle Klassen aus der Classmap von Composer lädt, wenn Sie so geneigt sind, Speicher zu verschwenden;) Es könnte auch als Paket angeboten werden toflar/preload-all-the-things mit einem preload Autoload, der dann alle Dateien aus der Klassenkarte einschließt.

Also ist meine Position, zumindest für den Moment, entweder etwas sehr Einfaches zu tun, um die Dinge zu erleichtern und eine vendor/preload.php Datei zu "standardisieren", oder alternativ tun wir überhaupt nichts.

Ich neige dazu, @Seldaek hier zuzustimmen.

Die Preloading-Everything-Strategie ist bereits einfach, wenn Sie eine vollständige Classmap für den optimierten Autoloader generieren (was Sie sowieso tun sollten, wenn Ihnen die Leistung wichtig ist, und Sie brauchen kein Preload, wenn es Ihnen egal ist).
Jeder intelligentere Algorithmus müsste sich auf die Struktur des Projekts verlassen, und daher könnte es in Composer schwierig sein, damit umzugehen.
In Symfony macht es wahrscheinlich keinen Sinn, eine Konfiguration im Paket zu haben, die entscheidet, welche Symfony-Dateien für alle Symfony-Projekte vorgeladen werden. Aber Symfony könnte Preload-Dateien für Projekte generieren https://github.com/symfony/symfony/issues/29105#issuecomment -436564272 vorgeschlagen (ich habe hier das Beispiel von Symfony genommen, weil ich den aktuellen Stand der Diskussion hier kenne, aber das gleiche könnte zutreffen für andere Frameworks natürlich).

Übrigens: Ich neige überhaupt nicht dazu, Speicher zu verschwenden. Da kam mir nur eine Variante in den Sinn und so habe ich sie weiter ausgeführt. Ich denke, es ist gut, mehrere Ansätze in Betracht zu ziehen, auch für die Leute, die die Ausgabe später lesen. Ich finde es völlig in Ordnung, die schlechten auszuschließen 😄

Wir könnten den Abschnitt preload nur im Stamm composer.json zulassen (also projektspezifisch) und dort geben Sie die Dateien an, die eingeschlossen werden sollen. Ob Sie andere Dateien verwenden, die zB von Symfony dynamisch generiert werden, ist dann Ihre Sache. Aber die wichtige Funktion hier wäre Composer, mit dem Sie sofort aggregieren können (und vielleicht können wir die Standardeinstellung der php.ini auf vendor/preload.php in PHP selbst setzen, die einfach ignoriert würde, wenn dies der Fall ist. t existiert 😄).

@Toflar Wenn es nur Root ist, warum sollten Sie sie dann in Composer.json ablegen, damit Composer sie in einer anderen Datei benötigt, auf die Sie dann in Ihrer php.ini verweisen können? Sie können Ihre eigene Datei direkt in der php.ini referenzieren.

Ich weiß 😄 Das einzige, was es tun würde, wäre, die Art und Weise etwas zu "standardisieren". Nichts anderes 😊

Ich würde denken, dass das Erstellen von Ebenen für das automatische Laden wie Protokollierungsebenen eine Art "automatisierte" Kontrolle ermöglichen würde, wobei die Bibliothek die Dateien/Klassen bereitstellt, die für die Ebene geeignet wären. Eine Überebene wie "all" könnte alle Dateien enthalten, einschließlich der Dateien für Bibliotheken, die die Ebenen nicht unterstützen. Klingt nach etwas, das auch in den Diskussionsbereich von PHP-FIG passen könnte.

Einige desorganisierte Gedanken:

1) Eine Möglichkeit, Dateien zum Vorabladen auf die Whitelist zu setzen, muss Regex-Unterstützung beinhalten; In der Praxis laden die wichtigsten Anwendungen bei jeder Anfrage Hunderte von Klassen. Ich esse lieber die Kosten für das Vorladen ein paar mehr als ich brauche, als sie alle manuell auflisten zu müssen.

2) Eine wichtige Frage ist, dass AIUI der erhöhte Speicherverbrauch geteilt wird, nicht wahr? Das heißt, wenn wir Klassen mit einem Wert von 50 MB vorab laden, erhöht dies die Speichernutzung jeder Anforderung um 50 MB oder erhöht es die Grundkosten für FPM-Prozesse um 50 MB, reduziert aber netto den Speicher pro Anforderung? (Ich weiß es hier ehrlich gesagt nicht, aber es ist eine Unterscheidung, die es wert ist, überprüft zu werden.)

3) Da Composer zu diesem Zeitpunkt im Grunde der universelle Autoloader ist, gibt es eine Möglichkeit, wie Composer bei der Bestimmung der geeigneten Kandidaten für das Vorladen helfen kann? Ich bin mir nicht ganz sicher, wie das gehen würde, ohne Daten auf die Festplatte zu schreiben, was wahrscheinlich unerwünscht ist, aber wenn wir sagen "Site-Besitzer, das ist Ihre Aufgabe", sollten wir versuchen, ihnen genügend Informationen zu geben, um dies zu erreichen Arbeit ganz einfach. Was sie wollen, ist eine Liste der X am meisten geladenen Klassen oder der Klassen, die bei mehr als Y% der Anfragen verwendet werden, oder so ähnlich. Ist das etwas, mit dem Composer bei der Berechnung helfen kann, und wenn nicht, was würde es tun?

4) Obwohl ich die Einfachheit des "Vorladens aller Dinge" befürworte, gibt es einige Dateien, die NICHT vorgeladen werden dürfen. Bei Platform.sh verwenden wir beispielsweise ein vom Composer geladenes file (keine Klasse), um Code auszuführen, bevor die Anwendung initialisiert wird. Auf diese Weise können wir vom Host bereitgestellte Umgebungsvariablen den von der Anwendung erwarteten Umgebungsvariablen zuordnen. Der Prozess funktioniert ziemlich gut, aber dieser Code muss bei jeder Anfrage ausgeführt werden, sodass die Datei keinen Code zur Symboldefinition enthält (dh sie verstößt gegen PSR-1), und daher würde ein Vorladen die Dinge kaputt machen. Daher ist es wahrscheinlich für jedes Auto-Preload-Builder-Ding (Composer oder andere) nützlich, eine Möglichkeit zu integrieren, Pakete auf die Blacklist bestimmter Dateien zu setzen, die niemals vorab geladen werden sollten.

5) Ich sehe hier nicht wirklich einen Platz für FIG; Was für FIG in den Anwendungsbereich fallen würde, wäre "Hey Pakete, so stellen Sie Ihre Preload-Informationen zur Verfügung". Aber wirklich, selbst wenn wir entscheiden, dass dies die Aufgabe eines Pakets ist (und das kann es sein), wird dies zu 99,999947% der Zeit über Composer.json erfolgen, was außerhalb des Zuständigkeitsbereichs von FIG liegt.

Ich stimme voll und ganz zu, dass preload ein separater Abschnitt von autoload da es sich um unterschiedliche Konzepte handelt. Zum einen können Sie einen Autoloader in Ihrem Preload-Skript verwenden:

<?php

spl_autoload_register(function($name) {
    include_once("$name.php");
});

use Foo;

Denken Sie daran, was vorinstalliert werden soll und was nicht, um die vorinstallierten Dateien zu aktualisieren, müssen Sie php neu starten. Ich denke, der typischste Anwendungsfall wäre, Ihren Anbieter vorab zu laden, aber Ihre Anwendung davon fernzuhalten, damit Sie Änderungen an Ihrer Anwendung ohne Serverneustart bereitstellen können.

Eine wichtige Frage ist, dass AIUI der erhöhte Speicherverbrauch geteilt wird, nicht wahr? Das heißt, wenn wir Klassen mit einem Wert von 50 MB vorab laden, erhöht dies die Speichernutzung jeder Anforderung um 50 MB oder erhöht es die Grundkosten für FPM-Prozesse um 50 MB, reduziert aber netto den Speicher pro Anforderung? (Ich weiß es hier ehrlich gesagt nicht, aber es ist eine Unterscheidung, die es wert ist, überprüft zu werden.)

Das ist dieselbe Frage, die ich mir gestellt habe. Weil ich es so verstehe, dass man Sachen vorlädt, die später sowieso in den Speicher geladen würden. Nur nicht auf jede Anfrage, sondern geteilt. Was wiederum bedeutet, dass das "Vorladen aller Dinge" die verwendete Speichermenge nicht effektiv ändert, mit Ausnahme des Prozentsatzes der Klassen, die nicht benötigt werden, auch bekannt als Klassen, die mit einer Bibliothek geliefert, aber nie im Kontext der App verwendet werden.
Aber auch nicht ganz sicher, aber sehr wichtig zu wissen.

@Toflar Ihre Antwort scheint davon auszugehen, dass alle Ihre Anfragen alle Klassen aus der Codebasis verwenden (also vom Projekt verwendet werden, die von der Anfrage verwendet werden). Bei den meisten Projekten ist das nicht der Fall. Viele Klassen werden nur von einigen spezifischen Anforderungen und nicht von allen verwendet.

Wenn Composer sich dazu entschließt, etwas zu tun, sollte es nur root sein. Es ist nicht hilfreich, Ihre Abhängigkeiten entscheiden zu lassen, was vorab geladen werden soll.

Eine wichtige Frage ist, dass AIUI der erhöhte Speicherverbrauch geteilt wird, nicht wahr? Das heißt, wenn wir Klassen mit einem Wert von 50 MB vorab laden, erhöht dies die Speichernutzung jeder Anforderung um 50 MB oder erhöht es die Grundkosten für FPM-Prozesse um 50 MB, reduziert aber netto den Speicher pro Anforderung? (Ich weiß es hier ehrlich gesagt nicht, aber es ist eine Unterscheidung, die es wert ist, überprüft zu werden.)

Wie @Crell und @Toflar habe ich mich dasselbe gefragt. Ich bezweifle stark, dass der Speicher, der durch das Vorladen von Klassen verwendet wird, in jeden einzelnen PHP-Prozess kopiert wird, ich denke, es ist Shared Memory (zu überprüfen), also würde das Vorladen des ganzen Zeugs "nur" ~100 MB verbrauchen, aber jeder PHP-Prozess danach frisst vielleicht weniger Erinnerung?

Ich persönlich bin dafür, dass Composer.json ein preload.php-Skript generiert, das standardmäßig alle Dateien aus dem Abschnitt preload des Projekts selbst und die Herstellerabhängigkeiten enthält.

Es macht mir jedoch nichts aus, wenn es eine Möglichkeit gibt , einige Dateien explizit autoload würde, es wären wahrscheinlich nur Entwicklerklassen, die in autoload-dev ?

Obwohl ich die Einfachheit des "Vorladens aller Dinge" befürworte, gibt es einige Dateien, die NICHT vorgeladen werden dürfen. Bei Platform.sh verwenden wir beispielsweise eine vom Composer geladene Datei (keine Klasse), um Code auszuführen, bevor die Anwendung initialisiert wird. Auf diese Weise können wir vom Host bereitgestellte Umgebungsvariablen den von der Anwendung erwarteten Umgebungsvariablen zuordnen. Der Prozess funktioniert ziemlich gut, aber dieser Code muss bei jeder Anfrage ausgeführt werden, sodass die Datei keinen Code zur Symboldefinition enthält (dh sie verstößt gegen PSR-1), und daher würde ein Vorladen die Dinge kaputt machen. Daher ist es wahrscheinlich für jeden Thinill gie von Auto-Preload-Builder (Composer oder andere) nützlich, eine Möglichkeit zu integrieren, Pakete auf die Blacklist bestimmter Dateien zu setzen, die niemals vorab geladen werden sollten.

Soweit ich das verstanden habe:

  • Sie müssen die vorinstallierten Dateien nicht ausführen , Sie können sie nur opcache_compile_file() ausführen ; Ich würde vorschlagen, dass die Datei preload.php nur eine große Liste von opcache_compile_file() Anweisungen ist;
  • Zur Überprüfung : Ich würde nicht erwarten, dass der Code in den vorinstallierten Dateien nicht ausgeführt wird. Soweit ich weiß, werden Klassendefinitionen in solchen Dateien zwischengespeichert, aber wenn Sie explizit eine vorgeladene Datei einschließen, denke ich, dass der Code neben den Klassen trotzdem ausgeführt wird.

Das einzige Problem, das mir für Ihren Anwendungsfall einfällt, ist, dass class_exists() true zurückgibt, da die Datei vorab geladen wurde, sodass der Autoloader möglicherweise nicht ausgelöst wird; Sie müssten die Datei daher explizit einschließen(). Mich würde jedoch interessieren, was Ihre Motivation ist, Klassendeklarationen mit anderem Code zu mischen: Sollte dieser – normalerweise nicht empfohlene – Ansatz den Composer daran hindern, für die meisten anderen Benutzer das Richtige zu tun? Nichts für ungut, aber ich denke, dass der Komponist darauf abzielen sollte, den empfohlenen Ansatz sofort zu unterstützen, und vielleicht sollte Ihr etwas exotischer Ansatz ein benutzerdefiniertes Vorladeskript erfordern?

@Toflar Ihre Antwort scheint davon auszugehen, dass alle Ihre Anfragen alle Klassen aus der Codebasis verwenden (also vom Projekt verwendet werden, die von der Anfrage verwendet werden). Bei den meisten Projekten ist das nicht der Fall. Viele Klassen werden nur von einigen spezifischen Anforderungen und nicht von allen verwendet.

Dann ist das Vorladen für diese Projekte nicht, wie im RFC explizit erwähnt:

Außerdem ist dieser Ansatz nicht mit Servern kompatibel, die mehrere Anwendungen oder mehrere Versionen von Anwendungen hosten – die unterschiedliche Implementierungen für bestimmte Klassen mit demselben Namen haben würden – wenn solche Klassen aus der Codebasis einer Anwendung vorgeladen werden, kommt es zu Konflikten beim Laden der anderen Klassenimplementierung aus der/den anderen App(s).


Daher würde ich preload.php (meine 2 Cent) folgendermaßen implementieren:

<?php

// list here all the files that are generated by the optimized autoloader

opcache_compile_file(...);
opcache_compile_file(...);
opcache_compile_file(...);
...

Dies wäre die Art von Datei, die ohne zusätzliche Konfiguration generiert würde. Es ist da, Sie können es verwenden, wenn Sie möchten, aber Sie müssen nicht.

Optional würde ich eine Option preload-exclude oder eine gleichwertige Option composer.json hinzufügen, die es ermöglicht, einzelne Dateien oder ganze Verzeichnisse oder sogar Herstellerabhängigkeiten auszuschließen.

Für diejenigen, die mehrere Versionen einer Anwendung / Abhängigkeit haben: Um es noch einmal zu wiederholen, würde ich empfehlen, das Vorabladen überhaupt nicht zu verwenden. Oder wenn Sie mutig genug sind, spielen Sie mit preload-exclude oder schreiben Sie Ihr eigenes Preload-Skript.

Für alle anderen Benutzer da draußen wird das Einbinden der automatisch generierten preload.php wie von Zauberhand funktionieren.

Vielleicht können wir @dstogov dazu bringen, uns zu helfen, die richtige Entscheidung für die PHP-Community hier zu treffen 😊

@BenMorel :

@Toflar Ihre Antwort scheint davon auszugehen, dass alle Ihre Anfragen alle Klassen aus der Codebasis verwenden (also vom Projekt verwendet werden, die von der Anfrage verwendet werden). Bei den meisten Projekten ist das nicht der Fall. Viele Klassen werden nur von einigen spezifischen Anforderungen und nicht von allen verwendet.

Dann ist das Vorladen für diese Projekte nicht, wie im RFC explizit erwähnt:

Außerdem ist dieser Ansatz nicht mit Servern kompatibel, die mehrere Anwendungen oder mehrere Versionen von Anwendungen hosten – die unterschiedliche Implementierungen für bestimmte Klassen mit demselben Namen haben würden – wenn solche Klassen aus der Codebasis einer Anwendung vorgeladen werden, kommt es zu Konflikten beim Laden der anderen Klassenimplementierung aus der/den anderen App(s).

Sie haben den Kommentar von @Toflar missverstanden, der Anwendung im Vergleich zu mehreren Anwendungen / mehreren Versionen von Anwendungen verwendet werden. Sie sind überhaupt nicht dasselbe.

@teohhanhui Ich glaube nicht, dass ich @Toflars Kommentar falsch verstanden @stof zitiert, der selbst auf @Toflar geantwortet hat.

Um meine Gedanken zu verdeutlichen:

  • nur einige Klassen werden in einigen Anforderungen der Anwendung verwendet:
    das Projekt würde immer noch davon profitieren, alle Klassen vorab zu laden (es sei denn, der Speicher ist ein Problem, was ich stark bezweifle).
  • mehrere Anwendungen mit verschiedenen Versionen derselben Abhängigkeit / mehrere Versionen von Anwendungen:
    Ich würde das Vorladen überhaupt nicht verwenden oder es dem Benutzer überlassen, sein eigenes Vorladeskript zu erstellen, wenn er weiß, was er tut.

Vielleicht können wir @dstogov dazu bringen, uns zu helfen, die richtige Entscheidung für die PHP-Community hier zu treffen

Ich denke, Preloading ist ein sehr neues Feature, um seine Unterstützung sofort im Composer zu implementieren.
Die Anpassung von Anwendungen und Frameworks für das Vorladen sollte die besten Lösungen, fehlende Funktionalität usw. identifizieren.

Ich habe versucht, das gesamte Framework (ZendFramework) vorzuladen und anwendungsspezifisches Vorladen (die Liste der verwendeten PHP-Skripte über opcache_get_status() abzurufen und eine Liste mit opcache_compile_file(...) zu generieren). Der zweite Ansatz funktioniert besser.

Lesen Sie mehr über die Verwendung von Java Class Data Sharing. Wir haben eine ähnliche Technologie implementiert und können Anwendungsfälle ausleihen.

Ich habe versucht, das gesamte Framework (ZendFramework) vorzuladen und anwendungsspezifisches Vorladen (die Liste der verwendeten PHP-Skripte über opcache_get_status() abzurufen und eine Liste mit opcache_compile_file(...) zu generieren). Der zweite Ansatz funktioniert besser.

Danke fürs Einspringen, @dstogov!

Könnten Sie bitte erklären, was Sie mit besser funktionieren meinen? Haben Sie eine bessere Leistung erzielt? Hat das Vorladen aller Klassen zu viel Speicher beansprucht? Hatten Sie ein Problem?

@dstogov Können Sie die obige Frage zur Speichernutzung einer vorinstallierten Klasse klären? Das heißt, wenn ich 100 Klassen habe, die sowieso für praktisch jede Anforderung verwendet werden, und ich sie dann alle vorab lade, wissen wir, dass dies CPU-Zeit spart. Wird es jedoch steigen, sinken oder hat es keine Auswirkungen auf die Speichernutzung?

Wenn wir 10 MB Code vorab laden, der nur für einen kleinen Bruchteil der Anfragen verwendet wird, und es 10 gleichzeitige Anfragen gibt, haben wir jetzt die Gesamtspeichernutzung um 10 MB (gemeinsamer Speicher) oder 100 MB (Kosten in jedem Prozess) erhöht )?

@BenMorel Das Beispiel von Platform.sh ist überhaupt keine Klasse. Es ist eine Datei, die ungefähr so ​​​​aussieht:

<?php

function stuff() {
  $_ENV['db_name'] = $_ENV['dbname'];
}

stuff();

(Weil die Anwendung eine Umgebungsvariable mit einem Namen benötigt und unser System standardmäßig einen anderen bereitstellt. Dies ist ein sehr stark vereinfachtes Beispiel, aber es vermittelt die Idee.)

Diese Datei wird dann von Composer eingebunden, sodass sie während des automatischen Ladens ausgeführt wird, bevor die Anwendung nach ihren Umgebungsvariablen sucht. An diesem Ansatz ist an sich nichts auszusetzen und er funktioniert im Moment ziemlich gut. Mein Punkt ist, dass eine solche Datei NICHT vorab geladen werden darf, da sie dann bei nachfolgenden Anforderungen nicht ausgeführt wird und die Anwendung unterbricht. Wir müssen hier nichts Besonderes dafür tun, außer sicherzustellen, dass es nicht versehentlich von dem Mechanismus aufgenommen und vorgeladen wird, den Composer letztendlich verwendet.

@Crell Das Vorabladen einer solchen Datei hätte keine Auswirkungen, wie ich es verstehe. Da es keine vorladbare Klasse deklariert, wird es ignoriert und bei Einbeziehung zur Laufzeit ausgeführt.

@Crell OK, ich sehe, woher du kommst. Ich habe selbst ähnliche Konfigurationsdateien, aber ich verlasse mich nicht darauf, dass Composer sie einbindet. Stattdessen füge ich solche Dateien manuell in eine Bootstrap-Klasse ein, dh ich rufe Bootstrap::bootstrap() oben im Eingabeskript auf.

Ich denke jedoch, @Seldaek hat Recht, das opcache_compile_file() sollte nichts bewirken , da keine Klasse deklariert wird. Es sollte weiterhin zur Laufzeit ausgeführt werden, wenn Sie wie gewohnt vendor/autoload.php einbinden.

Mein oben vorgeschlagener Ansatz sollte also nicht Ihre derzeitige Arbeitsweise beeinträchtigen: Sie sollten in der Lage sein, Ihre php.ini auf vendor/preload.php und trotzdem vendor/autoload.php in Ihren Code aufzunehmen; alles sollte wie bisher funktionieren.

Zu bestätigen durch @dstogov oder durch Testen der aktuellen Implementierung.

Ich habe versucht, das gesamte Framework (ZendFramework) vorzuladen und anwendungsspezifisches Vorladen (die Liste der verwendeten PHP-Skripte über opcache_get_status() abzurufen und eine Liste mit opcache_compile_file(...) zu generieren). Der zweite Ansatz funktioniert besser.

Danke fürs Einspringen, @dstogov!

Könnten Sie bitte erklären, was Sie mit besser funktionieren meinen? Haben Sie eine bessere Leistung erzielt?

Jawohl. Wenn Sie das Vorladen für die Anwendung optimieren, erzielen Sie eine bessere Leistung.

Hat das Vorladen aller Klassen zu viel Speicher beansprucht?

Heutzutage sind 100 MB oder 1 GB Arbeitsspeicher kein Problem, insbesondere wenn er von allen Arbeitern geteilt wird, aber je mehr Speicher die App nutzt, desto mehr CPU-Cache-Fehlschläge bekommen wir und die Leistung wird schlechter.

Hatten Sie ein Problem?

Preloading, funktioniert nicht mit allen Apps out of the box. Zum Beispiel enthält Wordpress einige Dateien, abhängig vom Ergebnis der Prüfung function_exists("foo"), aber wenn "foo" vorgeladen ist, werden diese Dateien nicht eingeschlossen (nicht ausgeführt) und Wordpress schlägt fehl.

@dstogov Können Sie die obige Frage zur Speichernutzung einer vorinstallierten Klasse klären? Das heißt, wenn ich 100 Klassen habe, die sowieso für praktisch jede Anforderung verwendet werden, und ich sie dann alle vorab lade, wissen wir, dass dies CPU-Zeit spart. Wird es jedoch steigen, sinken oder hat es keine Auswirkungen auf die Speichernutzung?

Höchstwahrscheinlich werden Sie eine deutliche Verbesserung der Speichernutzung erzielen. In jedem Fall werden alle angeforderten Klassen im Shared Memory gespeichert, aber ohne Vorladen werden sie normalerweise im "unlinked state" gespeichert. Bei jeder Anfrage werden sie teilweise in jeden Prozessspeicher kopiert und mit Parent, Interfaces und Traits verknüpft. Beim Preloading sollten die meisten Klassen bereits im verknüpften Zustand im Shared Memory gespeichert sein und werden überhaupt nicht in den Prozessspeicher kopiert.

Jawohl. Wenn Sie das Vorladen für die Anwendung optimieren, erzielen Sie eine bessere Leistung.

Heutzutage sind 100 MB oder 1 GB Arbeitsspeicher kein Problem, insbesondere wenn er von allen Arbeitern geteilt wird, aber je mehr Speicher die App nutzt, desto mehr CPU-Cache-Fehlschläge bekommen wir und die Leistung wird schlechter.

Bedeutet das, dass das Vorabladen aller Klassen eines Projekts im Gegensatz zum Vorabladen, sagen wir die 90 % der am häufigsten verwendeten Klassen, zu einem messbaren Leistungsabfall führt?

Höchstwahrscheinlich werden Sie eine deutliche Verbesserung der Speichernutzung erzielen. In jedem Fall werden alle angeforderten Klassen im Shared Memory gespeichert, aber ohne Vorladen werden sie normalerweise im "unlinked state" gespeichert. Bei jeder Anfrage werden sie teilweise in jeden Prozessspeicher kopiert und mit Parent, Interfaces und Traits verknüpft. Beim Preloading sollten die meisten Klassen bereits im verknüpften Zustand im Shared Memory gespeichert sein und werden überhaupt nicht in den Prozessspeicher kopiert.

Dies sind gute Nachrichten für diejenigen, die befürchten, dass das Vorladen des Ganzen mehr Speicher verbrauchen würde. Es kann sogar die Speicherauslastung unter hoher Last

Für mich hört es sich also so an, als ob die Faustregel "so viel wie möglich vorladen wird, solange Sie nicht so viel vorladen, dass Sie am Ende den CPU-Cache zerstören. Herausfinden, was diese Zeile ist, na ja, das ist Ihre" Problem für Ihre App/CPU; es gibt keine allgemeine Antwort."

Ist das bisher eine faire Zusammenfassung?

Auf jeden Fall glaube ich nicht, dass Composer dieses Problem für jeden einzelnen Anwendungsfall lösen kann, und dennoch denke, dass es ein preload.php-Skript bereitstellen sollte, das alles vorlädt (App- und Herstellerabhängigkeiten).

Auch hier steht es Ihnen frei, es zu verwenden oder nicht: Wenn Sie wissen, wie Sie das Vorladen Ihrer App besser optimieren können, dann verwenden Sie nicht vendor/preload.php ! Das ist kein Grund, warum Composer nicht standardmäßig eine generieren sollte.

Außerdem, @dstogov , denke ich, dass das Vorladen aller Dateien kaum langsamer sein kann als das Vorladen von nichts , oder? Wenn ja, dann haben wir in so ziemlich jedem Fall etwas von diesem Ansatz, und das ohne Konfiguration.

@BenMorel – sagen Sie mir, was ist der Zweck des Ladens aller angegebenen Klassen für eine bestimmte Bibliothek? Wenn ich beispielsweise Guzzle in einem einfachen Bot-Projekt verwende, muss ich nur eine POST-Anfrage ausführen und das ist alles. Was bringt es, alle verfügbaren Paketklassen vorab zu laden, wenn ich vielleicht 10 % seiner Leistung verbrauche? Wie soll der Komponist vorhersagen, welche Klassen aufgewärmt werden müssen?

@er1z

Wie soll der Komponist vorhersagen, welche Klassen aufgewärmt werden müssen?

Es kann nicht. Genau deshalb plädiere ich dafür, dass Composer einen Catch-All-Preloader generiert. Ich bin zuversichtlich, dass es schneller sein sollte, als das Vorladen nicht zu verwenden (es sei denn, ein Benchmark beweist natürlich, dass ich falsch liege).

Wenn Sie wissen, wie Sie Ihr Preloading optimieren können (zum Beispiel mit dem oben von vorgeschlagenen Ansatz : " Getting the list of used PHP scripts through opcache_get_status() and Generating a list of opcache_compile_file(...)" ), dann sind Sie Es steht Ihnen frei, die von Composer angebotene Datei preload.php nicht zu verwenden und einen alternativen Ansatz zu verwenden.

Jetzt sehe ich den Ansatz "Alles vorab laden" nur als Standard: Nichts hindert Composer daran, anzugeben, welche Abhängigkeiten oder Verzeichnisse vorab geladen werden sollen!

Warum also Ressourcen verschwenden, indem alles vorab aus dem Paket geladen wird?

@ er1z Um es zu wiederholen: das wäre nur ein optionaler Standard sein: Wenn Sie Ihre Anwendung mit Null - Konfiguration beschleunigen wollen, dann können Sie den Standard preload.php - Datei, die als nichts besser ist , verwenden, ist es nicht?

Wenn Sie wissen, welche Klassen/Abhängigkeiten Sie am häufigsten verwenden, können Sie Composer anweisen, nur diese vorab zu laden, falls Composer eine solche Konfigurationsoption bietet.

Wenn Sie tatsächlich ein Profil für Ihre Anwendung erstellen und ein vorab geladenes PHP-Skript aus opcache_get_status() generieren können, dann tun Sie dies. Ich denke, ein Skript von Drittanbietern, das dies tut, wäre schön, aber ich glaube nicht, dass dies dem Komponisten gehört.

Wenn Sie den Standard-Preloader nicht verwenden möchten, tun Sie es nicht. Natürlich wird durch die Verwendung eines nicht optimierten Preloaders eine gewisse Speicherverschwendung (und möglicherweise ein paar CPU-Zyklen) verursacht, aber wenn das Endergebnis sowieso eine bessere Leistung und weniger Speicher pro Anforderung ist, warum nicht?

Ich habe einen Benchmark mit einem mittelgroßen Projekt von mir (90 Paketabhängigkeiten) durchgeführt, das bei jeder Anfrage ein ziemlich umfangreiches Bootstrap-Skript enthält, das Klassen für die Abhängigkeitsinjektion einrichtet; Dies macht es zu einem guten Kandidaten für das Benchmarking der Klassenbelastung unter realen Bedingungen.

Ich habe eine einfache Seite der Website einem Benchmarking unterzogen, die die Datenbank sehr wenig nutzt, aber allein das automatische Laden von 380 Klassen auslöst. Ich habe folgende Konfigurationen getestet:

Kein Vorspannen

Ich habe den optimierten Autoloader von Composer verwendet: composer install --optimize-autoloader . Der Opcache wurde durch manuelles Laden der Seite aufgewärmt.

Nur "heiße" Klassen vorladen

Ich habe den Server neu gestartet, genügend Seiten von der Website geladen und dann dieses Skript verwendet, um eine Preload-Datei aus zwischengespeicherten Dateien zu generieren, wie von opcache berichtet:

<?php

header('Content-Type: text/plain');

echo '<?php', PHP_EOL;

$status = opcache_get_status(true);

foreach ($status['scripts'] as $script) {
        $path = $script['full_path'];
        echo 'opcache_compile_file(', var_export($path, true), ');', PHP_EOL;
}

Dieses Skript lädt 878 Dateien vorab.

Alle Klassen vorladen

Ich habe das folgende Preload-Skript verwendet, das die gesamte Composer Classmap vorlädt:

<?php

$files = require 'vendor/composer/autoload_classmap.php';

foreach (array_unique($files) as $file) {
    opcache_compile_file($file);
}

Dieses Skript lädt 14.541 Dateien vorab .

Ergebnisse

| Benchmark | Vorinstallierte Dateien | Startzeit des Servers | Verwendeter Opcache-Speicher | Pro Anfrage verwendeter Speicher | Anfragen pro Sekunde |
| --- | --- | --- | --- | --- | --- |
| Keine Vorspannung | 0 | 0,06 s | 16 MB nach dem Aufwärmen | 1,825 KB | 596 rq/s |
| Heiße Klassen vorladen | 878 | 0,26 s | 21 MB | 869 KB | 695 rq/s |
| Alles vorladen | 14541 | 1,56 s | 105 MB | 881 KB | 675 rq/s |

Wir können interessante Leistungsvorteile sehen, wenn wir das Vorladen verwenden:

  • + 13% wenn alles vorgeladen wird
  • + 16% wenn nur heiße Klassen vorab geladen werden

Wie von @dstogov vorhergesagt, ist die Ausführung etwas schneller, wenn nur die von einem bestimmten Projekt verwendeten Klassen

Die Startzeit des Servers ist für mich kein Thema, und der Overhead für das Vorladen von allem im Vergleich zum Vorladen von heißen Klassen beträgt hier nur 84 MB, also auf moderner Hardware vernachlässigbar.

Interessant ist auch, dass die Verwendung von Preloading (alles oder nur heiße Klassen, egal) den Speicherverbrauch pro Anfrage halbiert !

Einpacken

  • alles vorzuladen ist keine große Sache und kann ohne Konfiguration durchgeführt werden;
  • Nur heiße Klassen vorab zu laden ist etwas optimierter und es lohnt sich, wenn Sie sich die Zeit nehmen können, Ihren Opcache so weit aufzuwärmen, dass er so viele Klassen wie möglich abdeckt, bevor Sie das Preloader-Generatorskript ausführen.

Wenn ich mir die obigen Skripte anschaue, sind


Benchmark-Informationen:

  • VM mit 4 Kernen, 4GB RAM auf meinem i7 Laptop mit NVMe SSD
  • Fedora 29, neuestes PHP master aus Quellcode kompiliert
  • Apache + PHP-FPM
  • opcache.memory_consumption=1000
  • opcache.max_accelerated_files=20000

Benchmarks wurden mit Apache Bench ausgeführt, 1000 Anfragen mit 10 gleichzeitigen Anfragen. Alle Benchmarks wurden 50 Mal durchlaufen und das beste Ergebnis wurde verwendet.

Diese Ergebnisse sehen fantastisch aus.

Ich denke, dass native Composer-Unterstützung sinnvoll ist (habe schon vermutet, dass es in meinen ZendCon- und PHP-Ruhr-Präsentationen eine geben würde, die dies behandelt!), aber es gibt einige Dinge zu berücksichtigen:

  1. Dies ist wirklich nur im Fall eines Single-App-per-Server-Szenarios geeignet, da verschiedene Apps mit widersprüchlichen Abhängigkeiten aneinanderstoßen können - etwas, worüber Sie sich in der Regel ohne Vorladen keine Gedanken machen müssen. Ich glaube nicht, dass Composer jemals die php.ini berührt, daher sollte dies kein Problem sein - da der letzte Schritt, die Datei preload.php tatsächlich explizit in die php.ini zu platzieren, ein manueller Schritt wäre, den der Benutzer ausführen müsste proaktiv tun, aber wenn Composer jemals die php.ini aktualisiert, sollte es unter keinen Umständen automatisch das Vorladen aktivieren.

  2. Wie Dmitry erwähnte, gibt es Codemuster, die sich beim Vorladen anders verhalten können - bisher haben wir function_exists() erkannt, und es kann andere reflexionsbasierte Codemuster geben, die je nachdem, was geladen wird und was nicht, unterschiedlich ausgeführt werden am Ende anders ausgeführt werden, wenn vorgeladen vs. nicht.

Alles in allem, wenn Composer einfach ein Preload-Skript bereitstellt, das einfach alle relevanten Klassen aus Bequemlichkeit vorlädt - und der Benutzer den Auslöser für die tatsächliche Verwendung drücken soll - würde das meiner Meinung nach die Aufgabe gut erfüllen. Es wäre wahrscheinlich eine gute Idee, einige Kommentare am Anfang dieser Datei einzufügen (wie man sie einrichtet, die Tatsache, dass sie für PHP >7.4 ist, Vorsichtsmaßnahmen usw.).

Übrigens, beim Benchmark würde ich empfehlen, es über einen etwas längeren Zeitraum zu betreiben. Wenn ich die Statistiken richtig verstehe, liefen die Benchmarks etwas mehr als eine Sekunde lang (1000 Anfragen mit etwa 700 Anforderungen/Sek.), was normalerweise zu nicht so stabilen Ergebnissen führen kann. Führen Sie vielleicht "-t 10" aus, um zu sehen, wie viele Anfragen in 10 Sekunden gequetscht werden.

Vielen Dank!

@BenMorel danke für die Benchmarks! Sie sollten jedoch nicht composer install --optimize-autoloader ausführen, sondern composer install --optimize-autoloader --no-dev . Andernfalls werden Sie auch alle require-dev Autoload-Dateien vorladen 😄 Ihr Benchmark sollte also dort aktualisiert werden.

Eine andere Sache, die ich zu kommentieren wollte: Speicherverbrauch - Das Vorladen von Dateien verbraucht tatsächlich nicht wesentlich mehr gemeinsam genutzten Speicher, als es dauern würde, um sie regelmäßig einzuschließen () / zu erfordern () und sie im Opcache zu speichern. Es wird etwas länger dauern – da wir in einigen Fällen in dieser Phase etwas mehr Abhängigkeiten zwischen den Klassen auflösen und die Metadaten im Shared Memory speichern könnten – aber dies sollte vernachlässigbar sein, da die Hauptkonsumenten des Shared Memorys sind die eigentlichen Opcodes (Bytecodes). Und das ist natürlich gut angelegter Shared-Memory, da er später während der Laufzeit der Anfrage sowohl Zeit als auch Speicher pro Prozess spart.

Da die meisten Apps locker in mehrere Dutzend oder Hunderte von Megabyte passen - was serverweit wirklich nichts ist (alles wird geteilt) und da der Speicherverbrauch pro Prozess deutlich sinkt (und das ist eigentlich viel wichtiger, da es führt zu Dingen wie Speicherfragmentierung) - Ich würde denken, dass es besser ist, zu viel vorzuladen, als zu wenig vorzuladen.

Vielleicht gibt es eine Überprüfung, die den Benutzer warnt, falls die Größe des gemeinsam genutzten Speichers des Opcaches für die Menge der vorgeladenen Dateien nicht ausreicht? Dies kann wahrscheinlich in der automatisch generierten Datei preload.php implementiert werden, zusammen mit einer Empfehlung, wie es behoben werden kann - was in den meisten Fällen sehr einfach und billig sein sollte.

Mein 2c.

UPDATE: Dmitry hat diese Prüfung und Nachricht bereits hinzugefügt, falls der Opcache nicht mehr genügend Speicher / Dateien hat, direkt in die Preloading-Implementierung. Die Userland-Implementierung kann also naiv sein und einfach versuchen, alles zu laden.

Diese Ergebnisse sehen fantastisch aus.

Sie tun es, und selbst ohne Vorladen ist es angesichts des Arbeitsaufwands (380 geladene und verknüpfte Klassen in Echtzeit + Ausführen des eigentlichen Codes) unglaublich, 600 Anforderungen/s auf handelsüblicher Hardware zu erreichen! Das Vorladen ist das Sahnehäubchen (bevor wir JIT bekommen 😉)!

Alles in allem, wenn Composer einfach ein Preload-Skript bereitstellt, das einfach alle relevanten Klassen aus Bequemlichkeit vorlädt - und der Benutzer den Auslöser für die tatsächliche Verwendung drücken soll - würde das meiner Meinung nach die Aufgabe gut erfüllen.

Dafür plädiere ich bisher, aber ich denke, wir brauchten einen Maßstab, um überzeugt zu sein! Wie auch immer, es steht dem Endbenutzer frei, diese Datei in seine php.ini einzubinden oder ein eigenes Preload-Skript auszuführen.

Übrigens, beim Benchmark würde ich empfehlen, es über einen etwas längeren Zeitraum zu betreiben.

Sie sollten jedoch nicht Composer install --optimize-autoloader ausführen, sondern Composer install --optimize-autoloader --no-dev.

Guter Hinweis an euch beide! Ich habe die Benchmarks erneut mit --no-dev und -t 10 . Die Anzahl der Dateien hat sich seltsamerweise nicht viel geändert: bis auf 14096. Hier sind die (noch besseren) Ergebnisse:

| Benchmark | Anfragen pro Sekunde | Differenz |
| --- | --- | --- |
| Keine Vorspannung | 631 rq/s | - |
| Heiße Klassen vorladen | 738 rq/s | +17% |
| Alles vorladen | 712 rq/s | +13% |

Das Diff hat sich allerdings nur um wenige Dezimalstellen verändert!

Vielleicht gibt es eine Überprüfung, die den Benutzer warnt, falls die Größe des gemeinsam genutzten Speichers des Opcaches für die Menge der vorgeladenen Dateien nicht ausreicht?
UPDATE: Dmitry hat diese Prüfung und Nachricht bereits hinzugefügt, falls der Opcache nicht mehr genügend Speicher / Dateien hat, direkt in die Preloading-Implementierung. Die Userland-Implementierung kann also naiv sein und einfach versuchen, alles zu laden.

Genau, hier die Fehlermeldung beim Starten des Servers mit einem zu niedrigen opcache.memory_consumption :

Fatal Error Nicht genügend Shared Memory zum Vorladen!

Genau, hier die Fehlermeldung beim Starten des Servers mit einem zu niedrigen opcache.memory_consumption :

Fatal Error Nicht genügend Shared Memory zum Vorladen!

Es wird von nun an etwas informativer sein und die Leute darauf hinweisen, die opcache.memory_consumption oder opcache.max_accelerated_files (entsprechend) zu erhöhen.

Ich habe ein kleines und sehr rudimentäres Composer-Plugin zusammengestellt, um eine vendor/preload.php Datei aus einem bestimmten Satz von Pfaden zu generieren. Ich freue mich über jedes Feedback, wenn Sie es ausprobieren möchten.

https://github.com/Ayesh/Composer-Preload

Aber wenn die Leistung tatsächlich besser ist, wenn man sich nur die heißen Pfade ansieht (gecachte Skripte mit Opcache nach dem Ausführen mehrerer Anfragen), ist es dann überhaupt sinnvoll, Composer dies zu überlassen? Wie könnte man feststellen, welche Projekte eigentlich „heiß“ sind? Denn wenn ich Guzzle benötige, möchte ich es vielleicht nur bei 1 von 1.000 Anfragen verwenden, daher macht es nicht viel Sinn, es immer vorzuladen. Aber wenn ich es bei jeder einzelnen Anfrage verwende, tut es das..

@barryvdh Ich habe meine Meinung dazu persönlich fasse sie hier zusammen:

  1. Wenn überhaupt, sollte Composer neben autoload.php ein preload.php Skript bereitstellen, das so einfach wäre:

    <?php
    
    $files = require __DIR__ . '/composer/autoload_classmap.php';
    
    foreach (array_unique($files) as $file) {
        opcache_compile_file($file);
    }
    
  2. Ich glaube nicht, dass Composer gute Arbeit beim Generieren eines "optimierten" Preload-Skripts leisten kann, das, wie Sie sagten, die Analyse von Hot Paths in der tatsächlichen Anwendung erfordert.

Zumindest würde Composer etwas mitbringen, das out-of-the-box einen schönen Leistungsschub bieten würde. Wenn die Leute die Leistung noch weiter verbessern möchten (um ein paar %), können sie ein Preload-Skript mit einem Skript wie dem, das ich oben verwendet habe , generieren, aber ich glaube nicht, dass ein solches Skript zu Composer gehört.

Jedenfalls ist es so trivial, dass es mir nichts ausmachen würde, wenn Composer nichts über das Vorladen tun würde.

Wenn ich das Projekt jedoch leiten würde, würde ich immer noch Punkt 1 angehen . Schnell, einfach, effizient genug.

Wie könnte Composer die Anwendung analysieren, um eine Liste mit heißen Klassen zu erhalten? Ich denke, für eine gut gemachte Liste heißer Klassen sollte sie Heuristiken oder etwas so Fortschrittliches durchlaufen, das den Rahmen von Composer selbst sprengen würde. Heiße Klassen variieren von Projekt zu Projekt, und der Entwickler sollte dafür verantwortlich sein.

Ich kann sehen, dass Frameworks wie CakePHP, Laravel, Symfony und andere davon profitieren könnten, da sie Klassen haben, die immer geladen werden und dem Composer eine Liste dieser über ein preload.php anbieten.

Eine andere Lösung wäre, ein Paket zu haben, das vollständig getrennt ist und eine Liste von Klassen identifizieren könnte, die bei der Ausführung eines Skripts getroffen werden, wie während eines standardmäßigen Anforderungs-Antwort-Lebenszyklus, und diese Liste dann stoppen und zurückgeben könnte, damit der Entwickler überlegen kann, welche von allen benötigt wird aufgenommen werden oder nicht.

Abgesehen davon sollte Composer einen Schlüssel anbieten, um das Preloading zu verwalten. Dann könnte der Entwickler entscheiden, das Preload bestimmter Pakete durch das Root composer.json einzuschließen/auszuschließen. Wenn ein Paket also eine riesige Liste von Klassen enthält, die Sie kaum verwenden, können Sie es ausschließen oder überschreiben.

Es wäre auch cool zu prüfen, wie viel Speicher ein Preloading beanspruchen könnte.

Aber wie auch immer, Composer halten sich von der Logik fern, um zu entscheiden, was angesagt ist und was nicht.

Es wäre praktisch, wenn Composer einen Schlüssel enthalten würde, um zu verwalten, wie das Preloading (in der Produktion und in der Entwicklung) integriert wird:

  • Kein Schlüssel oder leerer Schlüssel wäre kein Vorladen.
  • autoload würde einfach alle Autoloading-Klassen vorab laden. Sie können bestimmte Namespaces oder Klassen ausschließen.
  • file würde Preload-Skripte verwenden, die sich irgendwo mit Ihrer eigenen Logik befinden, wie zum Beispiel die Autoloading-Klasse nehmen und bestimmte Klassen entfernen oder einige Ihrer eigenen hinzufügen, was auch immer. Das wird additiv sein, d. h. wenn sich eine Klasse wiederholt, wäre es egal, da der Komponist sie einfach überspringen würde.

Nur das Preload wird von der Wurzel composer.json . Wenn ein Paket den Schlüssel hat, gut für sie.

{
    "preload": "autoload",
    "preload-dev": {
        "files": [
            "my-app/preload.php",
            "heuristic/preload.php"
        ]
    }
}

Der Grund, warum ich dagegen bin, dieses Skript aufzunehmen (coole Idee übrigens), ist die Verwendung von Opcache. Da Composer außerhalb des Anwendungslebenszyklus und von PHP selbst lebt, wird ein Paket benötigt, um durch Analyse ein hilfreiches Preloading zu erstellen.

Da, meine zwei Cent.

Wann wird PHP 7.4 Hotload vollständig unterstützt?

Wie könnte Composer die Anwendung analysieren, um eine Liste mit heißen Klassen zu erhalten?

Auf den meisten Websites ist Opcache aktiviert, der Statistiken über die am häufigsten verwendeten Klassen in der Anwendung führt. Siehe @BenMorel- Skript wie oben.

@zsuraski

Du erwähnst:

Ich würde denken, dass es besser ist, zu viel vorzuspannen, als zu wenig vorzuspannen.

Könnten Sie das näher ausführen? Schlagen Sie vor, dass die Anwendung möglicherweise nicht funktioniert, wenn zu wenig geladen wurde, da Abhängigkeiten/verknüpfte Informationen fehlen?

Da Projekte in der Anzahl der installierten Pakete massiv variieren können, würde ich persönlich entscheiden, standardmäßig nur "heiße" Dateien vorzuladen. Es gibt viele Dateien in Ihrem Projekt, die wahrscheinlich nie berührt werden.

Zum Beispiel haben wir aws-sdk-php installiert, dies wird von league/flysystem-aws-s3-v3 und das Projekt hat über 1000+ PHP-Dateien, die laut meinen Apps nie zwischengespeichert werden (wahrscheinlich, weil wir nur einen winzigen Bruchteil verwenden dieses Pakets und nur während einer wöchentlichen Cron-Aufgabe).

Ich persönlich bin nicht für diesen "blinden" Ansatz, alles in vendor vorab zu laden, es scheint eine schlechte Gesamtstrategie zu sein, besonders wenn die Analysen darauf hindeuten, dass Hot Loading insgesamt effizienter ist.

Wie könnte Composer die Anwendung analysieren, um eine Liste mit heißen Klassen zu erhalten?

Auf den meisten Websites ist Opcache aktiviert, der Statistiken über die am häufigsten verwendeten Klassen in der Anwendung führt. Siehe @BenMorel- Skript wie oben.

@zsuraski

Du erwähnst:

Ich würde denken, dass es besser ist, zu viel vorzuspannen, als zu wenig vorzuspannen.

Könnten Sie das näher ausführen? Schlagen Sie vor, dass die Anwendung möglicherweise nicht funktioniert, wenn zu wenig geladen wurde, da Abhängigkeiten/verknüpfte Informationen fehlen?

Da Projekte in der Anzahl der installierten Pakete massiv variieren können, würde ich persönlich entscheiden, standardmäßig nur "heiße" Dateien vorzuladen. Es gibt viele Dateien in Ihrem Projekt, die wahrscheinlich nie berührt werden.

Zum Beispiel haben wir aws-sdk-php installiert, dies wird von league/flysystem-aws-s3-v3 und das Projekt hat über 1000+ PHP-Dateien, die laut meinen Apps nie zwischengespeichert werden (wahrscheinlich, weil wir nur einen winzigen Bruchteil verwenden dieses Pakets und nur während einer wöchentlichen Cron-Aufgabe).

Ich persönlich bin nicht für diesen "blinden" Ansatz, alles in vendor vorab zu laden, es scheint eine schlechte Gesamtstrategie zu sein, besonders wenn die Analysen darauf hindeuten, dass Hot Loading insgesamt effizienter ist.

Ich schaue mir immer Pakete und Funktionen an, die zwei Konfigurationsmöglichkeiten haben: manuell und manuell.

Den Analysen nach zu urteilen, sollte Composer die am häufigsten verwendeten Klassen in der Anwendung nehmen und sie bis zu einem bestimmten MB-Schwellenwert vorladen lassen (32~128 MB scheinen standardmäßig gut für eine Standardanwendung zu sein). Die Priorität der Klassen wären diejenigen mit mehr Treffern, und diese weniger Treffer werden weggelassen.

Im manuellen Modus sollte Composer jedoch ein Skript erhalten, das ein Array von Klassen oder Namespaces zum Vorabladen zurückgibt.

Letzteres könnte auch in Produktionsumgebungen gut sein, da Sie eine vordefinierte Liste von Klassen und Namespaces verwenden könnten, um die Leistung zu testen.

Nach allem, was ich sehe, hat der Opcache separate Caches und Statistiken für fpm und cli, was dazu führt, dass erzwungenes Vorladen, Statistiken oder Bereinigungsaktionen in einem Web-App-Kontext wahrscheinlich nicht den gleichen Effekt haben. Ich habe an der gleichen Funktion in meinem Composer-Preload-Plugin gearbeitet, aber ich konnte nicht herausfinden, wie ich die separaten Bins, die Opcache für fpm und cli hat, umgehen kann.

Nun, das vereitelt seinen Zweck, bis es keinen "Zugang" zum FPM gibt
Analytics, zumindest nicht direkt.

Dann wäre die einzige "gesunde" Option ein Paket mit einer Klasse, die
könnte regelmäßig eine Liste von Trefferklassen aktualisieren, während die Anwendung ausgeführt wird
in FPM, hoffentlich am Ende des Anforderungslebenszyklus (wie 1 von 20, das
einstellbar sein). Es würde Overhead hinzufügen, aber es wäre minimal. Es
würde eine preload-ready-Klassenliste mit den meisten Treffern schreiben.

Drehen Sie dann FPM herunter und verwenden Sie dann die Klassenliste, um opcache anzuweisen, die vorab zu laden
aufführen.

Es wäre cool, wenn opcache einige Analysen zu jeder Klasse liefern könnte
Speicherauslastung der Instanz, so dass die Liste weniger verwendet werden kann
Klassen außerhalb einer bestimmten Speichergrenze jedes Mal manipuliert wird.

El mié., 10. Juli. de 2019 23:01, Ayesh Karunaratne <
[email protected]> escribió:

Soweit ich das sehe, hat der Opcache separate Caches und Statistiken für fpm
und cli, die erzwungenes Vorladen, Statistiken oder Bereinigungsaktionen durchführen
wird wahrscheinlich nicht den gleichen Effekt in einem Web-App-Kontext haben. Ich habe daran gearbeitet
dieselbe Funktion in meinem Composer-Preload-Plugin, aber ich konnte es nicht herausfinden
wie man die separaten Bins umgeht, die Opcache für fpm und cli hat.


Sie erhalten dies, weil Sie einen Kommentar abgegeben haben.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/composer/composer/issues/7777?email_source=notifications&email_token=ABHHLF2TZ5XBBRVDFEM2YRTP62PA3A5CNFSM4GCIOG4KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKT-JP309commentGO
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/ABHHLFYFXT5JWK4NFTVLPA3P62PA3ANCNFSM4GCIOG4A
.

Hat jemand den Speicherverbrauch auf eingebetteten Systemen in Betracht gezogen, bei denen Sie tatsächlich keine Gigs und Gigs an RAM zur Verfügung haben? Wenn ich einen kleinen Webserver auf einem System hosten möchte, das eine riesige Menge von 64 Megabyte RAM bietet, kann ich etwa ein Dutzend Dateien vorladen und PHP wird scheißen, wenn Composer entschieden hat, dass "All in" die beste Vorladestrategie insgesamt ist ?

(Etwas übertriebenes Beispiel, ja.)

Ich würde sagen, dass es die beste Option ist, ein Preload-Skript nur aus der Definition des Root-Projekts Composer.json und nur mit benutzerdefinierten Dateien zu generieren, wenn Composer überhaupt für die Generierung von Preload-Dateien verwendet werden soll.

Das Vorladen sollte standardmäßig deaktiviert sein und das Vorladen einer benutzerdefinierten Liste zulassen.
Auf diese Weise würde es keine Probleme mit der RAM-Verwaltung in jedem Gerät geben.

El. März, 16. Juli de 2019 09:07, Otto Rask [email protected]
Beschreibung:

Hat jemand über die Speichernutzung auf eingebetteten Systemen nachgedacht, in denen Sie
haben eigentlich keine Gigs und Gigs RAM zur Verfügung? Wenn ich ein hosten möchte
kleiner Webserver auf einem System, der eine riesige Menge von 64 . bietet
Megabyte RAM, ich kann wie ein Dutzend Dateien vorladen und PHP wird scheißen, wenn
Der Komponist hat entschieden, dass "all in" die beste Vorladestrategie insgesamt ist?

(Etwas übertriebenes Beispiel, ja.)

Ich würde sagen, dass ein Preload-Skript nur aus dem Root-Projekt generiert wird
Composer.json-Definition, und nur mit benutzerdefinierten Dateien ist die beste
Option, wenn Composer überhaupt für die Generierung von Preload-Dateien verwendet werden soll.


Sie erhalten dies, weil Sie einen Kommentar abgegeben haben.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/composer/composer/issues/7777?email_source=notifications&email_token=ABHHLFYUNB4IWBKM63AFUPTP7XBZJA5CNFSM4GCIOG4KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJ2KTDN5WW#VMVBW63LNMVXHJ2KTDN5WW#
oder den Thread stumm schalten
https://github.com/notifications/unsubscribe-auth/ABHHLF3UJX75LEGC7N4IGLLP7XBZJANCNFSM4GCIOG4A
.

Leute, das Vorladen erfordert eine INI-Einstellung, damit Composer euch auch nicht in den Rücken sticht, keine Sorge ;-)

Ich bin sehr skeptisch, dass Composer der richtige Ort ist, um eine Hot-Path-Analyse durchzuführen, um den optimalen Satz von Dateien zum Vorladen zu bestimmen. Das Aktivieren von Preload erfordert eine ini-Einstellung, wie @BenMorel bemerkt, also könnte Composer wirklich nur ein Skript generieren, das alles vorlädt (was Sie dann verwenden können oder nicht) oder Bibliotheken erlauben, "diese Dateien

Alles, was komplexer wäre, würde meiner Meinung nach für Composer selbst nicht in Frage kommen. (Vielleicht eine Erweiterung?) Geben wir den armen Jordi und Nils nicht die Aufgabe, automatisches maschinelles Lernen zu implementieren, k? :Lächeln:

Ich bin sehr skeptisch, dass Composer der richtige Ort ist, um eine Hot-Path-Analyse durchzuführen, um den optimalen Satz von Dateien zum Vorladen zu bestimmen. Das Aktivieren von Preload erfordert eine ini-Einstellung, wie @BenMorel bemerkt, also könnte Composer wirklich nur ein Skript generieren, das alles vorlädt (was Sie dann verwenden können oder nicht) oder Bibliotheken erlauben, "diese Dateien

Alles, was komplexer wäre, würde meiner Meinung nach für Composer selbst nicht in Frage kommen. (Vielleicht eine Erweiterung?) Geben wir den armen Jordi und Nils nicht die Aufgabe, automatisches maschinelles Lernen zu implementieren, k? 😄

In diesem Fall sollte es kein Problem sein, ein composer preload hinzuzufügen, um eine Liste zu generieren, die als preload.php . Bibliotheken könnten deklarieren, welche Dateien unter einem Schlüssel als "vorladbar" deklariert werden sollen.

{
    "preload": {
        "psr-4": [
            "ServerUtils\\PingTools\\",
            "ServerUtils\\TracertManager"
        ],
        "files": [
            "helpers.php"
        ]
    }
}

Wenn eine Bibliothek nicht vorab geladen werden kann, kann der Entwickler eine Bibliothek mit den Projektstämmen composer.json zur automatisch generierten Liste "hinzufügen":

{
    "preload": {
        "psr-4": [
            "OldPackageNotPreloaded\\",
            "OtherNotPreloaded\\CommonClass"
        ],
        "files": [
            "my-app-helpers.php"
        ]
    }
}

Der Entwickler kann diese Liste für einen Schnellstart für die Entwicklung verwenden, da das Vorladen von Herstellerdateien nicht riskant sein sollte, da sich diese nicht ändern. In der Produktion sollte der Entwickler OPCache um Analysen bitten und die leistungsstärkste Liste der Klassen für seine Anwendung vorab laden.

Sollte das reichen? Composer wird nur helfen, eine vorläufige Preload-Liste zu erstellen, aber die endgültige Entscheidung liegt noch in der Hand der Entwickler.

@DarkGhostHunter Wie bereits mehrfach in diesem Thread erwähnt,

Ich stimme auch dem zu, was @Crell darüber gesagt hat, den Composer dazu zu bringen, die Autoload-Dateien zu bestimmen. Dies kann die Komplexität von Composer leicht erhöhen und sollte nicht Teil eines Abhängigkeitsmanagers sein.

Das Plugin, das ich schamlos selbst gesteckt habe, versucht auch, eine preload.php Datei basierend auf den composer.json Anweisungen zu generieren. Mit den aktuellen Beschränkungen der Opcache-Statistiken glaube ich, dass es nicht einmal möglich ist, Opcache-Dateien über verschiedene SAPIs hinweg zuverlässig aufzulisten und zu statisieren ( cli bis fpm , etc).

@DarkGhostHunter Wie bereits mehrfach in diesem Thread erwähnt,

Auf einer Entwicklungsmaschine könnte es funktionieren, da es keine hohen RAM-Einschränkungen wie bei einer Produktionsmaschine gibt.

Ich mag die Idee des composer.json Preloading-Vorschlags sehr, da er es dem Paketentwickler ermöglicht, anzugeben, welche Klassen oder Dateien vorab geladen werden sollen. Sinn macht es aber nur für kleine Pakete, die Entwickler für sich selbst und ihr aktuelles Projekt und Anwendungsfall schreiben, nicht für Frameworks wie Symfony, TYPO3, Drupal oder Laravel, die nicht wissen können, was der Entwickler, der das Framework nutzt, von seinem Framework tatsächlich nutzt.

Für mich wäre es am sinnvollsten, ein PHP-Paket zu entwickeln, um die Codebasis Ihres Projekts zu analysieren und die preload.php entsprechend zu generieren. Dies könnte ein Composer-Plugin sein (oder vielleicht etwas anderes, das dann in ein Composer-Plugin integriert wird), das eine beliebige Anzahl von Ordnern benötigt, um alle verwendeten Klassen zu überprüfen und zu versuchen, alle verwendeten Klassen aufzulösen und die Datei entsprechend generiert.

Diese Lösung müsste sich jedoch auf den Composer und den Autoloader verlassen, da es keinen Sinn macht, einen Autoloader nur für diesen Anwendungsfall neu zu schreiben.

Dies wäre für Entwickler praktisch, da sie sich nicht darum kümmern müssten, was sie tatsächlich bereitstellen müssten (und meiner Meinung nach ist es immer großartig, sich nicht um Dinge kümmern zu müssen).

Irgendwelche Gedanken?

BEARBEITEN: Ich mache mir auch ein bisschen Sorgen um das ganze Preloading-Zeug, da das Neustarten meines php-fpm Dienstes Ausfallzeiten bedeutet, die in einigen Fällen möglicherweise nicht akzeptabel sind (auch wenn wir über 0,26-1,5 Sekunden sprechen).

@CDRO Vielleicht wird es mit der Zeit geändert und Sie müssen nur php-fpm neu laden und nicht neu starten (damit werden vorhandene Anforderungen nicht beendet). Auf der anderen Seite, wenn Sie 0.26-1.5 secs nicht akzeptieren, sollten Sie wahrscheinlich bereits HA (mehrere Server-Setup) haben, mit dem Sie ein Mitglied aus dem Pool entfernen, PHP neu starten und erneut Mitglied hinzufügen können, und dann ist da keine Ausfallzeiten.

Ich dachte, das FPM-Neuladen war ein ordnungsgemäßer Neustart, was bedeutet, dass Arbeiter (die Daten vor dem Laden im Speicher haben) getötet und neu gestartet werden, sobald die aktuelle Anforderung bearbeitet wurde. Neustart würde nur die laufende Anforderung beenden und einen Fehler an den Client zurückgeben.

Wenn ein Reload das tut, was @rask vorschlägt, wäre dies in der Tat perfekt, vielleicht hat @nikic einen besseren Überblick, wenn es so ist, wie wir es erwarten.

@pjona Sie haben Recht, wenn dies ein Problem ist, sollte HA bereits implementiert sein, andererseits kann dies auch mit Bereitstellungsfenstern leicht gelöst werden, bei denen akzeptiert wird, dass die Anwendung für kurze Zeit nicht

Ein FPM-Neuladen löscht den Vorladestatus nicht, Sie benötigen einen vollständigen FPM-Neustart.

@nikic ich

Ich bin mir nicht ganz sicher, ob es möglich ist, eine nützliche Liste von Dingen zu generieren, die ohne Ausführungsstatistiken vorab geladen werden können, es sei denn, der Composer analysiert irgendwie die Codebasis und ihre tatsächlichen Einstiegspunkte, um zu sehen, was tatsächlich verwendet wird und was nicht. Dies ist etwas, wofür ein statischer Analysator wahrscheinlich besser geeignet ist, da einige der erforderlichen Werkzeuge bereits vorhanden sein sollten.

Ich erstelle derzeit die Preload-Datei aus den Opcache-Statistiken der realen Welt, nachdem ich die App, an der ich gerade arbeite, einige Tage in freier Wildbahn ausgeführt habe (wild bedeutet automatisierten Datenverkehr, da sich die App noch in der Entwicklung befindet). Diese Lösung funktioniert und kann möglicherweise bis zu einem gewissen Grad automatisiert werden, aber es wäre jedes Mal ein benutzerdefinierter Job.

Ich bin nicht überzeugt, dass Composer das richtige Werkzeug für diesen speziellen Job ist.

In Bezug auf das Vorladen von allem und die oben genannten Benchmarks wie sie sind, kann der zusätzliche Speicher, der von opcache verwendet wird, sehr problematisch sein, wenn Sie Ihre Apps in sehr promiskuitiven Umgebungen mit sehr engen Speicherbeschränkungen ausführen. Kubernetes zum Beispiel. Jeder einzelne Knoten kann sich magere 4 GB RAM mit 15 oder 20 Pods teilen, wobei die Ressourcengrenzen und Anforderungen eng angepasst wurden.

Ich denke, das ist das Preloading, nach dem wir suchen: Bieten Sie etwas Grundlegendes an, aber lassen Sie den Entwickler es erweitern.

{
  "preload": {
    "entrypoint": "entrypoint.php",
    "script": ["foo.php", "bar.php"],
    "directories": ["examples", "foo/bar"],
    "files": ["helpers.php"],
    "ignore": ["src/foo.php", "src/bar.php"],
}

Dies gibt 100% Flexibilität bei der Vorladung:

  • Benötigen Sie einen Einstiegspunkt in Ihr Projekt? Lassen Sie Composer es erstellen und zeigen Sie es in php.ini .
  • Verwenden Sie ein Skript? Fertig.
  • Einfach alles in einem Verzeichnis? Fertig.
  • Einige Dateien? Fertig.
  • Was kann man zusätzlich zu den hinzugefügten Dateien ignorieren? Fertig.

Der Ablauf

Vorladen bedeutet Bearbeiten von php.ini . Die Prozedur sollte als erster Punkt PHP sein, um den Einstiegspunkt des Projektstamms einzuschließen. Dieser Einstiegspunkt sollte von Composer verwaltet werden. Es verknüpft alle Preloading-Skripte aus Abhängigkeiten (oder baut sie) in eine Datei, die der Einstiegspunkt ist, mit einem Befehl:

composer preload build

Dadurch wird jedes Paket für einen preload Schlüssel durchlaufen und die Skripte, Verzeichnisse und Dateien (und ignorierten Dateien) zu einem kompilierten echten Einstiegspunkt hinzugefügt. Diese werden im Composer-Bootstraping zwischengespeichert.

Ideen?

@DarkGhostHunter Ich bin neu hier und sehe nicht unter die Haube des Komponisten. Aber aus der Sicht eines einfachen Benutzers sieht das für mich gut aus und wie etwas, mit dem ich arbeiten könnte :+1:

@DarkGhostHunter Ich bin neu hier und sehe nicht unter die Haube des Komponisten. Aber aus Sicht eines reinen Benutzers sieht das für mich gut aus und nach etwas, mit dem ich arbeiten könnte 👍

Während mein Vorschlag ein automatisches Vorladen ermöglicht, sind beim Vorladen nur der "heißen" Dateien noch Fortschritte zu erzielen. Es sollte eine Möglichkeit geben, OPCache-Analysen darüber zu speichern, welche Dateien am häufigsten betroffen sind, und einen Teil der Liste basierend auf Speicherbeschränkungen oder Prozentschwellenwerten zu verschieben. Wenn der Komponist einen Teil dieser Arbeit machen könnte, wäre das großartig

Letzteres ist wichtig, da Sie möglicherweise ein Projekt mit 1500 Dateien vorab laden, aber bei 99% der Anfragen mit nur 150 Dateien fast die gleiche Leistung erzielen. Dass Sie 10 weitere PHP-Instanzen statt nur einer instanziieren könnten.

Ich denke, alle sind sich einig, dass der optimale Weg zum Generieren des Preloadings darin besteht, Informationen über Opcache zu sammeln und nur die für das Projekt benötigten Dateien zu laden.

IMHO, da die meisten Projekte, die Composer verwenden, ihre Anwendung wahrscheinlich auf einem Bereitstellungsserver erstellen und dann die App/Website auf den Produktionsserver verschieben, kann composer preload die Opcache-Statistiken nicht verwenden (in diesen Fällen bei am wenigsten).

Aber was wäre, wenn es tatsächlich auf diese Informationen zugreifen könnte?

Ich könnte mir folgende Lösungen zu diesen Problemen vorstellen:

  • entweder ein Composer-Paket erstellen, das die Statistiken irgendwo auf dem Server sammelt und diese Informationen automatisch/manuell auf composer update / composer preload zieht
  • Erstellen Sie einen sicheren Endpunkt, auf den mit einem geheimen Schlüssel zugegriffen werden kann, der nur dem Komponisten bekannt ist und irgendwo in der Datei composer.lock oder composer.json gespeichert ist, der es composer preload ermöglicht, eine Anfrage zu stellen, um die Informationen zum Erstellen des Preload-Skripts zu sammeln

Wäre dies eine praktikable Lösung?

Gerne können Sie die Diskussion hier als zentrale Anlaufstelle für Interessierte zur Abstimmung weiterführen. Aber um es klarzustellen, ich bin ziemlich zuversichtlich, dass wir in naher Zukunft nichts zum Preloading in Composer hinzufügen werden.

Wenn sich in einem Jahr herausstellt - nachdem die Leute damit gespielt haben -, dass es etwas gibt, bei dem Composer einzigartig positioniert ist, um wirklich zu helfen, können wir es noch einmal aufgreifen. Im Moment scheint es mir eher ein Anwendungs-/Bereitstellungsproblem zu sein als ein Abhängigkeitsmanagement.

Ich denke, das Problem hier ist, dass wir versuchen, alles vorab zu laden.

Was wäre, wenn wir stattdessen Paketentwicklern die Verantwortung übertragen würden? Sie können Klassen/Dateien deklarieren, die in der composer.json zwischengespeichert werden müssen.

{
    "preload": [
        "/package/AbstractClassInterface.php",
        "/package/AbstractClass.php",
        "/package/helpers.php",
    ]
}

Für diese Dateien sind Paketentwickler verantwortlich. Sie sollten keine Abhängigkeiten aufweisen (oder diese zumindest in das Preloading einbeziehen). Composer erkennt diese deklarierten Dateien und erstellt automatisch ein Preload-Skript, das wir optional verwenden können.

Das Problem ist nicht alles vorzuladen. Das Problem ist, vorab zu laden, was ist
nützlich und was nicht, etwas, das außerhalb des Umfangs von Composer liegt; ein
Eine gute Preloading-Liste wird von Opcache-Statistiken und einem Speicherlimit erstellt und hat
manuell in die php.ini eingefügt werden.

Allein zu diesem Zweck habe ich ein Paket erstellt, das Ihre am häufigsten angeforderten prüft
Dateien und erstellt eine Liste, die diese zuerst in absteigender Reihenfolge enthält.

Alle Dateien vorab zu laden ist unverantwortlich, wenn man bedenkt, dass danach
An einem bestimmten Punkt wird das Hinzufügen weiterer Dateien zur Preload-Liste marginal sein
Leistung zurückgibt.

El vie., 13 de dic. de 2019 23:53, kapitanluffy [email protected]
Beschreibung:

Ich denke, das Problem hier ist, dass wir versuchen, alles vorab zu laden.

Was ist, wenn Paketentwickler Klassen/Dateien deklarieren können, die sein müssen?
in der Composer.json zwischengespeichert.

{
"vorladen": [
"/package/AbstractClassInterface.php",
"/package/AbstractClass.php",
"/package/helpers.php",
]
}

Für diese Dateien sind Paketentwickler verantwortlich. Sie sollten nicht haben
Abhängigkeiten (oder zumindest in das Preloading einbeziehen). Composer erkennt
diese deklarierten Dateien und erstellen automatisch ein Preload-Skript, das wir können
optional verwenden.


Sie erhalten dies, weil Sie erwähnt wurden.
Antworten Sie direkt auf diese E-Mail und zeigen Sie sie auf GitHub an
https://github.com/composer/composer/issues/7777?email_source=notifications&email_token=ABHHLF6ZSVZNW3DN6N4NYOLQYRDAXA5CNFSM4GCIOG4KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDNPY-5WW#
oder abmelden
https://github.com/notifications/unsubscribe-auth/ABHHLF2GLDG5CBQ7NGUQRK3QYRDAXANCNFSM4GCIOG4A
.

Ich versuche, dies aus einer einfachen Benutzerperspektive zu sehen.

Ich glaube, ich habe alle Kommentare hier durchgelesen. Habe ich etwas übersehen oder wirklich nirgendwo wurde dieses Szenario erwähnt?

Ein Benutzer hostet auf einem gemeinsam genutzten Webhost oder einem Server, über den er nicht viel Kontrolle hat. Und der Benutzer verwendet jede Art von Software, die Composer verwendet. Stellen wir uns vor, in jedem Paket oder auf Root-Ebene ist das Vorladeverhalten definiert. Der Benutzer weiß nicht einmal davon.

Nun, ja, es stimmt, es gibt immer noch den php.ini-Schritt, der verhindert, dass das Preload-Verhalten von PHP versehentlich aktiviert wird (wenn es in Zukunft nicht so etwas wie einen 'Standard-Link' zu Composer/preload.php von PHP selbst gibt, was Toflar schon erwähnt hat).

Aber was ist, wenn ein Benutzer es aktiviert, weil er in irgendeiner Art von Dokumentation davon erfahren hat, aber nicht das vollständige Ergebnis (gut und schlecht) davon kennt?

Wie kann der Benutzer die vorgeladenen Dateien aus seinem Speicher auf seinem gemeinsam genutzten Host holen?

Meiner Meinung nach sollte die Aktivierung des Preloadings dringend auf einem starken Opt-In basieren. Zum Beispiel, indem der erforderliche Code explizit in einem separaten Paket installiert werden muss, was komplizierter ist und „zufällige Aktivierungen“ verhindert. Weder Composer noch ein gepflegtes Paket sollten dies für den Benutzer ohne dessen Bestätigung entscheiden. Ist es nicht?

Dies bedeutet natürlich nicht, dass ein Preloader nicht die vom Composer generierte Klassenzuordnung verwenden sollte.

@NickSdot Sie können Naivität und Verantwortungslosigkeit nicht mit einem Composer-Paket beheben. Ich stimme zu, aber die Technik, um eine optimale Preload-Liste richtig zu erstellen, geht über Composer hinaus .

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen