RelSysSS15 P1

Aus Verteilte Systeme - Wiki
Wechseln zu: Navigation, Suche

Projektbeschreibung

In diesem Projekt soll eine Architektur entwickelt werden, welches ein oder mehrere verlässliche Webservices bereitstellt. Die Verlässlichkeit soll durch ein Failover-Cluster des Webservices gegeben sein. Der Ausfall eines Webservices soll vor dem Benutzer maskiert und automatisch auf den Backup-Service umgeschaltet werden. Die Webservices sollen sich dabei an die Webservice-Standards des W3C (World Wide Web Consortium) und der OASIS (Organization for the Advancement of Structured Information Standards) halten.

Recherche

Fehlermaskierung von Serverausfällen

Um die Verlässlichkeit eines Webservices zu erhöhen, ist es notwendig ein Failover-Cluster einzurichten. Beim Ausfall des Primärservers wird automatisch auf den Backupserver geschwenkt.

Nun kann man generell zwischen 2 Möglichkeiten Unterscheiden:

  • Der Client erkennt den Fehler und kennt weitere (Backup-)Server, die den gleichen Service anbieten
  • Der Fehler wird vor dem Client maskiert und er erreicht einen Backupserver unter der gleichen URI.

Ziel dieses Projekts ist es jegliche Ausfälle durch Redundanz zu vermeiden und Fehler vor einem Benutzer zu maskieren. Da ein Benutzer bei einem maskierten Fehler weiterhin die gleiche URI anpsricht, existieren folgende Möglichkeiten bei einem Clusterschwenk:

  1. Der DNS-Eintrag des Webservices wird angepasst und auf den Backupserver verwiesen.
  2. Ein Proxy-Server wird vor das Cluster geschaltet. Der Proxy-Server leitet die Anfrage dann zum Primär- oder Backup-Server weiter.
  3. Es wird ein virtuelle IP-Adresse (VIP) für den Webservice eingerichtet. Diese wird dem Pirmär-Server zugewiesen. Im Fehlerfall übernimmt der Backup-Server die VIP.

Die erste Möglichkeit eignet sich nicht für einen schnellen Clusterschwenk, denn der Client cached den DNS-Eintrag lokal bis zu 24h. Im zweiten Fall würde das Problem vom Webservice-Cluster auf den Proxy-Server verlagert werden. Denn auch der Proxy-Server muss Ausfallsicher konzipiert werden. Die dritte Möglichkeit einen Ausfall zu maskieren, ist eine weit verbreitete Methode. Diese Möglichkeit wird für das Projekt näher analysiert.

Virtuelle IP-Adresse

Jeder Server in einem Cluster besitzt seine eigene IP-Adresse. Eine virtuelle IP-Adresse ist eine dynamische IP-Adresse die in einem Cluster dem aktiven Server zugewiesen wird. Der aktive Server besitzt dann zwei IP-Adressen. Von außen wird der Cluster immer über die virtuelle IP-Adresse angesprochen, so dass automatisch das aktive System erreicht wird. Im Falle eines Failover wird ein Standby-System aktiviert und erhält nun die virtuelle IP-Adresse.

Clustering-Tools

Klassischerweise unterteilt sich das Cluster-Management in die beiden Komponenten Cluster Communication Management (CCM) und Cluster Resource Management (CRM). [1] Die CCM-Komponenten stellen die Kommunikation zwischen den Clusternodes sicher. Die CRM-Komponente verwaltet die Ressourcen, welche im Cluster geschwenkt werden sollen. Bei einer Erkennung eines Ausfalls mit Hilfe der CCM-Komponente, deligiert der Ressource Manager dauraufhin das Aktivwerden einer Backup-Node und deren Cluster-Ressourcen. Es existieren mehrere OpenSource Projekte, welche sich mit Linux-Clustern beschäftigen. Für den Einsatz als CCM-Komponenten haben sich folgende Projekte etabliert:

Heartbeat
Heratbeat war eins er ersten Protokolle, welche dazu genutzt werden, um den Betriebszustand zwischen zwei Clusternodes zu benachrichtigen. Zu Beginn war es nur Möglich zwischen 2 Nodes den Zustand zu benachrichtigen. Seit einigen Jahren ist es auch Möglich mehr als 2 Nodes in einem Cluster mit Heartbeat zu betreiben.
Corosync
Corosync bietet auch die Möglichkeit für die Kommunikation mehrerer Cluster-Nodes. ZUsätzlich bietet es noch einige Features wie beispielsweise Distributed Locking.
VRRPd
VRRPd (Virtual Router Redundancy Protocol daemon) ist eine Implementierung des Virtual Router Redundancy Protocol (VRRP). Es wird dazu genutzt um eine VIP über Clusternodes zu organisieren.

Als CRM-Systeme hat die Recherche folgende Projekte aufgezeigt:

Pacemaker

Ist ein Cluster Ressource Manager, welcher zur Kommunikation Heartbeat oder Corosync nutzen kann. Man könnte

Keepalived

Keepalived setzt auf das PRRP.

Speichersysteme

Um einen Webservice verlässlich zu konzipieren, muss ggf. auch auf persistente Daten zugegriffen werden. Auf diese muss auch verlässlich zugegriffen werden können.

Datenbanken

Eine Möglichkeit Daten über mehrere Clusternodes erreichbar zu machen, ist der Einsatz von Datenbankmanagementsystemen (DBMS). Dieses muss natürlich auch Ausfallsicher konzipiert werden.

