So skalieren Sie von 1 auf 100.000 Benutzer

Viele Startups haben dies durchgemacht: Täglich werden viele neue Benutzer registriert, und das Entwicklungsteam bemüht sich, die Arbeit des Dienstes zu unterstützen.

Dies ist ein angenehmes Problem, aber es gibt im Web nur wenige klare Informationen darüber, wie eine Webanwendung genau von null auf hunderttausende Benutzer skaliert werden kann. Normalerweise gibt es entweder Brandlösungen oder die Beseitigung von Engpässen (und oft beides). Daher verwenden die Leute ziemlich stereotype Tricks, um ihr Amateurprojekt in etwas wirklich Ernstes zu skalieren.

Versuchen wir, die Informationen herauszufiltern und die Hauptformel aufzuschreiben. Wir werden unsere neue Graminsta-Foto-Sharing-Site Schritt für Schritt von 1 auf 100.000 Benutzer skalieren.

Wir werden aufschreiben, welche spezifischen Maßnahmen erforderlich sind, um das Publikum auf 10, 100, 1000, 10 000 und 100 000 Personen zu erhöhen.

1 Benutzer: 1 Auto


Fast jede Anwendung, egal ob es sich um eine Website oder eine mobile Anwendung handelt, besteht aus drei Hauptkomponenten:

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

Die Datenbank speichert persistente Daten. Die API bedient Anforderungen für und um diese Daten. Der Client überträgt die Daten an den Benutzer.

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

Wenn wir zum ersten Mal eine Anwendung erstellen, können alle drei Komponenten auf demselben Server ausgeführt werden. In gewisser Weise erinnert uns dies an unsere Entwicklungsumgebung: Ein Techniker führt die Datenbank, die API und den Client auf demselben Computer aus.

Theoretisch könnten wir es in der Cloud auf einer Instanz von DigitalOcean Droplet oder AWS EC2 bereitstellen, wie unten gezeigt:

Wenn die Site mehr als einen Benutzer hat, ist es fast immer sinnvoll, die Datenbankebene hervorzuheben.

10 Benutzer: Die Datenbank auf eine separate Ebene bringen


Die Aufteilung einer Datenbank in verwaltete Dienste wie Amazon RDS oder die Digital Ocean Managed Database wird uns lange Zeit gute Dienste leisten. Dies ist etwas teurer als das Selbsthosting auf einem einzelnen Computer oder einer EC2-Instanz. Mit diesen Diensten erhalten Sie jedoch viele nützliche Erweiterungen, die sich in Zukunft als nützlich erweisen werden: Backups für mehrere Regionen, Lesereplikate, automatische Backups und vieles mehr.

So sieht das System jetzt aus:

100 Benutzer: Den Client auf eine separate Ebene bringen


Glücklicherweise hat unsere App die ersten Benutzer wirklich gemocht. Der Datenverkehr wird stabiler, daher ist es an der Zeit, den Client auf eine separate Ebene zu verschieben. Es sollte beachtet werden , dass Unternehmen Trennung ist ein wichtiger Aspekt eine skalierbare Anwendung zu bauen. Da ein Teil des Systems mehr Verkehr empfängt, können wir ihn aufteilen, um die Skalierung des Dienstes basierend auf bestimmten Verkehrsmustern zu steuern.

Deshalb möchte ich den Client getrennt von der API darstellen. Dies macht es sehr einfach, über die Entwicklung für verschiedene Plattformen zu sprechen: Web, mobiles Web, iOS, Android, Desktop-Anwendungen, Dienste von Drittanbietern usw. Alle sind nur Clients, die dieselbe API verwenden.

Zum Beispiel fordern unsere Benutzer jetzt am häufigsten die Freigabe einer mobilen Anwendung. Das Trennen von Client-Entitäten und APIs erleichtert dies.

So sieht das System aus:



1000 Benutzer: Load Balancer hinzufügen


Die Dinge laufen gut. Graminsta-Benutzer laden immer mehr Fotos hoch. Auch die Zahl der Anmeldungen wächst. Unser einzelner API-Server hat Schwierigkeiten, den gesamten Datenverkehr zu verwalten. Benötigen Sie mehr Eisen!

