Kann Laravel skalieren?


27.06.2022
Laravel

Als Laravel Freelancer bekommt man immer wieder die Frage gestellt, ob Laravel, bzw. irgendein PHP Framework überhaupt in der Lage ist, skalierbare Webanwendungen zu schreiben.

Wir alle sind die Fragen „Skaliert Laravel?“ leid. Nicht, weil die Leute Fragen stellen, sondern wegen der ignoranten Antworten auf diese Frage. Es ist nun schon mehrfach passiert, und die Geschichte ist immer die gleiche.

Jemand stellt auf Twitter oder in einem Forum die Frage, ob Laravel skalieren kann.
Zwei Gruppen von Leuten erscheinen Gruppe eins sagt: „Natürlich kann es skaliert werden; das Web-Framework wird für eine lange, lange Zeit kein Engpass sein“. Gruppe zwei sagt „nein“ und ist wütend, denn wie kann man es wagen, zu behaupten, dass ein PHP-Framework hyper-skalierbar ist.

In diesem Beitrag werde ich diese Frage klären: Ist Laravel skalierbar?

Wovor hat man Angst?

Bevor wir ins Detail gehen, ob Laravel skalieren kann, müssen Sie verstehen, dass die meisten Leute sich Sorgen über eine Situation machen, die sie nie erleben werden. Sie bauen nicht das nächste Google, Facebook oder YouTube.

Wenn also Leute die Frage stellen: „Lässt sich Laravel skalieren?“, weil sie ein Unternehmen gründen oder eine Anwendung für ein Multimilliarden-Dollar-Unternehmen entwickeln wollen, müssen sie sich darüber im Klaren sein, dass sie einfach nicht die Größenordnung von Facebook erreichen werden.

Wie viele Anfragen bewältigt Wikipedia?

Wikipedia ist eine der größten Websites der Welt, und, raten Sie mal, sie läuft mit PHP. Einem TechCrunch-Artikel aus dem Jahr 2020 zufolge verarbeitete Wikipedia im Durchschnitt 255 Millionen Seitenaufrufe pro Tag. Wie sieht das nun pro Sekunde und pro Monat aus?

225 Millionen / 86400 = 2.604 Seitenaufrufe pro Sekunde
225 Millionen x 30 = 6,75 Milliarden Seitenaufrufe pro Monat

Ist Wikipedia eine große Website?

Worüber sollte an sich Sorgen machen?

Nachdem ich nun einige der gebrochenen mentalen Modelle angesprochen habe, derer sich einige von uns schuldig gemacht haben, möchte ich auf die Feinheiten der Skalierung einer Laravel-Anwendung eingehen. Bevor ich eine Website-Analyseplattform mitbegründet habe, hatte ich keine Erfahrung mit der Skalierung von Anwendungen. Meine Erfahrung bis zur Leitung dieses Unternehmens bestand darin, Anwendungen für 100 bis 10.000 Benutzer zu entwickeln, und ich musste mich sicherlich nie mit Milliarden von Seitenaufrufen befassen.

Wenn Laravel also nicht der Bereich ist, über den wir uns Sorgen machen sollten, wenn es um die Skalierung geht, was dann?

Datenbank, Cache und Sitzungen.

Ihre Datenbank wird bei der Skalierung der Flaschenhals sein. Ich gehe hier von einem traditionellen MySQL/PostgreSQL-Setup aus. Sie werden keine Probleme bekommen, wenn Sie von Anfang an DynamoDB oder SingleStore verwenden, da diese Lösungen für eine gigantische Skalierung mit minimaler Konfiguration ausgelegt sind. Wie auch immer, die Datenbankleistung ist ein ganzes Berufsfeld, und viele Dinge können außerhalb der Abfragen, die Sie schreiben, optimiert werden.

Ein möglicher Weg zur Datenbank wäre:

A SQLite file for each client (this was terrible, don’t do it).
Managed PostgreSQL on Heroku (lack of familiarity with Postgress led to a desire to switch to MySQL).
Managed MySQL on Heroku (this was fine, but we abandoned Heroku and switched to Laravel Vapor).
RDS for MySQL (we ran into performance issues because we needed ad-hoc analytics and a highly scalable ingest. MySQL kept falling over, despite upgrades and IOPS increases).
SingleStore (the database of our dreams)