Netzwerk-Dateisysteme

Netzwerk Dateisysteme wie NFS oder CIFS bieten allen Clusternodes die Möglichkeit auf ein Dateisystem zuzugreifen, allerdings ist auch hier wie bei den Datenbanken ein Server zwischengeschaltet, welcher einen Single-Point of Failure darstellt.

Cluster-Dateisysteme

Besser eignen sich Clusterdateisysteme wie GFS2 (Globa File System 2) oder OCFS2 (Oracle Cluster File System 2). Auf ein Cluster-Dateisystem greifen alle im Cluster befindlichen Rechner direkt ohne Vermittlung eines Servers zu. Durch den direkten Zugriff wird eine wesentlich höhere Performance erreicht. Um eine schnelle synchronistaion zu gewährleisten wir in der Regel durch den Aufbau eines SAN auf der Basis von Fibre Channel oder iSCSI erreicht.

DRBD

Eine günstigere alternative zu Cluster Dateisystemen ist DRBD (Distributed Replicated Block Device). Dabei handelt es sich um eine freie Netzwerkspeicherlösungs-Software. Alle Schreibzugriffe auf ein Block Device der primary Node werden direkt auf die Backupnodes gespiegelt. Damit die Daten synchron auf allen Nodes vorhanden sind, erstellt DRBD ein virtuelles Gerät (/dev/drbdX) welches erst alle Schreibzugriffe nach oben hin bestätigt, wenn sie auch auf den anderen Nodes durchgeführt wurden.

Webservice

Bei dem Projekt sollen SOAP-Webservices eingesetzt werden, die in Java implementiert werden. Hierzu

einzelne Jar-Datei

Mit Hilfe von Java-APIs wie JAX-WS lassen sich schnell einfache Webservices generieren. Nach der Implementierung erhällt man eine Jar-Datei, die auf dem Server ausgeführt wird. Um den Webservice als Cluster Ressource anbieten zu können, muss es für den CRM eine Skript geben, mit dem man den Webservice Starten, Stoppen und Monitoren kann. Eine gute Möglichkeit dies zu tun ist mit Hilfe des Java Service Wrapper.

Web/Application Server

Alternativ kann die Java-Anwendung auf einem Web- oder Applicationsever ausgeführt werden. Bekannte Anwendungen sind:

  • Jetty
  • Tomcat
  • Oracle Weblogic
  • IBM Websphere

Grobkonzept

Für das Projekt wird ein Cluster-Verbund auf Basis von Pacemaker und Corosync realisiert. Um Daten persistent bereit zustellen, wird DRBD verwendet. Der genaue Aufbau der Grobkonzept wird hier erläutert: RelSysSS15_P1/Grobkonzept

Prototyp des Grobkonzepts

Das Grobkonzept wurde mit Hilfe eines Prototypen getestet: RelSysSS15_P1/Prototyp1


Analyse des Grobkonzepts

Pacemaker/Corosync

Mit Hilfe von Pacemaker und Corosync lassen sich Cluster-Ressourcen komfortabel schwenken. Es können auch komplexe Abhängigkeiten realisiert werden:

  • Es können Gruppen gebildet werden. Beispiel: Der Webservice und die VIP des Webservice müssen sich auf der gleichen Clusternode befinden.
  • Es können Startreihenfolgen festgelegt werden. Beispiel: Das DRBD-Dateisystem muss gemountet sein, bevor der Webservice gestartet wird.

Verzögerung beim Clusterschwenk

Ein Clusterschwenk ist mit dem Prototypen möglich, allerdings kommt steht dabei der Dienst kurzzeitig nicht zur Verfügung. In der nachfolgenden Konsolenausgabe wurde ein Test gestartet, in dem jede Sekunde die Funktion HelloWorld auf dem Cluster aufgerufen wird. Um zu erkennen welche Node gerade aktiv ist, wird zusätzlich der Hostname mitgeteilt. In dem Beispiel erkennt man, dass zu Beginn die Node rs1-02 aktiv ist. Anschließend wird auf die Node rs1-01 geschwenkt. Während des Clusterschwenks sieht man, dass das Cluster für 2 Sekunden nicht erreichbar ist (java.net.ConnectException: Connection refused).

Hello David Broll! I'm Host  rs1-02.
Hello David Broll! I'm Host  rs1-02.
Hello David Broll! I'm Host  rs1-02.
Hello David Broll! I'm Host  rs1-02.
Fehler beim Ausführen der Webservice-Funktion: java.net.ConnectException: Connection refused
Fehler beim Ausführen der Webservice-Funktion: HTTP-Transportfehler: java.net.ConnectException: Connection refused
Hello David Broll! I'm Host  rs1-01.
Hello David Broll! I'm Host  rs1-01.
Hello David Broll! I'm Host  rs1-01.
Hello David Broll! I'm Host  rs1-01.

Problem mit aktiven Verbindungen

Ziel dieses Projekts ist es Ausfälle nach außen hin zu maskieren. Dies funktioniert mit dem Prototypen aus dem Grobkonzept in den meisten Fällen problemlos. Eine Außnahme bilden allerdings aktive Verbindungen. Diese gehen bei einem Clusterschwenk verloren.

Mit der aktuellen Konfiguration lässt sich dieses Problem nicht lösen. Größere Appliktationsserver wie Oracle Weblogic bieten hier entsprechende Lösungen und replizieren bestehende HTTP-Sessions auf die anderen Clusternodes.

