PHP, YII2 und die Bildung großer Excel-Dateien

Starten Sie


Ein von unserem Unternehmen unterstütztes Buchhaltungs- und Berichtssystem wuchs in Bezug auf die gespeicherte Datenmenge sehr schnell. Das System ist in PHP unter Verwendung des Yii2-Frameworks geschrieben. Anfänglich wurden Berichte über die PhpSpreadsheet-Bibliothek erstellt, die das seit langem veraltete PhpExcel ersetzte.

Unter den verschiedenen Arten der Berichterstellung gab es eine sehr große - tatsächlich sollte der vollständige Satz aller in der Datenbank gespeicherten Daten in eine Excel-Tabelle hochgeladen werden. In der Anfangsphase gab es keine Probleme, aber als das Volumen begann, viele hunderttausende Datensätze zu überschreiten, begann das Skript zum Entladen der Formation zum Zeitlimit zu fallen. Zunächst haben wir diese Grenze angehoben und nach Wegen gesucht, um das Problem zu lösen. Eine vorübergehende Lösung hielt jedoch nicht lange an - das Problem mit dem Zeitlimit wurde zu einem Problem mit dem Speicherlimit. Sie warfen den "RAM" auf den Server und entfernten das memory_limit für diese bestimmte Operation. Sehr bald beschwerten sich Benutzer erneut über Laufzeitfehler. Ich musste das Zeitlimit für den vollständigen Bericht aufheben. Aber ein Dutzend Minuten mit einer Ladeanzeige auf dem Bildschirm zu sitzen und zu schauen, macht nicht viel Spaß. Darüber hinaus wurde manchmal ein Bericht „hier und jetzt“ benötigt, und jede Minute, die für seine Entstehung aufgewendet wurde, erwies sich als kritisch. Die Experimente mit den Umgebungseinstellungen wurden abgebrochen, am Hinterkopf zerkratzt und mit der Optimierung des Codes begonnen.

Suche nach einer Lösung


Als erstes wurde das Berichtsskript in den Hintergrundprozess gestellt und der Benutzer überwacht den Fortschritt über den "Fortschrittsbalken". Die Ausführung von Hintergrundjobs wurde über den Warteschlangenmechanismus unter Verwendung von Redis als Speicher implementiert. Die Arbeit im System wird nicht unterbrochen. Sie können andere Aufgaben ausführen und regelmäßig zur Berichtsseite zurückkehren, um festzustellen, ob die Datei bereit ist. Sobald die Datei erstellt wurde, wird dem Benutzer ein Download-Link angeboten. Wie oben erwähnt, war die Datei jedoch manchmal "sofort" erforderlich, und eine zunehmende Benutzerfreundlichkeit löste dieses Problem nicht. In der Zwischenzeit wuchs die Datenmenge weiter und die Zeit, die zum Erstellen der Datei benötigt wurde, erreichte 79 Minuten! Dies ist völlig inakzeptabel, insbesondere angesichts der Tatsache, dass die Berichterstellung eine der Grundlagen für die Funktionalität dieses Systems darstellt. Nein, alle anderen Teile funktionierten wie am Schnürchen, aber diese Fliege in der Salbe verdarb den Gesamteindruck.

Erste Ergebnisse


Wir setzten uns wieder zur Code-Analyse. Als erstes wurde die Auswahl von Daten aus der Datenbank getestet. Die Abfragen wurden jedoch bereits maximal optimiert. Obwohl die längste Anfrage eine schreckliche Stichprobe mit fünf oder sechs Anrufen beim monströsen FIAS war, funktionierte sie in 2-5 Sekunden. Die Schwachstelle war nicht er, sondern die Bildung der Datei "exelnik". Versuche haben begonnen, diesen Prozess zu optimieren. Angefangen beim Zwischenspeichern in Redis bis hin zu Perversionen wie der Bildung separater kleiner "Excels" in parallelen Streams, gefolgt vom Einfügen in eine Datei. Das Ergebnis war jedoch immer das gleiche: Das Problem im Laufe der Zeit wurde zu einem Problem mit dem Speicher und umgekehrt. Es gab keinen Mittelweg, der nur von einem Extrem zum anderen floss. Nach einer bestimmten Datenmenge begann der Ressourcenverbrauch der Bibliothek exponentiell zu wachsen und es war nicht möglich, ihn zu besiegen. PhpSpreadsheet - nicht für große Dateien geeignet. Infolgedessen wurde beschlossen, die Bibliothek zu ändern. Als Option - Schreiben Sie Ihr eigenes Analogon für die Bildung von Ex-Dateien.

Analyse und Werkzeugauswahl


Sie beeilten sich nicht, Fahrräder zu schreiben, sondern analysierten zunächst vorhandene Lösungen. Von den möglichen Optionen war nur die Box / der Auslauf von Interesse. Schreiben Sie das Modul mithilfe dieser Bibliothek schnell neu. Als Ergebnis wurde ein vollständiger Bericht in 145 Sekunden erhalten. Ich möchte Sie daran erinnern, dass die neuesten Tests mit PhpSpreadsheet 79 Minuten und hier 2,5 Minuten dauern! Durchgeführte Tests: Die Datenmenge wurde um das Zweifache erhöht. Der Bericht wurde in 172 Sekunden erstellt. Der Unterschied ist erstaunlich. Natürlich hat die Bibliothek nicht alle Funktionen wie PhpSpreadsheet, aber in diesem Fall reicht der Mindestsatz an Werkzeugen aus, da die Geschwindigkeit entscheidend ist.

Erweiterung für Yii2


Die endgültige Entscheidung wurde als Erweiterung für Yii2 festgelegt. Vielleicht wird jemand nützlich sein. Mit der Erweiterung können Sie jedes Dataset aus GridView hochladen, um eine hervorragende Leistung zu erzielen, während Sie das Filtern und Sortieren beibehalten. Es verwendet yii / queue und box / spout als Abhängigkeiten. Es ist sinnvoll, die Erweiterung zu verwenden, um wirklich große Dateien zu erstellen, also mindestens 50.000 Zeilen =) Derzeit ist das Modul, das die Grundlage für die Erweiterung geworden ist, mit einer Last von fast 600.000 Zeilen bekannt.

Link zu github: Yii2 ExcelReport-Erweiterung

Vielen Dank für Ihre Aufmerksamkeit!

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


All Articles