Wir haben einige Jahre lang Redis als Cache verwendet und sind dann auf DynamoDB umgestiegen (damit wir uns keine Gedanken über die Dimensionierung von Redis oder NAT-Gateways bei AWS machen mussten). Heutzutage verwenden wir die In-Memory-Tabellen von SingleStore für das Caching, weil es so schnell geht.

Wir haben nur mit Managed Services gearbeitet, weil wir keine Datenbankingenieure sind. Wenn Sie ein Datenbankingenieur sind, werden Sie keine Probleme mit der Skalierung Ihrer Datenbank haben, und Sie wissen bereits, wie man sie horizontal skaliert, optimiert, usw. Aber alle anderen sollten sich darauf einstellen, dass die Datenbank beim Wachstum Kopfschmerzen bereiten wird.

Queues / Warteschlangen

Das Laravel-Warteschlangensystem hat mehrere Treiber wie Amazon SQS, Redis, Datenbank usw. Wie Sie wissen, besteht der Zweck des Warteschlangensystems darin, zeitaufwändige Aufgaben in den Hintergrund zu verlagern, um schnelle Antwortzeiten für Ihre Benutzer zu gewährleisten.

Wir sind große Fans von SQS, weil es unbegrenzten Durchsatz und ausgezeichnete Sicherheit bietet und Aufträge über mehrere Verfügbarkeitszonen hinweg speichert. Jetzt, wo wir SingleStore für unsere Datenbank verwenden, könnten sie auch unsere Warteschlange betreiben, aber wir mögen es, dass unser Warteschlangensystem von der Datenbank getrennt ist (aus Gründen der Fehlertoleranz).

Eine meiner Bedenken, als wir Redis für unsere Warteschlange nutzten, war: „Was passiert, wenn wir einen Rückstau in der Warteschlange haben, Redis voll ist und uns der Platz ausgeht.“ Und das war eine berechtigte Sorge, denn in den ersten Tagen waren wir kurz davor. Darüber hinaus gibt es eine Reihe von Dingen, die man tun kann, um Redis zu skalieren, zu denen die meisten Leute in ihrer Karriere nicht kommen werden, aber es ist möglich. Man kann Redis so konfigurieren, dass es auf Laravel-Warteschlangen skaliert, und viele Leute haben das getan. Oder Sie können SQS oder SingleStore verwenden. Einfach.

Andere Dienste

Wenn Sie PHP-FPM verwenden, sollten Sie darauf achten, es einem Lasttest unterziehen und es so optimal wie möglich konfigurieren. Aber davon abgesehen werden Ihre „externen Dienste“, wie Ihre Datenbank, Ihr Warteschlangensystem usw., zu Ihrem primären Engpass werden, bevor PHP-FPM es tut (in den meisten Fällen, ich bin sicher, es gibt Ausnahmen, und ich bin sicher, die Antwort-Jungs werden es mich wissen lassen). Zusätzlich zu den oben genannten Punkten, vergessen Sie nicht das Folgende:

Vergewissern Sie sich, dass Ihre E-Mail-API (Postmark, SES usw.) mit den Raten zurechtkommt, mit denen Sie sie versenden. Das Gleiche gilt für SMS-Benachrichtigungen und alles andere. Überprüfen Sie auch die Ratenbeschränkungen für jeden externen Dienst, den Sie nutzen, und überwachen Sie diese, da Sie sie bei einer Skalierung möglicherweise erhöhen müssen.
Verwenden Sie ein CDN. Sie sollten keine statischen Inhalte von Ihrem Webserver aus bereitstellen, sondern ein CDN wie bunny.net, Cloudfront oder Cloudflare nutzen.

Skalierbaren Code schreiben

Wenn man ein Projekt in großem Maßstab betreibt, muss man über Dinge nachdenken, an die man vorher vielleicht nicht gedacht hat. Ich werde ein paar Gedanken dazu äußern, aber dies ist kein umfassender Leitfaden für die Programmierung 🙂

