So skalieren Sie von 1 auf 100 Benutzer

Viele Start-ups haben das erlebt: Jeden Tag registrieren sich Scharen neuer Benutzer und das Entwicklungsteam hat Mühe, den Dienst am Laufen zu halten.

Das ist ein nettes Problem, aber im Web gibt es kaum klare Informationen darüber, wie man eine Webanwendung sorgfältig von Null auf Hunderttausende von Benutzern skaliert. Typischerweise gibt es entweder Lösungen für den Brandfall oder Lösungen für Engpässe (oft auch beides). Daher verwenden die Leute eher klischeehafte Techniken, um ihr Amateurprojekt in etwas wirklich Ernstes zu verwandeln.

Versuchen wir, die Informationen zu filtern und die Grundformel aufzuschreiben. Wir werden unsere neue Foto-Sharing-Seite Graminsta Schritt für Schritt von 1 auf 100 Nutzer skalieren.

Schreiben wir auf, welche konkreten Maßnahmen ergriffen werden müssen, wenn das Publikum auf 10, 100, 1000, 10 und 000 Personen ansteigt.

1 Benutzer: 1 Maschine

Fast jede Anwendung, sei es eine Website oder eine mobile Anwendung, besteht aus drei Schlüsselkomponenten:

  • API
  • Datenbank
  • Client (mobile Anwendung selbst oder Website)

Die Datenbank speichert persistente Daten. Die API bedient Anfragen an und um diese Daten. Der Client übermittelt Daten an den Benutzer.

Ich kam zu dem Schluss, dass es viel einfacher ist, über die Skalierung einer Anwendung zu sprechen, wenn aus architektonischer Sicht die Client- und API-Entitäten vollständig getrennt sind.

Wenn wir zum ersten Mal mit der Erstellung einer Anwendung beginnen, können alle drei Komponenten auf demselben Server ausgeführt werden. In mancher Hinsicht ähnelt dies unserer Entwicklungsumgebung: Ein Ingenieur führt die Datenbank, die API und den Client auf demselben Computer aus.

Theoretisch könnten wir es in der Cloud auf einer einzelnen DigitalOcean Droplet- oder AWS EC2-Instanz bereitstellen, wie unten gezeigt:
So skalieren Sie von 1 auf 100 Benutzer
Wenn es jedoch mehr als einen Benutzer auf einer Site gibt, ist es fast immer sinnvoll, eine eigene Datenbankschicht bereitzustellen.

10 Benutzer: Verschieben der Datenbank auf eine separate Ebene

Die Aufteilung der Datenbank in verwaltete Dienste wie Amazon RDS oder Digital Ocean Managed Database wird uns noch lange gute Dienste leisten. Es ist etwas teurer als Selbsthosting auf einer einzelnen Maschine oder EC2-Instanz, aber mit diesen Diensten erhalten Sie sofort viele nützliche Erweiterungen, die sich in Zukunft als nützlich erweisen werden: Backup in mehreren Regionen, Lesereplikate, automatisch Backups und mehr.

So sieht das System jetzt aus:
So skalieren Sie von 1 auf 100 Benutzer

100 Benutzer: Verschieben des Clients auf eine separate Ebene

Glücklicherweise hat unseren ersten Benutzern unsere Anwendung sehr gut gefallen. Der Datenverkehr wird stabiler, daher ist es an der Zeit, den Client auf eine separate Ebene zu verschieben. Es ist darauf hinzuweisen, dass Trennung Entitäten sind ein wichtiger Aspekt beim Erstellen einer skalierbaren Anwendung. Wenn ein Teil des Systems mehr Datenverkehr empfängt, können wir ihn partitionieren, um zu steuern, wie der Dienst basierend auf bestimmten Datenverkehrsmustern skaliert.

Aus diesem Grund stelle ich mir den Client gerne getrennt von der API vor. Dies macht es sehr einfach, über die Entwicklung für mehrere Plattformen nachzudenken: Web, mobiles Web, iOS, Android, Desktop-Anwendungen, Dienste von Drittanbietern usw. Es sind alles nur Clients, die dieselbe API verwenden.

Beispielsweise fragen unsere Benutzer heute am häufigsten nach der Veröffentlichung einer mobilen Anwendung. Wenn Sie die Client- und API-Entitäten trennen, wird dies einfacher.

So sieht ein solches System aus:

So skalieren Sie von 1 auf 100 Benutzer

1000 Benutzer: Load Balancer hinzufügen

Es geht bergauf. Graminsta-Benutzer laden immer mehr Fotos hoch. Auch die Zahl der Anmeldungen steigt. Unser einziger API-Server hat Schwierigkeiten, mit dem gesamten Datenverkehr Schritt zu halten. Brauchen Sie mehr Eisen!

