Wie erstelle ich hochskalierbare Webdienste in Java?

15

Ich erstelle einige Webdienste, die 2000 gleichzeitige Benutzer haben würden. Die Dienste werden kostenlos angeboten und es wird daher eine große Nutzerbasis erwartet. In Zukunft kann es erforderlich sein, bis zu 50.000 Benutzer zu skalieren.

Es gibt bereits einige andere Fragen, die sich mit dem Problem befassen: /programming/2567254/building-highly-scalable-web-services

Meine Anforderungen weichen jedoch von der obigen Frage ab.

Zum Beispiel: Meine Anwendung hat keine Benutzeroberfläche, daher sind Bilder, CSS und Javascript kein Problem. Es ist in Java so, dass Vorschläge wie die Verwendung von HipHop zur Übersetzung von PHP in nativen Code unbrauchbar sind.

Daher habe ich beschlossen, meine Frage separat zu stellen.

Dies ist mein Projektaufbau -

  1. Restbasierte Webdienste mit Apache CXF
  2. Hibernate 3.0 (mit relevanten Optimierungen wie verzögertem Laden und benutzerdefiniertem HQL für die Optimierung)
  3. Tomcat 6.0
  4. MySQL 5.5

Welche Best Practices müssen befolgt werden, um eine Java-basierte Anwendung skalierbar zu machen?

Kshitiz Sharma
quelle
Wenn Sie einen REST-Service verfügbar machen, kann die Verwendung eines Reverse-Proxys wie Varnish sehr hilfreich sein. Wie aktuell müssen die Daten sein? Sind Sie sicher, dass Sie eine relationale Datenbank benötigen? Könnten Sie die Daten partitionieren? Bei dem Technologie-Stack, den Sie beschreiben, würde ich mich darauf konzentrieren, sicherzustellen, dass so wenig wie möglich Anforderungen tatsächlich Ihren Endpunkt erreichen. Haben Sie sich überlegt, dies mit Lösungen wie Hazel Cast / Gigaspaces usw. in Erinnerung zu rufen?
Ebaxt
@ebaxt danke für deine Vorschläge. Gigaspaces scheinen Open Source zu sein. Aber die Besetzung mit Hazel sieht interessant aus.
Kshitiz Sharma
1
@ebaxt "Sind Sie sicher, dass Sie eine relationale Datenbank benötigen?" Die Einführung von nosql hätte drastische Änderungen an der Anwendungsarchitektur zur Folge. Wir versuchen, die Komplexität so gering wie möglich zu halten. Die Kosten spielen für uns jedoch keine Rolle. Also bleiben wir beim relationalen Ansatz.
Kshitiz Sharma
1
Sie können Postgres, MySQL oder was auch immer verwenden. Was ist mit Ihrer Infrastruktur? Können Sie Disk-Arrays verwenden? Werden die Server am selben Ort gehostet? Können Sie Ihren Cluster mit Heartbeat usw. verbinden? Können Sie sie in dasselbe Subnetz stellen?
Edze
1
Ich bin auch ein Programmierer. Aber wenn Ihre relationale Datenbank der Engpass ist, werden Sie am Ende diese Fragen haben. Es gibt Datenbanken auf dem Markt, von denen einige in bestimmten Situationen besser abschneiden als andere. Aber sie verwenden unterschiedliche Standardtransaktionsisolationsstufen und optimistische Parallelität gegenüber pessimistischer Parallelität usw.
edze

Antworten:

8

Ich habe mich in der Vergangenheit mit dem Thema befasst, habe aber immer noch das Gefühl, dass ich auf dem Feld viel zu lernen habe. Ich halte dies für eines der interessantesten Gebiete in der Softwareentwicklung. Hier einige Gedanken dazu:
MySQL ist eine Datenbank, die fair genug ist, es sei denn, Sie arbeiten mit einer riesigen Datenmenge, und in diesem Fall könnten Sie NoSQL in Betracht ziehen Sie sollten jedoch sorgfältig prüfen, welche NoSQL-Datenbank für Ihre Anforderungen am besten geeignet ist .