Möglichkeiten die getestet werden können:

  • Applikationsserver mit Session Replication
  • Asynchrone Webservices und den Callback Aufruf persistent zwischenspeichern
  • Hazelcast mit Tomcat oder Jetty
  • Einsatz des Webservice Standards WS-Reliable Messaging, um verlorene Verbindung wieder aufzubauen.

HTTP-Session Replication

In einem ersten Versuch wurde versucht das Problem mittels Session Replication zu lösen. Hierzu wurde der Webservice modifiziert, sodass er als War-Datei compiliert wird. Außerdem wurde eine entsprechende Jetty-Umgebung aufgesetzt. Der Quellcode ist hier zu finden: Service1 als War-Datei

Anfangs bestand die Idee Hazelcast[2] einzusetzen. Hazelcast bietet die Möglichkeit Session Replication in Jetty oder Tomcat zu integrieren. Allerdings ist die Funktionalität Session Replication nicht in der Open Source Version vorhanden. Stattdessen sollte versucht werden Ininispan einzusetzen. Inifispan ist eine Opensource-Software für einen verteilten Cache. Es wird auch im Applikationsserver Wildfly eingesetzt um Session Replication umzusetzen. Es existiert auch ein Modul für Jetty[3].

Während der Integration von Infinispan in Jetty wurde allerdings klar, dass das eigentliche Problem nicht die HTTP-Session sind. Eine HTTP-Session wird dazu verwendet um einen Client über mehrere HTTP-Requests hinweg zu identifizieren. Beispielsweise für den Warenkorb in einem Online-Shop. In unserem Konzept verwenden wir synchrone Webservices. Das heißt ein Aufruf entspricht einem HTTP-Request. Das heißt wir versuchen den Abbruch eines HTTP-Requests zu vermeiden und nicht einer HTTP-Session. Der Einsatz von Session Replication würde keinen Mehrwert für dieses Problem bringen. Aus diesem Grund wurde dieser Lösungsansatz nicht weiter verfolgt.

WS-ReliableMessaging

Ein weiterer Lösungsansatz der verfolgt wurde, ist der Einsatz des OASIS-Standards Reliable Messaging(WS-RM). Reliable Messaging beschreibt ein Protokoll, welches erlaubt Nachrichten sicher zwischen zwei Nodes zu übertragen, auch bei Komponenten-, System oder Netzwerkfehlern.[4] Das Protokoll nutzt hierzu die Protokolle SOAP und WSDL. Dabei wird auf Sender- und Empfängerseite je ein Vermittler auf Middleware-Ebene dazwischengeschaltet.

Rs1 ws-rm overview.gif


Der WS-RM Standard schreibt nicht vor wie es technisch gelöst werden soll. Für die Realisierung wurde das Framework Apache CXF eingesetzt. Dieser unterstützt WS-RM [5].

Bei einem Test wurde wieder der Hello World Webservice verwendet und um Reliable Messaging erweitert. Dabei wurde die Antwort des Webservice künstlich um 10s verzörgert. Dabei kann man in den Logs verfolgen, dass der Client alle 4 Sekunden um eine Antwort bittet:

Konsolenausgabe des Clients beim Aufruf der HelloWorld Funktion:

INFORMATION: Outbound Message
---------------------------
ID: 1
Address: http://localhost:8080/ws/hello
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml
Headers: {Accept=[*/*], SOAPAction=["http://schemas.xmlsoap.org/ws/2005/02/rm/CreateSequence"]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><Action xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2005/02/rm/CreateSequence</Action><MessageID xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:uuid:d493bde8-92b9-40c1-9426-58e54994ddb9</MessageID><To xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://localhost:8080/ws/hello</To><ReplyTo xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</Address></ReplyTo></soap:Header><soap:Body><ns1:CreateSequence xmlns:ns1="http://schemas.xmlsoap.org/ws/2005/02/rm"><CreateSequence xmlns="http://schemas.xmlsoap.org/ws/2005/02/rm" xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"><AcksTo><ns2:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</ns2:Address></AcksTo><Expires>PT0S</Expires><Offer><Identifier>urn:uuid:553d8603-f05a-47a4-ab01-59ce645221f4</Identifier><Expires>PT0S</Expires></Offer></CreateSequence></ns1:CreateSequence></soap:Body></soap:Envelope>
--------------------------------------
Jul 22, 2015 6:48:58 PM org.apache.cxf.services.SequenceAbstractService.SequenceAbstractSoapPort.SequenceAbstractPortType
INFORMATION: Inbound Message
----------------------------
ID: 1
Response-Code: 200
Encoding: UTF-8
Content-Type: text/xml;charset=UTF-8
Headers: {content-type=[text/xml;charset=UTF-8], Server=[Jetty(8.1.14.v20131031)], transfer-encoding=[chunked]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><Action xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2005/02/rm/CreateSequenceResponse</Action><MessageID xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:uuid:8323a7f8-0ac2-4e97-8761-245f3ca9da6f</MessageID><To xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</To><RelatesTo xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:uuid:d493bde8-92b9-40c1-9426-58e54994ddb9</RelatesTo></soap:Header><soap:Body><ns1:CreateSequenceResponse xmlns:ns1="http://schemas.xmlsoap.org/ws/2005/02/rm"><CreateSequenceResponse xmlns="http://schemas.xmlsoap.org/ws/2005/02/rm" xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"><Identifier>urn:uuid:aa8e59dc-9aa0-4a60-8a81-0a24b22943d4</Identifier><Expires>PT0S</Expires><Accept><AcksTo><ns2:Address>http://localhost:8080/ws/hello</ns2:Address></AcksTo></Accept></CreateSequenceResponse></ns1:CreateSequenceResponse></soap:Body></soap:Envelope>
--------------------------------------
Jul 22, 2015 6:48:58 PM org.apache.cxf.ws.rm.soap.RMSoapInterceptor updateServiceModelInfo
INFORMATION: Updating service model info in exchange
Jul 22, 2015 6:48:58 PM org.apache.cxf.services.HelloWorldService.HelloWorldPort.HelloWorld
INFORMATION: Outbound Message
---------------------------
ID: 2
Address: http://localhost:8080/ws/hello
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml
Headers: {Accept=[*/*], SOAPAction=[""]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><Action xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://sr1.rs.bv.org/HelloWorld/getHelloWorldAsString</Action><MessageID xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:uuid:5c0b29a0-1661-4adf-8f95-ce456c4eba7d</MessageID><To xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://localhost:8080/ws/hello</To><ReplyTo xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</Address></ReplyTo><wsrm:Sequence soap:mustUnderstand="1" xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsrm="http://schemas.xmlsoap.org/ws/2005/02/rm"><wsrm:Identifier>urn:uuid:aa8e59dc-9aa0-4a60-8a81-0a24b22943d4</wsrm:Identifier><wsrm:MessageNumber>1</wsrm:MessageNumber></wsrm:Sequence></soap:Header><soap:Body><ns1:getHelloWorldAsString xmlns:ns1="http://sr1.rs.bv.org/"></ns1:getHelloWorldAsString></soap:Body></soap:Envelope>
--------------------------------------
Jul 22, 2015 6:49:02 PM org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl$3 resend
INFORMATION: WS-RM retransmission of message 1.
Jul 22, 2015 6:49:08 PM org.apache.cxf.services.HelloWorldService.HelloWorldPort.HelloWorld
INFORMATION: Inbound Message
----------------------------
ID: 2
Response-Code: 200
Encoding: UTF-8
Content-Type: text/xml;charset=UTF-8
Headers: {content-type=[text/xml;charset=UTF-8], Server=[Jetty(8.1.14.v20131031)], transfer-encoding=[chunked]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><Action xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://sr1.rs.bv.org/HelloWorld/getHelloWorldAsStringResponse</Action><MessageID xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:uuid:756d54c4-2b3a-4797-9b54-51ee7a1314bb</MessageID><To xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</To><RelatesTo xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:uuid:5c0b29a0-1661-4adf-8f95-ce456c4eba7d</RelatesTo><wsrm:Sequence soap:mustUnderstand="1" xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsrm="http://schemas.xmlsoap.org/ws/2005/02/rm"><wsrm:Identifier>urn:uuid:553d8603-f05a-47a4-ab01-59ce645221f4</wsrm:Identifier><wsrm:MessageNumber>1</wsrm:MessageNumber></wsrm:Sequence><wsrm:SequenceAcknowledgement xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsrm="http://schemas.xmlsoap.org/ws/2005/02/rm"><wsrm:Identifier>urn:uuid:aa8e59dc-9aa0-4a60-8a81-0a24b22943d4</wsrm:Identifier><wsrm:AcknowledgementRange Lower="1" Upper="1"/></wsrm:SequenceAcknowledgement></soap:Header><soap:Body><ns1:getHelloWorldAsStringResponse xmlns:ns1="http://sr1.rs.bv.org/"><result>Hello WorldI'm Host  Davids-MacBook-Pro.local.</result></ns1:getHelloWorldAsStringResponse></soap:Body></soap:Envelope>
--------------------------------------
Server said: Hello WorldI'm Host  Davids-MacBook-Pro.local.


Wird während dieser 10 Sekunden der Webservice beendet und wieder gestartet, wird die Anfrage des Clients vom Server abgewiesen. Der Grund ist, dass jeder Webserviceaufruf und jede Nachricht eine eindeutige ID erhält. Nach einem Neustart des Webservices, kennt er die alte ID nicht mehr und sendet dem Client eine Fehlermeldung: "Identifier is not a known Sequence identifier." Eine Möglichkeit dieses Problem zu umgehen, wurde nicht gefunden. Daher eignet sich WS-RM nicht für diese Problematik.

Konsolenausgabe des Clients beim Abbruch der Serververarbeitung:

INFORMATION: Outbound Message
---------------------------
ID: 1
Address: http://localhost:8080/ws/hello
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml
Headers: {Accept=[*/*], SOAPAction=["http://schemas.xmlsoap.org/ws/2005/02/rm/CreateSequence"]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><Action xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2005/02/rm/CreateSequence</Action><MessageID xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:uuid:6952dd17-6667-40d8-a873-8fcbd807f281</MessageID><To xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://localhost:8080/ws/hello</To><ReplyTo xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</Address></ReplyTo></soap:Header><soap:Body><ns1:CreateSequence xmlns:ns1="http://schemas.xmlsoap.org/ws/2005/02/rm"><CreateSequence xmlns="http://schemas.xmlsoap.org/ws/2005/02/rm" xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"><AcksTo><ns2:Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</ns2:Address></AcksTo><Expires>PT0S</Expires><Offer><Identifier>urn:uuid:5c2654a7-4516-48d1-9baf-fbf03a1f88e3</Identifier><Expires>PT0S</Expires></Offer></CreateSequence></ns1:CreateSequence></soap:Body></soap:Envelope>
--------------------------------------
Jul 22, 2015 8:50:55 PM org.apache.cxf.services.SequenceAbstractService.SequenceAbstractSoapPort.SequenceAbstractPortType
INFORMATION: Inbound Message
----------------------------
ID: 1
Response-Code: 200
Encoding: UTF-8
Content-Type: text/xml;charset=UTF-8
Headers: {content-type=[text/xml;charset=UTF-8], Server=[Jetty(8.1.14.v20131031)], transfer-encoding=[chunked]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><Action xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2005/02/rm/CreateSequenceResponse</Action><MessageID xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:uuid:38d91c42-5054-438b-b803-0c2ae720f9e1</MessageID><To xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</To><RelatesTo xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:uuid:6952dd17-6667-40d8-a873-8fcbd807f281</RelatesTo></soap:Header><soap:Body><ns1:CreateSequenceResponse xmlns:ns1="http://schemas.xmlsoap.org/ws/2005/02/rm"><CreateSequenceResponse xmlns="http://schemas.xmlsoap.org/ws/2005/02/rm" xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing"><Identifier>urn:uuid:c2f9e77c-61e4-4e4d-87b5-5a528a498ead</Identifier><Expires>PT0S</Expires><Accept><AcksTo><ns2:Address>http://localhost:8080/ws/hello</ns2:Address></AcksTo></Accept></CreateSequenceResponse></ns1:CreateSequenceResponse></soap:Body></soap:Envelope>
--------------------------------------
Jul 22, 2015 8:50:55 PM org.apache.cxf.ws.rm.soap.RMSoapInterceptor updateServiceModelInfo
INFORMATION: Updating service model info in exchange
Jul 22, 2015 8:50:55 PM org.apache.cxf.services.HelloWorldService.HelloWorldPort.HelloWorld
INFORMATION: Outbound Message
---------------------------
ID: 2
Address: http://localhost:8080/ws/hello
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml
Headers: {Accept=[*/*], SOAPAction=[""]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><Action xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://sr1.rs.bv.org/HelloWorld/getHelloWorldAsString</Action><MessageID xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:uuid:dc1e6519-5dec-447e-8fec-caa7c409cf98</MessageID><To xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://localhost:8080/ws/hello</To><ReplyTo xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><Address>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</Address></ReplyTo><wsrm:Sequence soap:mustUnderstand="1" xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsrm="http://schemas.xmlsoap.org/ws/2005/02/rm"><wsrm:Identifier>urn:uuid:c2f9e77c-61e4-4e4d-87b5-5a528a498ead</wsrm:Identifier><wsrm:MessageNumber>1</wsrm:MessageNumber></wsrm:Sequence></soap:Header><soap:Body><ns1:getHelloWorldAsString xmlns:ns1="http://sr1.rs.bv.org/"></ns1:getHelloWorldAsString></soap:Body></soap:Envelope>
--------------------------------------
Jul 22, 2015 8:50:59 PM org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl$3 resend
INFORMATION: WS-RM retransmission of message 1.
Jul 22, 2015 8:50:59 PM org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl resend
SCHWERWIEGEND: WS-RM retransmission failed.
java.net.SocketException: SocketException invoking http://localhost:8080/ws/hello: Unexpected end of file from server
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
	at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.mapException(HTTPConduit.java:1339)
	at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1323)
	at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
	at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:628)
	at org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl.resend(RetransmissionQueueImpl.java:476)
	at org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl.clientResend(RetransmissionQueueImpl.java:366)
	at org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl.access$400(RetransmissionQueueImpl.java:79)
	at org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl$3.resend(RetransmissionQueueImpl.java:765)
	at org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl$ResendCandidate.run(RetransmissionQueueImpl.java:574)
	at org.apache.cxf.workqueue.SynchronousExecutor.execute(SynchronousExecutor.java:37)
	at org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl$ResendCandidate.initiate(RetransmissionQueueImpl.java:562)
	at org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl$ResendCandidate$1ResendTask.run(RetransmissionQueueImpl.java:721)
	at java.util.TimerThread.mainLoop(Timer.java:555)
	at java.util.TimerThread.run(Timer.java:505)
Caused by: java.net.SocketException: Unexpected end of file from server
	at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:776)
	at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:633)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1324)
	at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:468)
	at org.apache.cxf.transport.http.URLConnectionHTTPConduit$URLConnectionWrappedOutputStream.getResponseCode(URLConnectionHTTPConduit.java:266)
	at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1531)
	at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1504)
	at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1310)
	... 12 more