Load Balancer ist ein sehr leistungsfähiges Konzept. Die Kernidee besteht darin, dass wir vor der API einen Load Balancer platzieren, der den Datenverkehr auf einzelne Serviceinstanzen verteilt. Auf diese Weise skalieren wir horizontal, d. h. wir fügen mehr Server mit demselben Code hinzu und erhöhen so die Anzahl der Anfragen, die wir verarbeiten können.

Wir werden separate Load Balancer vor dem Webclient und vor der API platzieren. Das bedeutet, dass Sie mehrere Instanzen ausführen können, auf denen API-Code und Web-Client-Code ausgeführt werden. Der Load Balancer leitet Anfragen an den Server weiter, der weniger ausgelastet ist.

Hier erhalten wir einen weiteren wichtigen Vorteil – Redundanz. Wenn eine Instanz ausfällt (vielleicht überlastet oder abgestürzt), bleiben uns andere übrig, die weiterhin auf eingehende Anfragen reagieren. Wenn nur eine Instanz funktionieren würde, würde im Fehlerfall das gesamte System abstürzen.

Der Load Balancer bietet auch eine automatische Skalierung. Wir können es so konfigurieren, dass die Anzahl der Instanzen vor Spitzenlast erhöht und verringert wird, wenn alle Benutzer schlafen.

Mit einem Load Balancer kann die API-Ebene nahezu unbegrenzt skaliert werden, indem einfach neue Instanzen hinzugefügt werden, wenn die Anzahl der Anfragen steigt.

So skalieren Sie von 1 auf 100 Benutzer

Notiz. Derzeit ähnelt unser System stark dem, was PaaS-Unternehmen wie Heroku oder Elastic Beanstalk auf AWS standardmäßig anbieten (weshalb sie so beliebt sind). Heroku legt die Datenbank auf einem separaten Host ab, verwaltet einen automatisch skalierenden Load Balancer und ermöglicht Ihnen, den Webclient getrennt von der API zu hosten. Dies ist ein guter Grund, Heroku für Projekte oder Startups in der Frühphase zu verwenden – Sie erhalten alle grundlegenden Dienste sofort einsatzbereit.

10 Benutzer: CDN

Vielleicht hätten wir das von Anfang an tun sollen. Die Bearbeitung von Anfragen und die Annahme neuer Fotos überfordern unsere Server zunehmend.

In dieser Phase müssen Sie einen Cloud-Dienst zum Speichern statischer Inhalte nutzen – Bilder, Videos und vieles mehr (AWS S3 oder Digital Ocean Spaces). Im Allgemeinen sollte unsere API Dinge wie das Bereitstellen von Bildern und das Hochladen von Bildern auf den Server vermeiden.

Ein weiterer Vorteil des Cloud-Hostings ist das CDN (AWS nennt dieses Add-on Cloudfront, aber viele Cloud-Speicheranbieter bieten es sofort an). Das CDN speichert unsere Bilder automatisch in verschiedenen Rechenzentren auf der ganzen Welt zwischen.

Obwohl sich unser Hauptrechenzentrum möglicherweise in Ohio befindet, erstellt der Cloud-Anbieter eine Kopie und speichert sie in seinem japanischen Rechenzentrum, wenn jemand ein Bild aus Japan anfordert. Die nächste Person, die dieses Bild in Japan anfordert, wird es viel schneller erhalten. Dies ist wichtig, wenn wir mit großen Dateien wie Fotos oder Videos arbeiten, deren Herunterladen und weltweite Übertragung lange dauert.

So skalieren Sie von 1 auf 100 Benutzer

100 Benutzer: Skalierung der Datenschicht

CDN hat sehr geholfen: Der Verkehr wächst mit voller Geschwindigkeit. Der berühmte Videoblogger Mavid Mobrick hat sich gerade bei uns registriert und seine „Story“, wie man so sagt, gepostet. Dank des Load Balancers wird die CPU- und Speicherauslastung auf den API-Servern niedrig gehalten (zehn API-Instanzen laufen), aber bei Anfragen kommt es zunehmend zu Zeitüberschreitungen ... woher kommen diese Verzögerungen?

Wenn wir ein wenig in die Metriken eintauchen, sehen wir, dass die CPU auf dem Datenbankserver zu 80–90 % ausgelastet ist. Wir sind am Limit.

Die Skalierung der Datenschicht ist wahrscheinlich der schwierigste Teil der Gleichung. API-Server bedienen zustandslose Anfragen, daher fügen wir einfach weitere API-Instanzen hinzu. Nase mit der Mehrheit Datenbanken können dies nicht. Wir werden über beliebte relationale Datenbankverwaltungssysteme (PostgreSQL, MySQL usw.) sprechen.

Caching

