Hochverfügbarkeit einrichten

Die Standardversion des WhatsApp Business API-Client wird in einem einzelnen Docker-Container ausgeführt. Mehrere parallel ausgeführte Docker-Container verursachen Probleme und führen dazu, dass dein Konto vorübergehend gesperrt wird. Dieser Leitfaden enthält Informationen dazu, wie du die hohe Verfügbarkeit einrichtest und Docker-Container als Standby-Lösungen für den Fall nutzt, dass der primäre Docker-Container ausfällt.

Diese Hochverfügbarkeitslösung erfordert die zusätzliche Ausführung einer vorhandenen Einzelinstanz-Installation des WhatsApp Business API-Client. Wenn du deine WhatsApp Business API-Client-Telefonnummer noch nicht eingerichtet hast, lies dir die Installationsdokumentation durch, bevor du mit dieser Lösung fortfährst.

Übersicht

Ein Hochverfügbarkeits-Cluster erfordert zumindest zwei Master-Nodes und zwei Coreapp-Nodes (siehe Diagramm unten):

Hochverfügbarkeits-Cluster

Es empfiehlt sich, alle Nodes auf unterschiedlichen Rechnern/Racks auszuführen. So wird verhindert, dass bei Ausfall eines Rechners/Racks gleichzeitig mehrere Nodes betroffen sind.

Hochfahren

Wenn ein Cluster hochfährt, konkurrieren alle Master-Nodes um den Master-Lease, um der primäre Node zu werden. Nur ein Node hat Erfolg. Die anderen werden zu sekundären Master-Nodes. Ein Cluster mit N Master-Nodes enthält einen primären Master und N-1 sekundäre Master. Der primäre Master ist zuständig für Registrierung, Upgrade des Datenbankschemas, Übertragung von Konfigurationsänderungen, Reporting on Datenbankstatistiken, Cluster-Verwaltung etc. Wenn der primäre Master abstürzt und den Master-Lease verliert, konkurrieren andere sekundäre m=Master um die Position des primären Masters.

Wenn ein Master zum primären Master wird, lädt er zuerst die Shard Map-Tabelle aus der Datenbank. Dort findet er den aktuellen primären Coreapp. Wenn das Cluster keinen primären Coreapp enthält, befördert der primäre Master einen funktionsfähigen Sekundär-Coreapp zum primären Coreapp und aktualisiert die Shard Map-Tabelle in der Datenbank. Dort kann Webapp nachsehen, an welchen Coreapp-Node API-Anfragen zu senden sind. Auf diese Weise ist gewährleistet, dass API-Anfragen in den Coreapp-Nodes auch dann bearbeitet werden können, wenn alle Master ausgefallen sind. Die Hochverfügbarkeit ist damit gewährleistet.

Wenn ein Coreapp-Node hochfährt, wird er als sekundärer Coreapp ausgeführt, bis er vom primären Master zum primären Coreapp befördert wird, der mit dem WhatsApp-Server verbunden ist. Im Anschluss daran ist er für die Verarbeitung von API-Anfragen verantwortlich.

Datenbankbasierte Überwachung

Zur Bestätigung seiner Funktionsfähigkeit aktualisiert jeder Coreapp-Node im Minutentakt die Datenbank. Der primäre Master überprüft in regelmäßigen Abständen die Datenbank auf fehlerhafte Coreapp-Nodes. Wenn ein primärer Coreapp-Node die Datenbank länger als zwei Minuten nicht aktualisiert hat, betrachtet der primäre Master ihn als fehlerhaft. Dann befördert er andere Coreapp-Nodes zu primären Nodes. So ist gewährleistet, dass eine Ausfallzeit maximal zwei Minuten dauert.

Hartbeat-basierte Überwachung

Wenn ein Cluster mehr als einen aktiven Master hat, erkennt die heartbeat-basierte Überwachung Node-Ausfälle schneller als die datenbankbasierte Überwachung. Bei der heartbeat-basierten Überwachung müssen alle Master Coreapp-Nodes überwachen. Dazu senden sie im fünf-Sekunden-Takt (konfiguriert über heartbeat_interval) Heartbeat-Signale an diese Nodes. Wenn ein primärer Coreapp 30 Sekunden lang (konfiguriert über unhealthy_interval) weder dem primären Master noch einem sekundären Master geantwortet hat, wird er als fehlerhaft betrachtet. Der primäre Master befördert dann einen funktionsfähigen Coreapp zum primären Coreapp. So ist gewährleistet, dass eine Ausfallzeit standardmäßig maximal 30 Sekunden dauert. Wenn du die Ausfallzeit verkürzen möchtest, kannst du den Wert unhealthy_interval verringern. Siehe dir hierzu die Beispiel-Payloads in der Dokumentation zu den Einstellungen an.

