Skalierung Ihrer Webanwendung: grundlegende Schritte
Veröffentlicht: 2022-09-13Es reicht nicht aus, Anwendungen für Ihr Unternehmen zu erstellen, Sie müssen sie optimieren. Ein effektiver Weg ist die Skalierung. In diesem Artikel erfahren Sie mehr über Codeoptimierung, Architekturoptimierung und wie Sie skalierbare Webanwendungen im Allgemeinen erstellen.
Optimierung
Gearheart schlägt vor, sich die folgenden Fragen zu stellen:
- sind die Datenbankabfragen optimal (EXPLAIN-Analyse, Nutzung von Indizes)?
- Werden die Daten korrekt gespeichert (SQL vs. NoSQL)?
- wird Caching verwendet?
- keine unnötigen Anfragen an den FS oder die Datenbank?
- Sind die Datenverarbeitungsalgorithmen optimal?
- sind die Umgebungseinstellungen optimal: Apache/Nginx, MySQL/PostgreSQL, PHP/Python?
Jede dieser Fragen könnte in einem separaten Artikel behandelt werden, sodass eine detaillierte Betrachtung im Rahmen dieses Artikels eindeutig übertrieben ist. Es ist wichtig zu verstehen, dass es sehr wünschenswert ist, ihre Arbeit so weit wie möglich zu optimieren, bevor Sie mit der Skalierung einer Anwendung beginnen – tatsächlich ist es dann möglich, dass überhaupt keine Skalierung erforderlich ist.
Skalierung
Angenommen, Sie haben Ihre Anwendung bereits optimiert, aber sie ist immer noch nicht in der Lage, die Last zu bewältigen. In diesem Fall besteht die naheliegende Lösung darin, die Anwendung auf mehrere Hosts zu verteilen, um die Gesamtleistung der Anwendung durch Erhöhung der verfügbaren Ressourcen zu erhöhen. Dieser Ansatz wird offiziell als „Skalieren“ der Anwendung bezeichnet. Genauer gesagt ist Skalierbarkeit die Fähigkeit eines Systems, seine Leistung zu steigern, indem es die Menge der ihm zur Verfügung stehenden Ressourcen erhöht.
Es gibt zwei Arten der Skalierbarkeit: vertikal und horizontal. Vertikale Skalierbarkeit impliziert eine Steigerung der Anwendungsleistung durch Hinzufügen von Ressourcen (CPU, Arbeitsspeicher, Festplatte) innerhalb eines Knotens (Host). Die horizontale Skalierung ist typisch für verteilte Anwendungen und impliziert die Steigerung der Anwendungsleistung durch Hinzufügen eines weiteren Knotens.
Es ist klar, dass der einfachste Weg ein einfaches Hardware-Upgrade (Prozessor, Speicher, Festplatte) ist – also vertikale Skalierung. Darüber hinaus erfordert dieser Ansatz keine Änderungen an der Anwendung. Allerdings stößt die vertikale Skalierung schnell an ihre Grenzen, woraufhin Entwickler und Administratoren keine andere Wahl haben, als auf horizontale Skalierung der Anwendung umzusteigen.
Anwendungsarchitektur
Die meisten Webanwendungen sind a priori verteilt, da ihre Architektur in mindestens drei Schichten unterteilt werden kann: Webserver, Geschäftslogik (Anwendung), Daten (Datenbank, statisch).
Jede dieser Ebenen kann skaliert werden. Wenn Ihr System also über eine Anwendung und eine Datenbank verfügt, die sich auf demselben Host befinden, sollte der erste Schritt auf jeden Fall darin bestehen, sie auf verschiedenen Hosts zu trennen.
Der Flaschenhals
Um mit der Skalierung des Systems fortzufahren, muss zunächst bestimmt werden, welche der Schichten der „Flaschenhals“ ist, dh langsamer als der Rest des Systems. Zunächst können Sie triviale Dienstprogramme wie top (htop) verwenden, um den CPU-/Speicherverbrauch auszuwerten, und df, iostat, um den Plattenverbrauch auszuwerten. Es ist jedoch wünschenswert, einen separaten Host mit einer Kampfladeemulation (mit AB oder JMeter) bereitzustellen, auf dem Sie die Anwendung mit Dienstprogrammen wie xdebug, oprofile usw. profilieren können. Sie können Dienstprogramme wie pgFouine verwenden, um enge Datenbankabfragen zu identifizieren (natürlich ist es besser, dies auf der Grundlage von Protokollen vom Kampfserver zu tun).
Normalerweise hängt es von der Architektur der Anwendung ab, aber im Allgemeinen sind die wahrscheinlichsten Kandidaten für einen Engpass die Datenbank und der Code. Wenn Ihre Anwendung viele Benutzerdaten verarbeitet, liegt der Engpass wahrscheinlich im statischen Speicher.
Datenbankskalierung
Wie oben erwähnt, ist der Flaschenhals in modernen Anwendungen oft die Datenbank. Probleme damit werden normalerweise in zwei Klassen eingeteilt: Leistung und die Notwendigkeit, eine große Datenmenge zu speichern.
Sie können die Belastung der Datenbank verringern, indem Sie sie auf mehrere Hosts aufteilen. Es gibt eine akute Schwierigkeit der Synchronisation zwischen ihnen, die gelöst werden kann, indem das Master/Slave-Schema mit synchroner oder asynchroner Replikation implementiert wird. Für PostgreSQL können Sie Slony-I für die synchrone Replikation und PgPool-II oder WAL (9.0) für die asynchrone Replikation verwenden. Um das Problem der Aufteilung von Lese- und Schreibanforderungen zu lösen und die Last zwischen den Slaves auszugleichen, können Sie eine spezielle Datenbankzugriffsschicht (PgPool-II) konfigurieren.
Das Problem der Speicherung großer Datenmengen bei relationalen Datenbanken kann durch Partitionierung („Partitionierung“ in PostgreSQL) oder durch Bereitstellung der Datenbank auf einer verteilten Datenbank wie Hadoop DFS gelöst werden.
Sie können beide Lösungen in dem hervorragenden Buch zur Konfiguration von PostgreSQL nachlesen.
1. Zum Speichern großer Datenmengen ist Sharding jedoch die beste Lösung, was ein inhärenter Vorteil der meisten NoSQL-Datenbanken (z. B. MongoDB) ist.
2. Darüber hinaus arbeiten NoSQL-Datenbanken im Allgemeinen schneller als ihre SQL-Brüder, da der Overhead für das Parsen/Optimieren der Abfrage, das Überprüfen der Datenstrukturintegrität usw. fehlt. Das Thema des Vergleichs der relationalen und NoSQL-Datenbanken ist ebenfalls recht umfangreich und verdient ein separater Artikel.
3.Separat erwähnenswert ist die Erfahrung von Facebook, das MySQL ohne JOIN-Auswahl verwendet. Diese Strategie ermöglicht es ihnen, die Datenbank viel einfacher zu skalieren, während die Last von der Datenbank auf den Code übertragen wird, der, wie unten beschrieben wird, einfacher skaliert als die Datenbank.
Code-Skalierung
- Die Komplexität der Skalierung von Code hängt davon ab, wie viele gemeinsam genutzte Ressourcen Ihre Hosts zum Ausführen Ihrer Anwendung benötigen. Werden es nur Sitzungen sein oder müssen Sie Caches und Dateien teilen? In jedem Fall müssen Sie zunächst Kopien der Anwendung auf mehreren Hosts mit derselben Umgebung ausführen.
- Als Nächstes müssen Sie den Last-/Anforderungsausgleich zwischen diesen Hosts einrichten. Sie können dies sowohl über TCP (HAProxy), HTTP (nginx) als auch über DNS tun.
- Der nächste Schritt, wie Gearheart erwähnte, besteht darin, die statischen Dateien, den Cache und die Webanwendungssitzungen auf jedem Host verfügbar zu machen. Für Sitzungen können Sie einen Server verwenden, der über das Netzwerk arbeitet (z. B. Memcached). Als Cache-Server ist es sinnvoll, denselben Memcached zu verwenden, aber natürlich auf einem anderen Host.
- Statische Dateien können von einigen gemeinsam genutzten Dateispeichern über NFS/CIFS oder mithilfe von verteiltem FS (HDFS, GlusterFS, Ceph) gemountet werden.
Es ist auch möglich, Dateien in einer Datenbank (z. B. Mongo GridFS) zu speichern, wodurch das Problem der Verfügbarkeit und Skalierbarkeit gelöst wird (wobei zu berücksichtigen ist, dass für die NoSQL-Datenbank das Skalierbarkeitsproblem durch Sharding gelöst wird).
Besonders erwähnenswert ist das Problem der Bereitstellung auf mehreren Hosts. Wie kann sichergestellt werden, dass der Benutzer durch Klicken auf „Aktualisieren“ keine verschiedenen Versionen der Anwendung sieht? Die einfachste Lösung wäre meiner Meinung nach, die Hosts, die nicht aktualisiert werden, aus dem Konfigurations-Load-Balancer (Webserver) auszuschließen und sie nacheinander einzuschalten, wenn Aktualisierungen vorgenommen werden. Sie können Benutzer auch per Cookie oder IP an bestimmte Hosts binden. Wenn die Aktualisierung erhebliche Änderungen an der Datenbank erfordert, ist es am einfachsten, das Projekt vorübergehend zu schließen.