Jul 22, 2015 8:50:59 PM org.apache.cxf.phase.PhaseInterceptorChain doDefaultLogging
WARNUNG: Interceptor for {http://sr1.rs.bv.org/}HelloWorldService#{http://sr1.rs.bv.org/}getHelloWorldAsString has thrown exception, unwinding now
org.apache.cxf.interceptor.Fault: Could not send Message.
	at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:64)
	at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
	at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:565)
	at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:474)
	at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:377)
	at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:330)
	at org.apache.cxf.frontend.ClientProxy.invokeSync(ClientProxy.java:96)
	at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:135)
	at com.sun.proxy.$Proxy36.getHelloWorldAsString(Unknown Source)
	at org.bv.rs.sr1Client.HelloWorldClient.main(HelloWorldClient.java:28)
Caused by: java.net.SocketException: SocketException invoking http://localhost:8080/ws/hello: Unexpected end of file from server
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
	at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.mapException(HTTPConduit.java:1339)
	at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1323)
	at org.apache.cxf.io.CachedOutputStream.close(CachedOutputStream.java:221)
	at org.apache.cxf.io.CacheAndWriteOutputStream.postClose(CacheAndWriteOutputStream.java:50)
	at org.apache.cxf.io.CachedOutputStream.close(CachedOutputStream.java:223)
	at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
	at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:628)
	at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
	... 9 more
Caused by: java.net.SocketException: Unexpected end of file from server
	at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:776)
	at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:633)
	at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1324)
	at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:468)
	at org.apache.cxf.transport.http.URLConnectionHTTPConduit$URLConnectionWrappedOutputStream.getResponseCode(URLConnectionHTTPConduit.java:266)
	at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1531)
	at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1504)
	at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1310)
	... 15 more

Jul 22, 2015 8:51:03 PM org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl$3 resend
INFORMATION: WS-RM retransmission of message 1.
Jul 22, 2015 8:51:07 PM org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl$3 resend
INFORMATION: WS-RM retransmission of message 1.
Jul 22, 2015 8:51:11 PM org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl$3 resend
INFORMATION: WS-RM retransmission of message 1.
Jul 22, 2015 8:51:11 PM org.apache.cxf.services.HelloWorldService.HelloWorldPort.HelloWorld
INFORMATION: Inbound Message
----------------------------
ID: 2
Response-Code: 500
Encoding: UTF-8
Content-Type: text/xml;charset=UTF-8
Headers: {content-type=[text/xml;charset=UTF-8], Server=[Jetty(8.1.14.v20131031)], transfer-encoding=[chunked]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><Action xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing/fault</Action><MessageID xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:uuid:01f11697-26db-4f28-9da2-3f110630e73c</MessageID><To xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</To><RelatesTo xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:uuid:dc1e6519-5dec-447e-8fec-caa7c409cf98</RelatesTo><wsrm:SequenceFault xmlns:ns2="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsrm="http://schemas.xmlsoap.org/ws/2005/02/rm"><wsrm:FaultCode>wsrm:UnknownSequence</wsrm:FaultCode><wsrm:Identifier xmlns="http://schemas.xmlsoap.org/ws/2005/02/rm">urn:uuid:c2f9e77c-61e4-4e4d-87b5-5a528a498ead</wsrm:Identifier></wsrm:SequenceFault></soap:Header><soap:Body><soap:Fault><faultcode>soap:Client</faultcode><faultstring>The value of wsrm:Identifier is not a known Sequence identifier.</faultstring></soap:Fault></soap:Body></soap:Envelope>
--------------------------------------
Jul 22, 2015 8:51:11 PM org.apache.cxf.ws.rm.RMInInterceptor handle
INFORMATION: deferred uncorrelated message abort
javax.xml.ws.soap.SOAPFaultException: The value of wsrm:Identifier is not a known Sequence identifier.
	at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:157)
	at com.sun.proxy.$Proxy36.getHelloWorldAsString(Unknown Source)
	at org.bv.rs.sr1Client.HelloWorldClient.main(HelloWorldClient.java:28)
Caused by: org.apache.cxf.binding.soap.SoapFault: The value of wsrm:Identifier is not a known Sequence identifier.
	at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.unmarshalFault(Soap11FaultInInterceptor.java:84)
	at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.handleMessage(Soap11FaultInInterceptor.java:51)
	at org.apache.cxf.binding.soap.interceptor.Soap11FaultInInterceptor.handleMessage(Soap11FaultInInterceptor.java:40)
	at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
	at org.apache.cxf.interceptor.AbstractFaultChainInitiatorObserver.onMessage(AbstractFaultChainInitiatorObserver.java:113)
	at org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor.handleMessage(CheckFaultInterceptor.java:69)
	at org.apache.cxf.binding.soap.interceptor.CheckFaultInterceptor.handleMessage(CheckFaultInterceptor.java:34)
	at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:272)
	at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:835)
	at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1613)
	at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1504)
	at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1310)
	at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
	at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:628)
	at org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl.resend(RetransmissionQueueImpl.java:476)
	at org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl.clientResend(RetransmissionQueueImpl.java:366)
	at org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl.access$400(RetransmissionQueueImpl.java:79)
	at org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl$3.resend(RetransmissionQueueImpl.java:765)
	at org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl$ResendCandidate.run(RetransmissionQueueImpl.java:574)
	at org.apache.cxf.workqueue.SynchronousExecutor.execute(SynchronousExecutor.java:37)
	at org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl$ResendCandidate.initiate(RetransmissionQueueImpl.java:562)
	at org.apache.cxf.ws.rm.soap.RetransmissionQueueImpl$ResendCandidate$1ResendTask.run(RetransmissionQueueImpl.java:721)
	at java.util.TimerThread.mainLoop(Timer.java:555)
	at java.util.TimerThread.run(Timer.java:505)

Der Quellcode des Webservices inkl. WS-RM ist hier zu finden: Service1 mit WS-RM

Split-Brain-Problematik

Mit Hilfe von Corosync überwachen sich die Clusternodes gegenseitig. Fällt der Primärserver in einem Cluster aus, wird dies vom Backupserver erkannt und der Backupserver schaltet alle Clusterressourcen des Primärservers aktiv. Fällt der Primärserver allerdings nicht aus, sonden verliert jediglich die Netzwerkverbindung zum Backupserver, wird der Backupserver dennoch aktiv. Diesen Zustand, in dem beide Clusternodes aktiv sind, nennt man SplitBrain-Zustand. Dies kann schnell zu Inkonsistenzen bei gemeinsam genutzen Daten führen. Um dies zu verhindern, gibt es zwei Möglichketien:

Fencing [6]
Fencing bezeichnet es eine Methode, die es einer Node des Clusters erlaubt, eine andere Node - notfalls gewaltsam - aus dem Cluster auszugrenzen. [7] Eine Möglichkeit ist das sogenannte STONITH (Shoot The Other Node In The Head). Hierbei wird der Clusternode der Strom abgeschaltet, um den Zugriff auf gemeinsam genutzte Ressourcen zu verhindern. Eine sanftere Möglichkeit ist es alle Netzwerkverbindungen der Node zu trennen um sie zu isolieren. Für das Fencing benötigt man allerdings spezielle Hardware, um die Stromzufuhr aus der Ferneabschalten zu können.
Quorum
Beim Quorum entscheidet jede Node selbst, ob sie aktiv ist oder nicht. Ein Cluster hat das Quorum, wenn mehr als die Hälfte aller bekannten Nodes online sind.[8] Am besten lässt es sich anhand von einem Besipiel erklären: Ein 5-Node-Cluster zerfällt in eine 3er- und 2er-Gruppe. Die beiden Gruppen können wegen eine Netzwerkfehlers nicht mehr miteinander kommunizieren. Da die 3er-Gruppe mehr als die Hälfte aller Nodes ausmacht, schaltet eine der Nodes aktiv. Die andere Gruppe bleibt die ganze Zeit inatkiv, da es weniger als die Hälfte ausmacht. Eine vollständige Garantie ist diese Methode allerdings nicht, denn es setzt vorraus, das Pacemaker nicht abstürzt.
Damit dieses Prinzip funktioniert bei Clustern mit ungerader Node-Anzahl.

Feinkonzept

Aus den Analyse des ersten Prototypen wird nun nun ein neues Konzept erstellt.

Architektur

Ähnlich dem Grobkonzept besteht das neue Konzept aus zwei Webservices. Statt eines HellWorld-Webservices aus dem Prototypen wird nun ein Taschenrechner-Webservice implementiert. Um die Probleme der Splitbrain-Problematik zu umgehen, wird jeder Webservice zu einem 3-Node-Cluster erweitert, um das Quorum einsetzten zu können. Alternativ hätte auch STONITH eingesetzt werden können, allerdings wird diese Funktionalität in der VMware-Umgebung der HS-RM nicht unterstützt.

Sr1 Feinkonzept Architektur.png

Webservices

Um auch Abhängigkeiten zwischen Webservices in dem Konzept zu berücksichtigen, wird zur Demonstration ein Calculator-Webservice implementiert. Webservice1 (InfixCalculator) nimmt eine mathematische Operation mit den Operanden (+, -, *, /) entgegen. Diese wird in kleinere Operationen zerlegt und nacheinander an den Webservice2 (SimpleCalculator) übergeben. Das nachfolgende Sequenzdiagramm stellt den Ablauf der Berechnung von "5*8+12/6" dar:

Sr1 InfixCalculator Sequenzdiagramm.png


aktive Verbindungen

Da keine Lösungsmöglichkeit gefunden wurde, um Fehler während aktiven Verbindungen zu maskieren, werden vom Client automatisch Neuversuche gestartet. Tritt also ein Ausfall auf, versucht der Client bis zu 5 mal die Webservice-Funktion erneut aufzurufen.

  • Das Cluster wird auf 3 Nodes aufgesetzt um die Split-Brain Problematik zu vermeiden.
  • Um den Ausfall einer Ressource zu erkennen, muss zusätzlich ein Monitoring Attribut gesetzt werden.
  • Auf DRBD wird doch nicht eingesetzt, da es sich nicht für ein Cluster mit mehr als 2 Nodes eignet. Die dritte node wird nur asynchron synchronisiert.

Implementierung

Bei der Konfiguration der 6 Clusternodes wurde sich an der Installation des Prototypen gerichtet.

DRBD

Im Prototyp wurde DRBD mit 2 Clusternodes erfolgreich eingesetzt. DRBD bietet auch die Möglichkeit über mehr als zwei Clusternodes hinweg synchron zu synchronisieren[9]. Da für das Konzept kein synchroner persistenter Speicher benötigt wird, entfällt die Implementiewrung im Konzept.

Pacemaker/Corosync

Um einen Ausfall einer Cluster-Ressource (z.B. Java-Webservice) zu erkennen, muss für jede Cluster-Resspurce zusätzlich ein Monitor-Intervall definiert werden. Hierzu editieren wir die crm Konfigurationsdatei auf beiden Clustern:

sudo crm configure edit

Anschließend sollten die Ressourcen wie folgt aussehen:

primitive sr1_java lsb:service1 \
        op monitor interval="10"
primitive sr1_vip ocf:heartbeat:IPaddr2 \
        params ip="10.18.48.194" cidr_netmask="24" \
        op monitor interval="10" timeout="20"
group sr1 sr1_vip sr1_java


Da wir nun Gebrauch des Quorum machen, sollte folgender Befehl in der Anleitung NICHT ausgeführt werden:

crm configure property no-quorum-policy=ignore


Corosync kommuniziert mittels Multicast-Adressen. Da nun zwei Cluster in einem Netz betrieben werden, sollten zwei verschieden Multicast Adressen verwendet werden. Die Konfiguration wird in der Datei /etc/corosync/corosync.conf vorgenommen. Dabei muss folgender Eintrag im Webservice2 angepasst werden:

mcastaddr: 226.94.1.2

Webservices

Die Webservices werden, wie im Prototyp, mittels Java Service Wrapper als Dienst bereitsgestellt. Die Webservice besitzen folgende Übergabeparameter:

InfixCalculator.jar <publishURL> <publishURL-SimpleCalculator>
InfixCalculator.jar http://rs1-service1.vs.cs.hs-rm.de:8080/ws/InfixCalc http://rs1-service2.vs.cs.hs-rm.de:8081/ws/SimpleCalc

SimpleCalculator.jar <publishURL>
SimpleCalculator.jar http://rs1-service2.vs.cs.hs-rm.de:8081/ws/SimpleCalc

Diese werden in der Konfigurationsdatei /opt/service1/conf/wrapper.conf bzw /opt/service2/conf/wrapper.conf definiert.


Der Quellcode ist hier zu finden:

Analyse des Feinkonzepts

Nachdem das Konzept umgesetzt wurde folgt nun eine Analyse, ob die Änderung wie erhofft die Problematiken beseitigen.

aktive Verbindungen

Aktive Verbindungen gehen weiterhin verloren. Durch den automatischen Versuch die Verarbeitung bis zu 5 mal zu wiederholen, werden die meisten Fehler erfolgreich auf der Clientseite maskiert.

Der nachfolgende Auszug aus der Logdatei zeigt zeigt einen Clusterschwenk von Node rs1-01 auf rs1-02. Dabei ist zu erkennen, dass die Berechnung erst beim 3. Versuch erfolgreich war:

Konsolenausgabe des Clients beim Aufruf des Webservices "InfixCalculator" Funktion:

...
[INFO] 2015-07-29 11:53:36,543 - 10+8+1+10/8/4/3-8-3*2 = 5.104166666666668 [rs1-01]
[INFO] 2015-07-29 11:53:37,646 - 1/3-7 = -6.666666666666667 [rs1-01]
[WARN] 2015-07-29 11:53:37,663 - 9+7+9*10*2-5+1+4+6+3: Fehler beim 1. Versuch. Fehlermeldung: Kein Zugriff auf WSDL bei: http://rs1-service1.vs.cs.hs-rm.de:8080/ws/InfixCalc?wsdl. Zugriff nicht erfolgreich mit: 
	Connection refused.
[WARN] 2015-07-29 11:53:39,672 - 9+7+9*10*2-5+1+4+6+3: Fehler beim 2. Versuch. Fehlermeldung: Kein Zugriff auf WSDL bei: http://rs1-service1.vs.cs.hs-rm.de:8080/ws/InfixCalc?wsdl. Zugriff nicht erfolgreich mit: 
	Connection refused.
[INFO] 2015-07-29 11:53:43,228 - 9+7+9*10*2-5+1+4+6+3 = 177.0 [rs1-02]
[INFO] 2015-07-29 11:53:44,340 - 2/9*6 = 1.3333333333333333 [rs1-02]
[INFO] 2015-07-29 11:53:45,734 - 4+6-1+8*6*7/7+8 = -47.0 [rs1-02]
[INFO] 2015-07-29 11:53:46,962 - 5+5/10-2*3+8 = -8.5 [rs1-02]
...

Split-Brain-Problematik

Durch den Einsatz von drei Nodes pro Cluster kann die Quorum-Funktionalität genutzt werden. Um einen Netzwerkausfall zu simulieren und so eine Split-Brain-Problematik nachzustellen, wurde der Netzwerkverkehr mit iptables (bis auf Port 22 für SSH) blockiert.

Allerdings konnte die Quorum-Funktionalität erst gar nicht richtig getestet werden. Das Problem liegt hierbei bei Corosync. Corosync ist für die Kommunikation zwischen den Clusternodes zuständig und somit auch für die Erkennung, welche Clusternodes erreichbar sind und welche nicht. Bei dem Versuch eine Clusternode vom Netzwerk zu trennen, realisiert Corosync auf der Node nicht, dass die anderen Nodes nicht mehr erreichbar sind. Dadurch greift die Quorum-Regel nicht und die Ressourcen auf der Node werden nicht deaktiviert. Die anderen beiden Clusternodes merken allerdings, dass die Node mit dem deaktivierten Netzwerk nicht mehr erreichbar ist. Eine der beiden Clusternodes aktiviert dadurch auch die Ressourcen und es kommt zur Split-Brain-Problematik. Es wurde keine Möglichkeit gefunden dieses Problem zu umgehen.

Quellen

  1. HA-Serie, Teil 1: Grundlagen von Pacemaker und Co., Admin-Magazin Ausgabe vom April 2011
  2. http://hazelcast.com/ Hazelcast
  3. Session Clustering with Infinispan eclipse.org abgerufen am 4. Juli 2014
  4. Web Services Reliable Messaging (WS-ReliableMessaging) Version 1.2, oasis-open.org, abgerfuen am 9. Juli 2015
  5. WS-Reliable Messaging Apache CXF, abgerufen vom 22. Juli 2015
  6. Fencing and STONITH, Clusterlabs.org vom Juni 2013
  7. Fencing verhindert Chaos im Cluster, ADMIN Magazin Ausgabe vom März 2012
  8. Perform a Failover, Clusterlabs Documentation vom Juli 2015
  9. Creating a three-node setup, drbd.linbit.com vom 25. Juli 2015