Eine meiner ersten Erfahrungen mit einem „WTF“-Moment war, als ich Datenbanktransaktionen für Einfügevorgänge verwendete und bei der automatischen Inkrementierung von Spalten in Tabellen auf Deadlock-Fehler stieß. Um es kurz zu machen: Ich hatte mehrere Multi-Abfrage-Tabellen-Transaktionen, die darum kämpften, eine Sperre für Auto-Increment zu erhalten, um eine Zeile zu schreiben. Die ursprüngliche Lösung für dieses Problem, die gut funktionierte, bestand darin, die Transaktion 50 Mal zu wiederholen, aber das lässt sich nicht skalieren und ist äußerst ineffizient.

Schließlich sind wir von der Verwendung von Transaktionen abgekommen und haben das Problem behoben. Was ich damit sagen will, ist, dass Sie dieses Problem in geringem Umfang nicht bemerken werden. Aber wenn die Dinge erst einmal in Gang kommen, werden Sie Dinge wie diese sehen.

In diesem Sinne möchte ich Ihnen einige Überlegungen zum Schreiben von skalierbarem Code vorstellen:

  • Stellen Sie sicher, dass Ihre Abfragen konsistent sind. Die Ingenieure von Facebook hatten einen guten Rat: „Es ist in Ordnung, wenn eine Abfrage langsam ist, solange sie immer langsam ist“. Ich stimme zu, und das bedeutet, dass Sie Ihre Abfragen gut kennen und sie effizient schreiben müssen.
  • Wissen, wann man Funktionalität auslagern sollte. Wir sprechen hier über den Einsatz von Laravel in großem Maßstab, aber ich sage nicht, dass Sie Laravel für die Verarbeitung von Videos verwenden sollten. Wenn Amazon einen Service anbietet, der dies für Sie tun kann, sollten Sie ihn nutzen. Wenn Sie erst einmal Milliarden von Dollar pro Jahr umsetzen, können Sie es mit einem hochmodernen C++-Framework selbst entwickeln. Das wird ein Riesenspaß!
  • Teure Abfragen zwischenspeichern. Dies gilt für alle Projekte, wird aber mit zunehmender Größe entscheidend. Wenn Sie eine komplexe/langsame SQL-Abfrage ausführen und diese für mehrere Personen oder mehrmals angezeigt wird, sollten Sie das Ergebnis zwischenspeichern. Auf diese Weise müssen Sie bei nachfolgenden Anfragen nur eine Schlüssel/Wert-Cache-Suche durchführen, was sich enorm auszahlt. Wir haben dies für unsere aktuelle Besucherbox auf dem Fathom-Dashboard getan. Wenn jemand sein öffentliches Fathom-Dashboard einem großen Publikum zur Verfügung stellt, gibt es plötzlich Tausende von Leuten, die alle 10 Sekunden mit der gleichen Abfrage nach den aktuellen Besuchern in Echtzeit suchen, und das möglicherweise stundenlang. Daher haben wir damit begonnen, die Antwort für nicht authentifizierte Benutzer (aka zufällige Personen), die ein öffentliches Dashboard ansehen, für 10 Sekunden zwischenzuspeichern. Durch diese Änderung wurde unsere Datenbank erheblich entlastet, da nur noch eine der Anfragen die teure Abfrage durchführte, während der Rest in den Cache ging. Und diese Spitzen traten nie wieder auf, weil Schlüssel/Wert-Abfragen (Cache) viel effizienter sind.
  • AWS-Servicegrenzen. Wenn Sie AWS nutzen, gibt es für verschiedene Dienste Limits, und die können Sie beißen. Ein hervorragendes Beispiel in Laravel Vapor ist, dass Sie bei der Verwendung von Secrets möglicherweise den Durchsatz Ihres Parameterspeichers erhöhen müssen. Vapor verwendet diese bei der Erstellung eines Containers (Hinweis: Der Container wird mehrmals wiederverwendet, bevor er neu gestartet wird, so dass er nicht bei jeder Anfrage auf den Parameterspeicher zugreift). Standardmäßig haben Sie Zugriff auf 40 Transaktionen pro Sekunde, was für viele Anwendungsfälle perfekt ist. Als wir jedoch wuchsen, traten Fehler auf, und wir mussten auf einen höheren Durchsatz umsteigen (3.000 Transaktionen pro Sekunde). Schauen Sie sich also die Quoten für alle Ihre Dienste an.