Eine der einfachsten Möglichkeiten, die Leistung unserer Datenbank zu steigern, ist die Einführung einer neuen Komponente: der Cache-Schicht. Die gebräuchlichste Caching-Methode ist ein speicherinterner Schlüsselwert-Datensatzspeicher wie Redis oder Memcached. Die meisten Clouds verfügen über eine verwaltete Version dieser Dienste: Elasticache auf AWS und Memorystore auf Google Cloud.

Ein Cache ist nützlich, wenn ein Dienst viele wiederholte Aufrufe an die Datenbank durchführt, um dieselben Informationen abzurufen. Im Wesentlichen greifen wir nur einmal auf die Datenbank zu, speichern die Informationen im Cache und greifen nicht mehr darauf zu.

In unserem Graminsta-Dienst beispielsweise fragt der API-Server jedes Mal, wenn jemand die Profilseite des Stars Mobrik aufruft, die Datenbank nach Informationen aus seinem Profil ab. Das kommt immer wieder vor. Da sich die Profilinformationen von Mobrik nicht bei jeder Anfrage ändern, eignet es sich hervorragend zum Zwischenspeichern.

Wir werden die Ergebnisse aus der Datenbank in Redis nach Schlüssel zwischenspeichern user:id mit einer Gültigkeitsdauer von 30 Sekunden. Wenn nun jemand das Profil von Mobrik aufruft, überprüfen wir zunächst Redis, und wenn die Daten dort sind, übertragen wir sie einfach direkt von Redis. Jetzt laden Anfragen an das beliebteste Profil auf der Website unsere Datenbank praktisch nicht mehr.

Ein weiterer Vorteil der meisten Caching-Dienste besteht darin, dass sie einfacher zu skalieren sind als Datenbankserver. Redis verfügt über einen integrierten Redis-Cluster-Modus. Ähnlich einem Load Balancer1ermöglicht es Ihnen, Ihren Redis-Cache auf mehrere Maschinen zu verteilen (bei Bedarf auf Tausende von Servern).

Fast alle großen Anwendungen verwenden Caching; es ist ein absolut integraler Bestandteil einer schnellen API. Eine schnellere Abfrageverarbeitung und produktiverer Code sind wichtig, aber ohne Cache ist es fast unmöglich, einen Dienst auf Millionen von Benutzern zu skalieren.

Replikate lesen

Wenn die Anzahl der Abfragen an die Datenbank stark zugenommen hat, können wir auch Lesereplikate im Datenbankverwaltungssystem hinzufügen. Mit den oben beschriebenen Managed Services gelingt dies mit einem Klick. Das Lesereplikat bleibt in der Hauptdatenbank aktuell und steht für SELECT-Anweisungen zur Verfügung.

Hier ist jetzt unser System:

So skalieren Sie von 1 auf 100 Benutzer

Nächste Schritte

Während die Anwendung weiter wächst, werden wir die Dienste weiterhin trennen, um sie unabhängig voneinander zu skalieren. Wenn wir beispielsweise anfangen, Websockets zu verwenden, ist es sinnvoll, den Websockets-Verarbeitungscode in einen separaten Dienst zu ziehen. Wir können es auf neuen Instanzen hinter unserem eigenen Load Balancer platzieren, der basierend auf offenen Websockets-Verbindungen und unabhängig von der Anzahl der HTTP-Anfragen nach oben und unten skalieren kann.

Auch auf Datenbankebene werden wir weiterhin gegen Einschränkungen vorgehen. In diesem Stadium ist es an der Zeit, sich mit der Datenbankpartitionierung und dem Sharding zu befassen. Beide Ansätze erfordern zusätzlichen Aufwand, ermöglichen jedoch eine nahezu unbegrenzte Skalierung der Datenbank.

Wir möchten außerdem einen Überwachungs- und Analysedienst wie New Relic oder Datadog installieren. Dies wird Ihnen helfen, langsame Abfragen zu erkennen und zu verstehen, wo Verbesserungen erforderlich sind. Bei der Skalierung möchten wir uns darauf konzentrieren, Engpässe zu finden und zu beseitigen – oft unter Verwendung einiger Ideen aus den vorherigen Abschnitten.

Quellen

Dieser Beitrag ist von einem davon inspiriert meine Lieblingsbeiträge zum Thema hohe Skalierbarkeit. Ich wollte den Artikel etwas spezifischer für die Anfangsphasen von Projekten gestalten und ihn von einem Anbieter trennen. Lesen Sie unbedingt, wenn Sie sich für dieses Thema interessieren.

Fußnoten

  1. Obwohl die Lastverteilung auf mehrere Instanzen ähnlich ist, unterscheidet sich die zugrunde liegende Implementierung eines Redis-Clusters stark von einem Load Balancer. [zurückkehren]

So skalieren Sie von 1 auf 100 Benutzer

Source: habr.com

Kommentar hinzufügen