Sie sollten Caching auf Ihrem System implementieren - versuchen Sie, so viele Nur-Lese-Daten wie möglich zwischenzuspeichern, oder definieren Sie einige Caching-Strategien. Beispielsweise hatten wir ein Szenario, in dem ein Benutzer "alte Daten" als "gültig" ansah solange das letzte Update in der letzten Stunde stattgefunden hat.
Ich würde JBoss Cache oder vielleicht Infinispan (das eher einer verteilten Datenstruktur ähnelt ) oder ein anderes beliebtes Caching-Framework für diesen Zweck in Betracht ziehen .
Wie Sie bereits erwähnt haben, gehe ich davon aus, dass Sie in einem Request-Respone-Modul arbeiten. Versuchen Sie, einen Cache zu verwenden, der in einem Bereich einer bestimmten Anforderung vorhanden ist. Dies kann sogar eine einfache HashMap sein, die dem lokalen Thread-Speicher zugeordnet ist .
Meine Idee hier ähnelt ziemlich dem Cache der ersten Ebene im Ruhezustand .

Sie sollten sich daran erinnern, dass Dateien, Transaktionen und andere Ressourcen teuer sind, um sie offen zu halten. Stellen Sie sicher, dass Sie Dateien und Transaktionen so schnell wie möglich schließen. Andernfalls treten Fehler auf, die bei umfangreichen Setups auftreten können

Darüber hinaus müssen Sie wissen, welche 2000 gleichzeitigen Benutzer auf Ihren Server zugreifen. Bedeutet dies, dass 2000 Benutzer gleichzeitig auf Ihren Server zugreifen, oder verwenden sie Ihr System? Unterscheiden Sie zwischen Fällen, in denen 2000 Benutzer versuchen, einen Socket für Ihren Server zu öffnen, und einem Fall, in dem nur 500 Benutzer und derzeit 1500 Benutzer die Ergebnisse der Eingabe auf Clientseite anzeigen.

Sie sollten die Verwendung von Clustering in Betracht ziehen - Sie müssen sich mit Problemen wie Lastausgleich und Sticky-Sitzung befassen (was bedeutet, dass der Lastausgleich eine Anforderung für dieselbe Sitzung an denselben Server umleitet) und mehr.

Wenn Sie einen Synchronisierungscode benötigen, wählen Sie die Synchronisierungsstrategie sorgfältig aus. Ich habe einige Systeme gesehen, in denen ein einfaches Schloss verwendet wurde, aber ein ReaderWriterLockhätte verbessert werden können, da die meisten Zugriffe schreibgeschützt waren.

Erwägen Sie nach Möglichkeit die clientseitige Zwischenspeicherung und Validierung, versuchen Sie, Anrufe auf dem Server zu speichern und nur Datenunterschiede zu senden, falls sich der größte Teil Ihrer Antwort auf eine Anforderung mit demselben Parameter nicht ändert.
Beispielsweise fordern wir bei einem Open-Source-Projekt von oVirt Statistiken zu einer bestimmten virtuellen Maschine an. Einige der Daten der VM ändern sich selten, daher senden wir nur MD5 davon. Wenn sich die Daten ändern, wird auch der MD5-Wert geändert, und es wird eine Anforderung zum Abrufen der vollständigen Daten und nicht nur des MD5 ausgeführt.

Ich habe den Ruhezustand bereits erwähnt - ich empfehle Ihnen, ihn sorgfältig zu verwenden -, wenn Sie viele Schreibvorgänge und weniger Lesevorgänge ausführen müssen, ist der Ruhezustand möglicherweise nicht ideal für Sie, und Sie sollten in Betracht ziehen, mit Spring-JDBC als Wrapper zu arbeiten JDBC.

Indizieren Sie Ihre Datenbank mit Bedacht und verwenden Sie ein korrektes Datenbankschema. Erwägen Sie die Verwendung einer Schicht gespeicherter Prozeduren, da diese vorkompiliert und optimiert sind.

Ich möchte darauf hinweisen, dass ich mich in der Vergangenheit mit einem System (einzelner Knoten) auf MySQL (meist nur Lesezugriff) mit JBoss 4.2.1 befasst habe und 2000 gleichzeitig erreicht habe Benutzer
(Es wird nicht sofort zugegriffen, um 2000 Sockets für unseren Server zu öffnen), sondern es wird "heiß und beliebt" sein, unser System zu verwenden / zu durchsuchen, JBoss Cache zu verwenden und einige der Daten, auf die am häufigsten zugegriffen wird, in den Cache zu laden "aber unsere Lösung war gut für unsere Architektur und unsere Abläufe,
also, wie ich in diesen Fällen sage -
Es gibt weitere Tipps und Tricks, aber es hängt wirklich von Ihrer Architektur ab und welche Abläufe Sie in Ihrem System haben müssen. Viel Glück!


quelle
Ich bin damit einverstanden, außer für gespeicherte Procs, verwende keine gespeicherten Procs. Und Sie können eine gleichzeitige Hashmap und atomare Werte verwenden, um threadsicher zu machen
NimChimpsky
3

Gute Frage. Wahrscheinlich schwer zu sagen, welcher Ansatz der beste ist, aber ich werde es aus meiner Erfahrung versuchen.

Der beste Weg, die Java-basierte Webanwendung zu skalieren, besteht darin, sie so zustandslos wie möglich zu schreiben (wenn Sie könnten). Auf diese Weise können Sie die Anwendung horizontal skalieren und Tomcat-Server hinzufügen, wenn mehrere Benutzer gleichzeitig angemeldet sind.

Wie Sie bereits bemerkt haben, kann es jedoch zu Problemen mit den Datenbankverbindungen kommen. Aber die Frage, die ich habe, ist, wie kommen Sie an die Daten? Wird es vom Benutzer generiert oder Sie erhalten die Daten von Dritten? Dies ist sehr wichtig, da Sie, wenn Sie Ihrem Benutzer einen Dienst mit den aus Drittanbieteranwendungen (z. B. FB, Twitter usw.) aggregierten Daten anbieten, in die Master-Datenbank schreiben und die Daten in Slave-Datenbanken replizieren können die jeweils Tomcat-Instanzen zugeordnet sind. Dann kann jeder Tomcat-Server aus seiner eigenen Slave-Datenbank beziehen.

 Are there faster alternatives to Mysql?

Sie können sich für MySQL-Cluster mit speicherinternem Datenspeicher entscheiden. Beachten Sie jedoch, dass die Anwendung möglicherweise einige Änderungen benötigt. Die sql joinswerden in MySQL Cluster nicht gut unterstützt, obwohl es in der neuesten Version Verbesserungen dafür gibt. Wenn die Kosten keine Rolle spielen, können Sie Oracle ausprobieren.

Die Caching-Lösung wird auf jeden Fall die Leistung verbessern. Aber dann hängt alles von der Architektur der gesamten Anwendung ab. Sie sollten sich darüber im Klaren sein, wann Sie Daten in den Cache übertragen und wann Sie sie verschmutzen (aus dem Cache entfernen).

In Bezug auf die Verteilung der Last in einer Umgebung mit mehreren Servern würde ich vorschlagen, dass Sie Load Balancer verwenden, anstatt Apache für den Lastenausgleich zu verwenden.

Chandra
quelle
"Ich würde vorschlagen, dass Sie Load Balancer verwenden, anstatt Apache für den Lastausgleich zu verwenden." Welchen Ansatz / welche Software würden Sie vorschlagen, wenn nicht Apache?
Kshitiz Sharma
Grundsätzlich empfahl ich Load-Balancer-Hardware, die Ihr Netzwerkadministrator konfigurieren kann. Dieser Vorgang verursacht zusätzliche Kosten für das Projekt. Dieser Load Balancer hat eine eigene IP (auch virtuelle IP genannt) und im Grunde weisen Sie diese IP Ihrer Domain zu. Wenn die Anfrage eintrifft, wird sie im Round-Robin-Verfahren (auch andere verfügbare Algorithmen) an alle verbundenen Server weitergeleitet. Sie können Apache für diesen Zweck verwenden, wenn Hardware keine Option ist, aber ich würde Hardware vorziehen, da Sie Apache nicht nur für diesen Zweck optimieren müssen.
Wir verwenden einen dedizierten Server mit httpd, um dasselbe zu tun. Hardware ist kein Problem.
Kshitiz Sharma
Sie können httpd und mod_cluster verwenden, wenn ich mich richtig erinnere. Ich würde sorgfältig prüfen, bevor ich zur "Overkill" -Lösung von Hardware LB gehe, bevor ich httpd und mod_cluster überprüfe
@ zaske - Du hast wahrscheinlich recht, dass der Hardware Load Balancer vielleicht ein Overkill ist. Wenn Sie jedoch skalieren müssen, können Sie ganz einfach weitere Server hinzufügen.
2

Ich richte gerade ein ähnliches System ein (auf professioneller Ebene), und dies ist das Design, das ich gewählt habe:

  • Zwei Nginx-Loadbalancer (beide aktiv, beide Failover für den anderen, ausgeglichen mit DNS-Round-Robin)
  • Zwei MySQL-Datenbanken im Master-Master-Replikationsmodus
  • Zwei Tomcat-Instanzen als Tomcat-Cluster
  • Zwei zwischengespeicherte Instanzen für Caching und Sitzungsstatusfreigabe für den Tomcat-Cluster

Dadurch wird eine redundante, hochverfügbare und skalierbare Lösung erreicht.

Die Loadbalancer (auf vernünftiger Hardware) können problemlos jeweils eine gesättigte 1-GBit-Leitung ausgleichen. Dies ist auch ein großartiger Ort für das SSL-Offloading.

Sie können Ihre Sitzungsinformationen in memcached speichern. Wenn eine Tomcat-Instanz ausfällt, kann eine andere Tomcat-Instanz relevante Sitzungsinformationen abrufen, und die Clients bemerken nichts. Vergessen Sie nicht, dies auch mit Sticky Sessions zu kombinieren. (Um den Netzwerkverkehr gering zu halten)

Tomcat-Clustering bietet auch die Option, Sitzungsinformationen in Echtzeit für den Cluster freizugeben, ohne Memcached zu verwenden. Obwohl ich die Leistung für sinnvoll halte, ist die Verwendung von Memcached besser.

Wenn Sie in einer dieser Anwendungen mehr Leistung benötigen:

  • Nginx: Fügen Sie weitere Loadbalancer hinzu, obwohl ich nicht glaube, dass dies sehr bald der Engpass sein wird.
  • Tomcat: Sie können den Tomcat-Cluster problemlos vergrößern oder weitere Cluster hinzufügen
  • MySQL: Fügen Sie einige schreibgeschützte Slaves hinzu oder erhöhen Sie die Clustergröße (abhängig von Ihrer Anwendung, aber da Sie eine REST-basierte Anwendung geschrieben haben, sollte dies kein Problem sein).
  • Memcached: Füge mehr Knoten hinzu, Memcached skaliert, glaube ich, ziemlich gut.

Ich weiß nicht, wie Ihre Anwendung aufgebaut ist und wie hoch die Ressourcenbelastung ist, aber wenn Sie eine hohe Datenbanklast (während Ihrer Belastungstests!) Feststellen, kann das Hinzufügen eines Caches zwischen der Anwendung und der Datenbank die Leistung erheblich verbessern. Aber vergessen Sie nicht, dass nicht alles zwischengespeichert werden kann. Wenn Ihre Abfragen immer unterschiedlich sind, hilft das Zwischenspeichern nicht (viel).

Mein Rat wäre, VMware Workbench (oder eine ähnliche Virtualisierungssoftware) herunterzuladen und zu versuchen, ein einfaches Setup zu erstellen. Kein Loadbalancing oder Clustering, nur die Grundlagen und die Arbeit von dort. Fügen Sie nacheinander weitere Funktionen hinzu (Balancing, Caching, Clustering usw.) und stellen Sie sicher, dass Sie zu jedem Thema Nachforschungen anstellen, damit Sie wissen, dass Sie die richtige Wahl getroffen haben.

Wenn Sie während dieses Vorgangs immer wieder dieselben Leistungstests durchführen, können Sie selbst feststellen, ob die Verwendung von X in Ihrem Setup besser ist als die Verwendung von Y , oder welche Auswirkungen das Caching usw. hat.

Letztendlich hängt ein solches Setup wirklich von den Anforderungen Ihrer Anwendung und ihrer Kunden ab. Alles kann auf verschiedene Arten durchgeführt werden, wobei jede ihre eigenen Stärken und Schwächen hat.

Sonst noch Fragen?

Viel Glück!

Wesley

Wesley
quelle
Hazelcast? hazelcast.com
NimChimpsky
Verwenden Sie ein Framework für die Caching-Ebene oder nur einige manuelle Hashes für SQL-Abfragen?
Djechlin