Erst-Setup

In einem Hochverfügbarkeits-Cluster werden drei Arten von Nodes unterschieden: Webapp, Master und Coreapp. Diese Nodes könnten auf unterschiedlichen Rechnern gestartet werden, aber sie müssen sich in demselben Netzwerk befinden, damit sie untereinander kommunizieren können.

Webapp-Nodes sind für die Durchführung des API-Datenverkehrs zuständig (wie die ursprünglichen Webapp-Container). Coreapp-Nodes kümmern sich um den Messaging-Datenverkehr zu bzw. von WhatsApp. Master-Nodes schließlich sind für die Überwachung von Coreapp-Nodes im Cluster verantwortlich. Wenn beispielsweise ein Coreapp-Node nicht mehr verfügbar ist, wird der Datenverkehr an einen anderen Coreapp-Node weitergeleitet, damit die hohe Verfügbarkeit gewährleistet bleibt. Im Cluster können sich mehrere Webapp-, Coreapp- und Master-Nodes befinden.

Aktive Nodes werden nicht mehr als Slave-Nodes bezeichnet, sondern als Coreapp-Nodes.

Hinweis: In Produktionsumgebungen sollte die Datenbank in den meisten Fällen auf einem physischen Server von den Coreapp- und Webapp-Containern getrennt betrieben werden. Für echte Hochverfügbarkeit sollten Master-, Webapp- und Coreapp-Container auf unterschiedlichen physischen Rechnern ausgeführt werden.

Freigegebenes Dateisystem für Mediennachrichten einrichten

Wenn dich Mediennachrichten nicht interessieren, kannst du diesen Schritt überspringen.

Wenn das Senden und Empfangen von Mediennachrichten unterstützt werden soll, musst du ein NFS-Dateisystem einrichten und in einem lokalen Verzeichnis auf allen Webapp-, Master- und Coreapp-Nodes mounten. Im freigegebenen Verzeichnis müssen Lese- und Schreibberechtigungen gewährt werden.

Beispiel-Mount-Befehl in NFS:

mkdir new-local-directory
mount -t nfs nfs_server_IP_addr:/share_directory new-local-directory

Installation mit Docker Compose

Dieser Leitfaden erfordert Docker, eine Containerplattform, auf der der WhatsApp Business API-Client ausgeführt werden kann. Docker Compose ist ebenfalls erforderlich. Docker Compose ist im Lieferumfang von Docker für MacOS und Windows enthalten, erfordert aber eine separate Installation unter Linux.

Entwicklerkonfiguration mit einzelnem Server

  1. Installiere Docker auf deinem System.
  2. Wenn Docker Compose nicht im Lieferumfang deiner Docker-Installation enthalten ist, muss Docker Compose installiert werden.
  3. Lade die Konfigurationsdateien multiconnect-compose.yml und db.env herunter: WhatsApp_Configuration_Files.zip.
  4. #Öffne eine Konsole und navigiere zu dem Verzeichnis, indem du die heruntergeladenen Dateien gespeichert hast.
  5. Wenn du eine MySQL-Installation durchgeführt hast, ändere die Werte in der Datei db.env der MySQL-Konfiguration entsprechend. Wenn du MySQL nicht installiert hast, sind die Dateien multiconnect-compose.yml und db.env standardmäßig so konfiguriert, dass eine Instanz in einem lokalen Container geöffnet wird.
  6. Beim Start der Ausführung mehrerer Container für Hochverfügbarkeit dürfen keine einzeln verbundenen Container mehr ausgeführt werden:
      docker-compose -f your-single-connect-yml-filename stop
    
  7. Führe in der Konsole den folgenden Befehl aus:
    docker-compose -f multiconnect-compose.yml up
    Du erhältst einige Ausgabeinformationen, während das Skript die Docker-Images herunterlädt und das Setup abschließt. Um die Container im Hintergrund auszuführen, verwende den folgenden -d-Parameter:
    docker-compose -f multiconnect-compose.yml up -d

Überprüfe nach Abschluss dieser Schritte, ob die Container mit dem folgenden Befehl ausgeführt werden:

docker-compose ps

Standardmäßig wird der Webapp-Container auf Port 9090 ausgeführt.

