Herausforderungen und Lösungen der horizontalen Skalierbarkeit von EMQX – MQTT-Broker-Clustering Teil 3

In diesem Blogbeitrag stellen wir einige der Verbesserungen der Skalierbarkeit des MQTT-Broker-Clusters vor. Wir werden uns hauptsächlich auf die Datenbank-Engine konzentrieren, die EMQX intern verwendet, und wie wir sie in EMQX 5.0 verbessert haben.

Bevor wir beginnen, sollten Sie wissen, wie Daten im EMQX-Cluster repliziert werden: EMQX-Broker speichert die Laufzeitinformationen zu den Themen und Clients in Mnesia Datenbank, die dabei hilft, diese Daten im gesamten Cluster zu replizieren.

Was ist Mnesia?

Lassen Sie uns genauer besprechen, was Mnesia ist und wie es funktioniert. Mnesia ist ein Open-Source-Datenbankverwaltungssystem, das von der Ericsson Corporation als Teil von entwickelt wurde Öffnen Sie die Telekommunikationsplattform. Ursprünglich sollte es Konfigurations- und Laufzeitdaten in Telekommunikations-Switches der ISP-Klasse verarbeiten. Bis zur Version 4.3 speicherte EMQX damit alle Arten von Laufzeitdaten, wie Themen, Routen, ACL-Regeln, Alarme und vieles mehr.

Sie sind wahrscheinlich mit Datenbanken wie MySQL, Postgres, MongoDB und In-Memory-Speichern wie Redis und Memcached vertraut. Mnesia hingegen bleibt relativ dunkel. Nichtsdestotrotz ist es in vielerlei Hinsicht einzigartig, zum Teil, weil es viele der Funktionen der oben genannten Produkte in einer einzigen ordentlichen Anwendung kombiniert.

Wir beginnen mit einer eher akademischen Definition: Mnesia ist eine eingebettete, verteilte, transaktionale NoSQL-Datenbank. Das ist ein ziemlicher Schluck! Lassen Sie uns also auspacken, was das alles bedeutet.

Eingebettet

Beginnen wir mit dem “eingebetteten” Teil. Die am weitesten verbreiteten Datenbanken wie MySQL und Postgres verwenden ein Client-Server-Modell: Die Datenbank läuft in einem separaten Prozess, oft auf einem dedizierten Server, und die Geschäftsanwendungen interagieren damit, indem sie Anfragen über das Netzwerk oder einen UNIX-Domain-Socket senden und warten für Antworten. Dieses Modell ist in vielerlei Hinsicht praktisch, da Sie damit die Geschäftslogik vom Speicher trennen und separat verwalten können. Es hat jedoch auch einige Nachteile: Die Interaktion mit dem Remote-Prozess erhöht unweigerlich die Latenz jeder Anfrage.

Im Gegensatz dazu laufen eingebettete Datenbanken im selben Prozess wie die Geschäftsanwendung. Ein bemerkenswertes Beispiel für eine eingebettete Datenbank ist SQLite. Mnesia fällt ebenfalls in diese Kategorie: Es läuft im selben Prozess wie die übrigen EMQX-Anwendungen. Das Lesen von Daten aus einer Mnesia-Tabelle kann so schnell sein wie das Lesen einer lokalen Variablen, sodass wir an Hotspots aus der Datenbank lesen können, ohne die Leistung zu beeinträchtigen.

Verteilt

Zuvor haben wir erwähnt, dass Mnesia eine verteilte Datenbank ist. Das bedeutet, dass die Tabellen vom Netzwerk über verschiedene physische Standorte hinweg repliziert werden. Die Art der verteilten Datenbank, bei der Knoten keine physischen Ressourcen wie RAM oder Festplatte gemeinsam nutzen und die Koordination auf Anwendungsebene erfolgt, wird als Shared-Nothing-Architektur (SN) bezeichnet. Dieser Ansatz wird häufig bevorzugt, da er keine spezielle Hardware erfordert und horizontal skaliert werden kann.

Die Mnesia-Anwendung, die zusammen mit EMQX ausgeführt wird, hilft dabei, die Tabellenaktualisierungen über alle Knoten im Cluster über das Erlang-Verteilungsprotokoll zu replizieren. Das bedeutet, dass die Geschäftsanwendungen die aktualisierten Daten lokal lesen können. Es hilft auch bei der Fehlertoleranz: Die Daten sind sicher, solange mindestens ein Knoten im Cluster aktiv ist. EMQX verlässt sich auf diese Funktion, um die Routing-Informationen im gesamten Cluster zu replizieren.

Transaktional

Mnesia unterstützt SÄURE Transaktionen, was für eine eingebettete Datenbank ein ziemlich einzigartiges Merkmal ist. Das bedeutet, dass mehrere Lese- und Aktualisierungsvorgänge zusammen gruppiert werden können. Eine Mnesia-Transaktion ist atomar (sie muss entweder in ihrer Gesamtheit vollständig sein oder keinerlei Wirkung haben), konsistent (obwohl die Garantien laxer sind als beispielsweise in Postgres), isoliert (sie wirkt sich nicht auf andere Transaktionen aus) und dauerhaft. All diese Garantien bleiben über den gesamten Cluster erhalten.

EMQX verwendet Mnesia-Transaktionen an den Stellen, an denen die Datenkonsistenz kritisch ist.

NoSQL