Load Balancer ist ein sehr leistungsfähiges Konzept. Die Schlüsselidee ist, dass wir den Balancer vor die API stellen und den Datenverkehr auf einzelne Dienstinstanzen verteilen. Dies ist die Art der horizontalen Skalierung, dh wir fügen mehr Server mit demselben Code hinzu und erhöhen so die Anzahl der Anforderungen, die wir verarbeiten können.

Wir werden separate Load Balancer vor dem Webclient und vor der API platzieren. Dies bedeutet, dass Sie mehrere Instanzen ausführen können, die den API-Code und den Webclient-Code ausführen. Der Load Balancer leitet Anforderungen an den Server weiter, der weniger belastet ist.

Hier bekommen wir einen weiteren wichtigen Vorteil - Redundanz. Wenn eine Instanz ausfällt (möglicherweise überlastet oder abstürzt), haben wir noch andere, die noch auf eingehende Anfragen reagieren. Wenn eine einzelne Instanz funktioniert, fällt im Falle eines Fehlers das gesamte System aus.

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

Mit einem Load Balancer kann die API-Ebene auf unendlich skaliert werden. Wir fügen lediglich neue Instanzen hinzu, wenn die Anzahl der Anforderungen zunimmt.


. , PaaS, Heroku Elastic Beanstalk AWS ( ). Heroku , - API. , Heroku — .

10 000 : CDN


Vielleicht hätte es von Anfang an gemacht werden sollen. Die Bearbeitung von Anfragen und das Aufnehmen neuer Fotos belasten unsere Server zu stark.

Zu diesem Zeitpunkt müssen Sie einen Cloud-Dienst zum Speichern statischer Inhalte verwenden - Bilder, Videos und vieles mehr (AWS S3 oder Digital Ocean Spaces). Im Allgemeinen sollte unsere API vermeiden, Dinge wie das Hochladen von Bildern und das Hochladen von Bildern auf einen Server zu verarbeiten.

Ein weiterer Vorteil des Cloud-Hostings ist das CDN (in AWS heißt dieses Add-On Cloudfront, wird jedoch von vielen Cloud-Speicherdiensten sofort angeboten). CDN speichert unsere Bilder automatisch in verschiedenen Rechenzentren auf der ganzen Welt zwischen.

Unser Hauptrechenzentrum befindet sich zwar in Ohio, aber wenn jemand ein Bild aus Japan anfordert, erstellt der Cloud-Anbieter eine Kopie und speichert es in seinem japanischen Rechenzentrum. Die nächste Person, die dieses Bild in Japan anfordert, erhält es viel schneller. Dies ist wichtig, wenn wir mit großen Dateien arbeiten, z. B. Fotos oder Videos, deren Hochladen und Übertragen über den gesamten Planeten lange dauert.



100.000 Benutzer: Skalierung auf Datenebene


CDN hat wirklich geholfen: Der Verkehr wächst mit voller Geschwindigkeit. Der berühmte Videoblogger Maid Mobrick hat sich gerade bei uns registriert und seine Geschichte veröffentlicht, wie es heißt. Dank des Load Balancers wird die CPU- und Speicherauslastung auf den API-Servern niedrig gehalten (zehn API-Instanzen werden ausgeführt), aber wir bekommen allmählich viele Zeitüberschreitungen für Anforderungen ... woher kamen diese Verzögerungen?

Nach einigem Eingraben in die Metriken sehen wir, dass die CPU auf dem Datenbankserver zu 80-90% ausgelastet ist. Wir sind am Limit.

Das Skalieren der Datenschicht ist wahrscheinlich der schwierigste Teil der Gleichung. API-Server bedienen zustandslose Anforderungen, daher fügen wir einfach weitere API-Instanzen hinzu. Aber mit den meistenDatenbanken sind nicht erfolgreich. Wir werden die gängigen relationalen Datenbankverwaltungssysteme (PostgreSQL, MySQL usw.) diskutieren.

Caching