Produktionskonfiguration mit mehreren Servern für jeden Container

  1. Installiere Docker auf deinen Systemen.
  2. Wenn Docker Compose nicht im Lieferumfang deiner Docker-Installationen enthalten ist, muss Docker Compose installiert werden.
  3. Lade die Konfigurationsdateien multiconnect-coreapp.yml, multiconnect-master.yml, multiconnect-webapp.yml und db.env herunter: WhatsApp_Configuration_Files.zip. Speichere die einzelnen Dateien auf den jeweiligen Servern.
  4. Öffne auf jedem Server eine Konsole, und navigiere zu dem Verzeichnis, in dem du die heruntergeladenen Dateien gespeichert hast.
  5. In einer Produktionskonfiguration solltest du nach Möglichkeit eine eigenständige MySQL-Instanz verwenden. Ändere, sobald dies der Fall ist, die Werte in der Datei db.env entsprechend deiner MySQL-Konfiguration.
  6. Beim Start der Ausführung mehrerer Container für Hochverfügbarkeit dürfen keine einzeln verbundenen Container mehr ausgeführt werden:
    docker-compose -f your-single-connect-yml-filename stop
    
  7. Führe in der Konsole die folgenden Befehle für die jeweiligen Rechner aus:

    Die Umgebungsvariable EXTERNAL_HOSTNAME muss eine IP-Adresse oder ein Hostname sein, auf die/den von den Rechnern, auf denen die anderen Container ausgeführt werden, zugegriffen werden kann. Die in einer Service-YML-Datei erwähnten Ports müssen offen für Verbindungen von Rechnern sein, auf denen andere Container ausgeführt werden. So müssen beispielsweise als COREAPP_EXTERNAL_PORTS in multiconnect-coreapp.yml definierte Ports für eingehenden Traffic auf dem Host offen sein, der coreapp-Container ausführt.

    EXTERNAL_HOSTNAME=MACHINE_HOSTNAME docker-compose -f multiconnect-coreapp.yml up # on the Coreapp server
    EXTERNAL_HOSTNAME=MACHINE_HOSTNAME docker-compose -f multiconnect-master.yml up # on the Master server
    EXTERNAL_HOSTNAME=MACHINE_HOSTNAME docker-compose -f multiconnect-webapp.yml up # on the Webapp server
    Du erhältst einige Ausgabeinformationen, während das Skript die Docker-Images herunterlädt und das Setup abschließt. Um die Container im Hintergrund auszuführen, verwende den folgenden -d-Parameter:
    EXTERNAL_HOSTNAME=MACHINE_HOSTNAME docker-compose -f multiconnect-coreapp.yml up -d # on the Coreapp server
    EXTERNAL_HOSTNAME=MACHINE_HOSTNAME docker-compose -f multiconnect-master.yml up -d # on the Master server
    EXTERNAL_HOSTNAME=MACHINE_HOSTNAME docker-compose -f multiconnect-webapp.yml up -d # on the Webapp server

Überprüfe nach Abschluss dieser Schritte, ob die Container mit dem folgenden Befehl ausgeführt werden:

EXTERNAL_HOSTNAME=MACHINE_HOSTNAME docker-compose -f multiconnect-coreapp.yml ps # on the Coreapp server
EXTERNAL_HOSTNAME=MACHINE_HOSTNAME docker-compose -f multiconnect-master.yml ps # on the Master server
EXTERNAL_HOSTNAME=MACHINE_HOSTNAME docker-compose -f multiconnect-webapp.yml ps # on the Webapp server

Das Ausführen mehrerer Instanzen desselben Dienstes (z. B. das Ausführen von 2 Coreapps auf demselben Host) funktioniert standardmäßig nicht, da ein Host-Port-Konflikt besteht. Um Portkonflikte zu vermeiden, musst du die entsprechende Service-YML-Datei, in diesem Fall multiconnect-coreapp.yml, ändern, um wie folgt für jede Instanz andere Host-Ports zu öffnen:

ports:
- "HOST_PORT_RANGE:6250-6253"

Standardmäßig wird der Webapp-Container auf Port 9090 ausgeführt.

Upgrade

Entwicklerkonfiguration mit einzelnem Server

Die Datei multiconnect-compose.yml umfasst Felder, die die Container-Versionen angeben. Beispiel:

services: ... waweb: image: docker.whatsapp.biz/web:v2.19.4 ... master: image: docker.whatsapp.biz/coreapp:v2.19.4 ... wacore: image: docker.whatsapp.biz/coreapp:v2.19.4

Um ein Upgrade für eine Installation durchzuführen, ändere die Versionsnummern in der Datei multiconnect-compose.yml:

services: ... waweb: image: docker.whatsapp.biz/web:v2.19.7 ... master: image: docker.whatsapp.biz/coreapp:v2.19.7 ... wacore: image: docker.whatsapp.biz/coreapp:v2.19.7

Starte dann die Docker-Container neu:

docker-compose -f multiconnect-compose.yml up

Produktionskonfiguration mit mehreren Servern für jeden Container

Die YAML-Dateien enthalten Felder für die Containerversionen. Beispiel:

services: ... waweb: image: docker.whatsapp.biz/web:v2.19.4
services: ... wacore: image: docker.whatsapp.biz/coreapp:v2.19.4

services: ... master: image: docker.whatsapp.biz/coreapp:v2.19.4

Um ein Upgrade für eine Installation durchzuführen, ändere die Versionsnummern in den entsprechenden Dateien:

services: ... waweb: image: docker.whatsapp.biz/web:v2.19.7
services: ... wacore: image: docker.whatsapp.biz/coreapp:v2.19.7

services: ... master: image: docker.whatsapp.biz/coreapp:v2.19.7

Starte dann die Docker-Container neu:

EXTERNAL_HOSTNAME=MACHINE_HOSTNAME docker-compose -f multiconnect-coreapp.yml up # on the Coreapp server
EXTERNAL_HOSTNAME=MACHINE_HOSTNAME docker-compose -f multiconnect-master.yml up # on the Master server
EXTERNAL_HOSTNAME=MACHINE_HOSTNAME docker-compose -f multiconnect-webapp.yml up # on the Webapp server

Vorhandene Volumes anhängen

Wenn du über Medienvolumes aus einer früheren Installation verfügst, ersetze die folgende Volumedefinition in den YAML-Dateien:

volumes:
  whatsappData:
      driver: local
  whatsappMedia:
      driver: local

mit:

volumes:
  whatsappData:
      external: true
  whatsappMedia:
      external: true

Bind-Mounts

Dies wird nur empfohlen, wenn ein vorhandenes Bind-Mount-Volume beibehalten werden soll.

Wenn du einen Hostpfad direkt in den Container mounten möchtest (d. h. an einem vorhandenen Speicherort auf deinem Host), ändere die Volumezeile im Dienstabschnitt so, dass auf den Hostpfad verwiesen wird.

wacore:
    volumes:
        /filepath/waent/data:/usr/local/waent/data
        /filepath/wamedia:/usr/local/wamedia

Deinstallation

Entwicklerkonfiguration mit einzelnem Server

Dieser Vorgang muss für alle Rechner wiederholt werden, auf denen Nodes ausgeführt werden.

Wenn du deine Entwicklungsumgebung durch Entfernen aller Container zurücksetzen musst, führe den folgenden Befehl über das Verzeichnis aus, das die Datei multiconnect-compose.yml enthält:

docker-compose -f multiconnect-compose.yml down

Um zusätzlich zu den Containern alle in der Datei multiconnect-compose.yml definierten Volumes zu entfernen, führe down mit dem Parameter -v aus:

docker-compose -f multiconnect-compose.yml down -v

Produktionskonfiguration mit mehreren Servern für jeden Container

Wenn du deine Entwicklungsumgebung durch Entfernung aller Container zurücksetzen musst, führe auf jedem Server den folgenden Befehl in dem Verzeichnis mit der YAML-Datei aus:

EXTERNAL_HOSTNAME=MACHINE_HOSTNAME docker-compose -f multiconnect-coreapp.yml down # on the Coreapp server
EXTERNAL_HOSTNAME=MACHINE_HOSTNAME docker-compose -f multiconnect-master.yml down # on the Master server
EXTERNAL_HOSTNAME=MACHINE_HOSTNAME docker-compose -f multiconnect-webapp.yml down # on the Webapp server

Um zusätzlich zu den Containern alle in den YAML-Dateien definierten Volumes zu entfernen, führe down mit dem Parameter -v aus:

EXTERNAL_HOSTNAME=MACHINE_HOSTNAME docker-compose -f multiconnect-coreapp.yml down -v # on the Coreapp server
EXTERNAL_HOSTNAME=MACHINE_HOSTNAME docker-compose -f multiconnect-master.yml down -v # on the Master server
EXTERNAL_HOSTNAME=MACHINE_HOSTNAME docker-compose -f multiconnect-webapp.yml down -v # on the Webapp server

Protokolle zur Fehlerbehebung

Führe den folgenden Befehl auf deinen Servern aus, um die Protokolle zur Fehlerbehebung abzurufen:

  docker-compose logs > debug_output.txt