Die herkömmlichen relationalen Datenbanken verwenden eine spezielle Abfragesprache namens SQL, um mit der Datenbank zu interagieren. Häufig ORM wird verwendet, um die Entwicklung zu beschleunigen. Mnesia hingegen hat keine spezialisierte Abfragesprache: Es verwendet Erlang (oder Elixir) als Abfragesprache, sodass kein ORM erforderlich ist. Es arbeitet direkt mit den Erlang-Begriffen, was die Integration in die Geschäftslogik sehr reibungslos macht.

Die Architektur

In einem Mnesia-Cluster sind alle Knoten gleich. Jeder von ihnen kann Kopien beliebiger Tabellen speichern, Transaktionen starten und auf die Tabellen zugreifen. Der Mnesia-Cluster verwendet eine Full-Mesh-Topologie: Jeder Knoten kommuniziert mit allen anderen Knoten im Cluster. Jede Transaktion wird auf alle Knoten im Cluster repliziert, wie im folgenden Bild gezeigt:

Mnesia-ClusterMnesia-Cluster

Bezüglich CAP-Theorem (Konsistenz, Verfügbarkeit, Partitionstoleranz: Wählen Sie zwei aus), Mnesia ist standardmäßig auf AP eingestellt.

Herausforderungen

Wie wir oben besprochen haben, hat die Mnesia-Datenbank eine ziemlich ungewöhnliche Reihe von Funktionen, die wir in EMQX verwenden. Jetzt ist es an der Zeit, über die Nachteile zu sprechen und warum wir uns entschieden haben, in die Verbesserung zu investieren.

Obwohl Mnesia Hardware-agnostisch ist, wurde es ursprünglich mit Blick auf eine bestimmte Cluster-Architektur entwickelt: eine Sammlung von Servern, die durch ein schnelles lokales Netzwerk mit geringer Latenz miteinander verbunden sind.

Unter idealen Bedingungen kann die Mesh-Topologie die Transaktionsreplikationslatenz reduzieren: Die gesamte Kommunikation zwischen den Knoten kann parallel und ohne Zwischenhändler erfolgen. Es begrenzt jedoch die horizontale Skalierbarkeit des Clusters, da die Anzahl der Verbindungen zwischen den Knoten quadratisch mit der Anzahl der Knoten wächst. Alle Knoten perfekt synchron zu halten, wird immer teurer und die Leistung der Transaktionen sinkt.

Die Gleichheit der Knoten spielte auch mit dem traditionellen Cluster-Paradigma eine Rolle: Es machte das Ersetzen eines einzelnen Knotens einfach, aber die Anzahl der Knoten, die gleichzeitig dem Cluster beitreten konnten, war begrenzt.

Jetzt leben wir in anderen Zeiten: Cluster werden in georedundanten Cloud-Umgebungen bereitgestellt, alles ist dynamisch und kurzlebig, Knoten laufen in den Auto-Scaling-Gruppen, und wir erwarten, dass sie ständig auf und ab gehen.

Als Antwort auf diese Herausforderungen haben wir eine Erweiterung für Mnesia namens Mria entwickelt.

Wir stellen Mria vor

Maria ist eine Open-Source-Erweiterung für Mnesia, die dem Cluster letztendlich Konsistenz verleiht.

Mria bewegt sich weg von einer Full-Mesh-Topologie hin zu einer Mesh+Stern-Topologie. Jeder Knoten übernimmt eine der beiden Rollen: Kern oder Replikant.

Kernknoten verhalten sich ähnlich wie normale Mnesia-Knoten: Sie sind in einem vollständigen Netz verbunden, und jeder Knoten kann Schreibtransaktionen initiieren, Sperren halten usw. Von Kernknoten wird erwartet, dass sie mehr oder weniger statisch und persistent sind.

Replikantenknoten hingegen nehmen nicht an den Transaktionen teil. Sie verbinden sich mit einem der Kernknoten und replizieren passiv die Transaktionen von diesem. Dies bedeutet, dass Replikanten keine Schreibvorgänge selbst ausführen dürfen. Stattdessen bitten sie einen Kernknoten, die Daten in ihrem Namen zu aktualisieren. Gleichzeitig verfügen sie über eine vollständige lokale Kopie der Daten, sodass der Lesezugriff genauso schnell erfolgt.

Mria-ClusterMria-Cluster

Man kann sich Mria als eine Kombination aus Client-Server und eingebetteter Datenbank vorstellen: Schreibvorgänge laufen über einen Server, aber die Lesevorgänge sind lokal.

Diese Cluster-Topologie adressiert zwei Probleme:

  • Horizontale Skalierbarkeit
  • Es aktiviert Cluster-Autoscaling

Da Replikantenknoten nicht an Schreibvorgängen teilnehmen, leidet die Transaktionslatenz nicht, wenn weitere Replikanten zum Cluster hinzugefügt werden. Dadurch können größere EMQX-Cluster erstellt werden.

Außerdem sind Replikantenknoten so konzipiert, dass sie kurzlebig sind. Das Hinzufügen oder Entfernen ändert nichts an der Datenredundanz, sodass sie in einer Autoscaling-Gruppe platziert werden können, wodurch bessere DevOps-Praktiken ermöglicht werden.

Im nächsten Beitrag werden wir ausführlicher besprechen, wie EMQX konfiguriert wird, um Mria voll auszunutzen.

Ursprünglich erschienen bei

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *