Ich nehme derzeit an einer Akademie zum Java Fullstack Software Engineer teil. In den kommenden Wochen möchte ich hier meine Mitschrift, so gut es geht, aufzeichnen und mitteilen. Hier ist das, was ich vom siebten Tag in Block 11+12 (wir springen etwas hin und her) gelernt und behalten habe:
Load Balancing mit Apache
Unterschied zwischen Tomcat und Apache/NGINX
Java erzeugt für jeden Datei-Zugriff 5 Objekte (IO-Stream, Buffer,…). Wenn jetzt auf viele Bilder oder Dateien zugegriffen wird, ist Tomcat relativ langsam.
Apache oder NGINX sind da viel schlanker und schneller unterwegs. Sie eigenen sich vor allem für statischen Inhalt. Dafür können sie kein Java.
Aufbau eines Apache Loadbalancers
Apache liefert (in C geschriebene) Module mit. Eines davon heißt mod.proxy.so. Dieses erkennt anhand der Antwortzeiten der dahinterliegenden Systeme, wohin er die Last verteilen soll.:
Tomcat hat ein Modul für Apache entwickelt (Tomcat Collector: "ModJK"), welches mit Apache reden kann über das AJP (Apache Java Protokoll). Dort stehen Zusatzinformationen drin, anhand dessen der Loadbalancer besser erkennen kann, wie stark der jeweilige Zielserver ausgelastet ist.
Das AJP ist ein eigenes Protokoll, in welches die http-Informationen mit reingesteckt werden (Briefumschlag im Briefumschlag).
Im Apache-Conf Ordner liegt die Datei http.conf. Dort werden die Module includiert:
Hier der Inhalt von http-modjk.conf:
Dort mounte ich die Anwendung "loadbalancer".
JKMount mountet die Anwendung vom Tomcat. Damit hat Apache direkten Zugriff auf den Webapps-Ordner des Zielservers.
In der worker.properties stehen die Informationen für die Zielserver drin:
Monitoring des Loadbalancings mit http://localhost/jkstatus:
In der server.xml-Datei des jeweiligen Tomcat-Servers werden die http- und AJP-Ports definiert:
HTTP -> HTTPS-Switch (Erzwungene HTTPs-Umschaltung)
Wenn ich https erzwingen möchte, trage ich folgendes in die $TOMCAT_HOME/conf/web.xml ein:
<user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> // CONFIDENTIAL or INTEGRAL or NONE </user-data-constraint>
Das Loadbalancing funktioniert, aber wir erhalten für jeden neuen Zugriff eine neue Session-ID. Dadurch verliert ggf. der Benutzer z.B. seinen Einkaufswagen. Was wir brauchen ist nicht Loadbalancing, sondern ein Cluster (rechter oberer Teil des Bildes):
Wenn ein Benutzer auf einen Server zugreift, erstellt dieser ein Session-Objekt. Dieses schickt der Server in das Intranet und teilt den anderen Servern seine Session-ID mit.
Sobald die Server sich synchronisiert haben (das dauert ca. 5 Minuten), bleibt die Session-ID gleich, auch wenn man im Webbrowser F5 drückt (aktualisiert).
Das Cluster braucht ein gemeinsames Netzwerksegment zur Kommunikation und ein gemeinsames Volume um die Daten auszutauschen.
In der Regel entspricht ein Pod einem Container.
Hier kann es aber sein, dass ein Pod einem Cluster entspricht (rotes Viereck). Voraussetzung für ein "Loadbalancer-Cluster-Pod" ist, dass alle Dienste exakt identisch sind. (Man macht also aus drei Zollstöcken einen großen)
Das blaue Viereck besteht aus mehreren Pods und ist nicht ein einziger, da sie unterschiedliche Dienste darstellen
Hier ein Bild aus dem Internet. Für unser Beispiel bedeutet es, dass wir im Pod noch ein "Loadbalancer-Cluster" haben können:
Die Einstellungen liegen in der server.xml. Der Profi erkennt in der Adresse ein Class-D Netz, also eine Broadcast-Adresse:
Die Clusterpartner müssen entsprechend programmiert sein, da z.B. Zähler ansonsten ggf. bei jedem Clusterpartner wieder bei Null anfangen.
Der Datenaustausch erfolgt über Session-Objekte. Diese werden serialisiert und den anderen Tomcats zur Verfügung gestellt. Jedes Objekt wird einer Session-ID zugeordnet.
(Pojo-Klasse vom Typ Transient, siehe Block 3, Projekt 07: Serialisierung)
In der persinstence.xml muss JTA von local auf remotes gestellt werden
Damit eine Datei Clusterfähig wird, muss In der web.xml stehen:
<web-app> <distributable/> </web-app>
Hier noch mal eine Zusammenfassung für den Loadbalance/Cluster:
Apache LB - > Tomcat-Cluster Show-Case
LoadBalancer -> Last sinnvoll zu verteilen (d.h. keinen Datenaustausch zwischen den Knoten)
Cluster -> Last sinnvoll zu verteilen + Datenaustausch zwischen den Cluster-Knoten (Session -> Warenkorb oder auch Workflow )
Eine Cluster-Anwendung muss auch Clusterfähig programmiert sein (ACHTUNG bei LOKALEM STATUS)
D.h.
- Vorsicht bei nativen File-IO's -> Satzzeiger in der Session austauschen
- Vorsicht bei nativen DB-IO's JDBC,JPA,DAO -> JTA Resource -> REMOTE
- Static Variablen (SingleTone) -> Via Session austauschen
-> Session in SpringBoot
- https://www.javainuse.com/spring/springboot_session
- https://www.baeldung.com/spring-mvc-session-attributes
Lösungen zu den Übungsaufgaben von letztem Freitag
Lösung von Christoph zu Aufgabe 3 vom letzten Freitag: Ribbon-Server Konfiguration:
In den jeweiligen Services muss noch ein "/" zurück gegeben werden, damit der Loadbalancer die Basis-Services findet. Christoph hat dafür einen eigenen Pingcontroller gebaut:
--------------------------
Lösungsansatz von Michael zu Aufgabe 4 (Spring Appl. Ribbon-Servers als Docker-Container betreiben (Externer Port:80xx))
---------------------------------------------------------------
Frage: Ich habe ein NGINX-Docker Server auf meinem Raspberry Pi installiert. Ich kann dort auf eine index.html zugreifen. Aber nicht auf den gemounteten "foto" Ordner. Was kann ich tun?
Antwort:
Die Ursache liegt in den Sicherheitseinstellungen. Diese kann man wie folgt ändern:
NGINX subdirectories zeigen: https://www.keycdn.com/support/nginx-directory-index
————————————————-
Disclaimer
Alles was ich mitschrieb und verstanden habe ist ohne Gewähr. Die Bilder stammen teilweise aus dem Internet und wir haben keine Urheberansprüche darauf.
Besten Dank an unseren sehr empfehlenswerten
Trainer: Hans-Joachim Blanke blanke@4point.de
In den nächsten Tagen geht es weiter, so: stay tuned!
Achim Mertens