Eine der einfachsten Möglichkeiten, die Leistung unserer Datenbank zu steigern, ist die Einführung einer neuen Komponente: der Cache-Ebene. Die häufigste Caching-Methode ist das Speichern von Schlüsselwertdatensätzen im RAM, z. B. Redis oder Memcached. Die meisten Clouds verfügen über eine verwaltete Version dieser Dienste: Elasticache in AWS und Memorystore in Google Cloud.

Der Cache ist nützlich, wenn ein Dienst die Datenbank wiederholt aufruft, um dieselben Informationen abzurufen. Tatsächlich greifen wir nur einmal auf die Datenbank zu, speichern die Informationen im Cache - und berühren sie nicht mehr.

In unserem Graminsta-Service fordert der API-Server beispielsweise jedes Mal, wenn jemand die Mobric-Sternprofilseite aufruft, Informationen von seinem Profil in der Datenbank an. Es passiert immer und immer wieder. Da sich die Profilinformationen von Mobrick nicht bei jeder Anfrage ändern, eignet sie sich hervorragend zum Zwischenspeichern.

Wir werden die Ergebnisse aus der Datenbank in Redis per Schlüssel user:idmit einer Gültigkeitsdauer von 30 Sekunden zwischenspeichern. Wenn jemand Mobricks Profil betritt, überprüfen wir zuerst Redis. Wenn die Daten vorhanden sind, übertragen wir sie einfach direkt von Redis. Abfragen zum beliebtesten Profil auf der Website laden 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-Cluster-Modus. Wie ein Load Balancer1Damit können Sie den Redis-Cache auf mehrere Computer verteilen (ggf. auf Tausende von Servern).

Fast alle großen Anwendungen verwenden Caching, dies ist ein absolut integraler Bestandteil der schnellen API. Schnellere Anforderungsverarbeitung und produktiverer Code - all dies ist wichtig, aber ohne Cache ist es fast unmöglich, den Dienst auf Millionen von Benutzern zu skalieren.

Repliken lesen


Wenn die Anzahl der Abfragen an die Datenbank erheblich zugenommen hat, können wir noch eines tun: Lesereplikate im Datenbankverwaltungssystem hinzufügen. Mit den oben beschriebenen verwalteten Diensten kann dies mit einem Klick erfolgen. Das gelesene Replikat bleibt in der Hauptdatenbank relevant und steht SELECT-Anweisungen zur Verfügung.

Hier ist jetzt unser System:



Weitere Maßnahmen


Da die Anwendung weiterhin skaliert wird, werden wir weiterhin Dienste trennen, um sie unabhängig voneinander zu skalieren. Wenn wir beispielsweise Websockets 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 abhängig von den offenen Websockets-Verbindungen und unabhängig von der Anzahl der HTTP-Anforderungen vergrößert und verkleinert werden kann.

Wir kämpfen auch weiterhin gegen Beschränkungen auf Datenbankebene. In diesem Stadium ist es an der Zeit, die Partitionierung und das Sharding der Datenbank zu untersuchen. Beide Ansätze erfordern zusätzlichen Overhead, aber Sie können die Datenbank fast bis unendlich skalieren.

Wir möchten auch einen Überwachungs- und Analysedienst wie New Relic oder Datadog installieren. Dadurch werden langsame Abfragen identifiziert und es wird verstanden, wo Verbesserungen erforderlich sind. Bei der Skalierung möchten wir uns darauf konzentrieren, Engpässe zu finden und zu beheben - häufig unter Verwendung einiger Ideen aus den vorherigen Abschnitten.

Quellen


Dieser Beitrag ist von einem meiner Lieblingsbeiträge mit hoher Skalierbarkeit inspiriert . Ich wollte den Artikel für die Anfangsphasen von Projekten ein wenig konkretisieren und ihn von einem Anbieter lösen. Lesen Sie unbedingt, wenn Sie an diesem Thema interessiert sind.

Fußnoten


  1. Trotz der Ähnlichkeiten hinsichtlich des Lastausgleichs über mehrere Instanzen unterscheidet sich die grundlegende Implementierung des Redis-Clusters stark vom Lastausgleich. [zurückgeben]



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


All Articles