Files
oop-heimdall/notes/NOTES.md
2024-01-24 07:20:20 +01:00

25 KiB
Raw Blame History

Millionen langlebiger TCP-Verbindungen Herausforderungen und Lösungen bei Update-Prozessen

Neulich stehe ich am Bahnhof, mit gepackten Koffern, und will in meinen Urlaub starten. Beim Warten auf den (natürlich) verspäteten Zug hatte ich jede Menge Zeit zum überlegen. Ich habe mich gefragt: "Ist der Herd wirklich abgeschaltet?". Anders als in früheren Urlauben hatte ich aber einen smarten Herd daheim. Ich öffne also meine App, stelle fest, dass alles in Ordnung ist, und kann beruhigt in den Zug einsteigen.

IoT (also "Internet of Things") beschreibt genau diese Art von Geräten. Mein Name ist Bene. Ich bin Softwareentwickler mit Fokus auf Softwarearchitektur bei Scandio. Wir bei Scandio entwickeln für unsere Kunden maßgeschneiderte intelligente und kreative Softwarelösungen. Wir haben dabei einen Schwerpunkt unter anderem im Bereich "Internet of Things".

Ein Projekt aus diesem Bereich will ich heute vorstellen. Dabei geht es darum, wie die IoT-Geräte unseres Kunden mit verschiedenen Backends kommunizieren und um die Herausforderungen bei der Aktualisierung des Systems, das zwischen den Geräten und den Backends liegt.

Inhalt

Ein kurzer Überblick über den Vortrag: Nach dem Projektsetup (also Hintergrund, Motivation und Ziel des Projekts) beschreibe ich euch die Problemstellung etwas genauer und dann natürlich auch die Lösungen, also: wie sieht die Architektur des Systems jetzt aus, was genau passiert, wenn das System Updates bekommt, und zum Schluss noch: was wären unsere Wunschträume für die Architektur, wenn Zeit und Geld keine Rolle spielen würde oder wir ganz von vorne anfangen würden.

Eine organisatorische Bemerkung: wenn während des Vortrags Fragen aufkommen, stellt sie gerne sofort und ich werde sie so gut wie möglich beantworten.

Über Scandio

Noch kurz ein paar Worte über Scandio: Neben IoT haben wir Stärken in den Bereichen Cloud und Systems Engineering, DevOps und Fullstack-Web-Entwicklung. Daneben unterstützen wir mit agilen Coaches und Beratern dabei, Prozesse zu optimieren. Insbesondere helfen wir als Atlassian Platinum Solution Partner unseren Kunden bei ihrer agilen Transformation.

Projektsetup

Das Projekt, von dem ich heute rede, hat den Namen "Heimdall".

Heimdall ist in der nordischen Mythologie der Wächter der Götterbrücke Bifröst (das ist der Regenbogen im Bild) und Heimdall hat außergewöhnliche Wahrnehmungsfähigkeiten. Hier im Bild ist das durch das Hören symbolisiert. Genauso wie Heimdall die Verbindung zwischen den Welten überwacht, fungiert unser Heimdall-System als ein Gateway, das die Brücke zwischen einer Vielzahl von IoT-Geräten und verschiedenen Backend-Systemen bildet. Ähnlich der mythischen Figur hat unser Heimdall die Aufgabe, die Sicherheit, Stabilität und Effizienz dieser Verbindungen zu gewährleisten.

Heimdall wird seit 2018 entwickelt und hat ein vollständig extern entwickeltes und verwaltetes System abgelöst. Bei diesem alten System hatte unser Kunde keinen Zugriff auf den Source Code oder Entwicklungsdetails. Daher wurde die Entscheidung für eine Neuentwicklung getroffen. Die fehlenden Informationen über das alte System gingen sogar so weit, dass wir bei der Migration zu unserem neuen System regelmäßig das alte System überlastet haben, da wir einfach keine Informationen bekommen konnten, welche Last das alte System aushält. Mit diesem Lock-In-Effekt war unser Kunde verständlicherweise unzufrieden und hat uns beauftragt, Heimdall neu zu entwickeln.

[5] Ich will hier einmal schematisch zeigen, welche Aufgabe Heimdall hat. Meine smarte Herdplatte von vorhin muss regelmäßig an das Herdplattenstatusbackend die Information senden, welche Herdplatten auf welcher Stufe angeschaltet sind. Gleichzeitig tauscht das smarte Heizungsthermostat eures Nachbarn Nachrichten mit einem Backend aus, um herauszufinden, ob die Heizung nach oben oder unten geregelt werden sollte, und die smarte Dunstabzugshaube eurer Tante meldet an das entsprechende Backend, dass die Filter mal wieder eine Reinigung bräuchten. Heimdall sitzt zwischen den Geräten und den Backends und sorgt dafür, dass die richtigen Nachrichten das richtige Backend erreichen, und dass umgekehrt auch Nachrichten in die Gegenrichtung versendet werden können: beispielsweise kann das Herdplattenbackend die Herdplatte anweisen, sich abzuschalten. Die Geräte halten dazu eine Verbindung zu Heimdall aufrecht. Über diese Verbindung werden die Nachrichten dann ausgetauscht.

Problemstellung

Das wichtigste Qualitätsziel bei Heimdall ist, dass diese Verbindungen zwischen Gerät und Heimdall so selten wie möglich unterbrochen werden. Das hat zwei Gründe: Zum einen kann ich als Nutzer nicht sehen, auf welcher Stufe mein Herd gerade kocht, wenn der Herd nicht mit Heimdall verbunden ist. Zum anderen finden einige Prozesse nach jeder Neuverbindung statt. Das kann potenziell zu Überlastung von Heimdall oder den Backends führen, wenn die Neuverbindungen zu häufig stattfinden.

Ein Szenario gibt es aber, in dem Verbindungen auf keinen Fall gehalten werden können: nämlich wenn der Server, mit dem die Hausgeräte verbunden sind, ein Update bekommt und daher ersetzt werden muss. Deswegen ist eins der größten Ziele bei der Entwicklung der Architektur von Heimdall, dass solche Neustarts bei den meisten Konfigurationsänderungen des Systems nicht notwendig sind, sondern die Konfigurationsänderungen am Live-System durchgeführt werden können.

Lösungen

Diesem Prinzip, dass Konfigurationsänderungen ohne Neustarts möglich sein sollen, werden wir bei der Betrachtung der Heimdall-Architektur noch öfter begegnen. Wir schauen uns jetzt mal an, wie Heimdall aufgebaut ist.

[10] Das Kernstück von Heimdall ist der sogenannte "Web Socket Manager", kurz WSM. Eure Herdplatte kann über euer heimisches WLAN mit dem Internet kommunizieren. Nachdem die Firmware der Herdplatte gestartet und die Verbindung mit dem Internet hergestellt wurde, versucht die Herdplatte eine Websocket-Verbindung zum WSM zu öffnen. Dabei handelt es sich um eine dauerhafte Verbindung, über die zu beliebigen Zeiten Nachrichten in beide Richtungen entlang der Verbindung geschickt werden können. Die Verbindung wird so lange wie möglich aufrecht erhalten. Es gibt im Wesentlichen vier Gründe für den Abbruch der Verbindung: Das Gerät wurde abgeschaltet, die Netzwerkverbindung zwischen Gerät und WSM wurde unterbrochen, der WSM wurde beendet oder der WSM hat die Verbindung beendet. Im letzten Fall teilt also der WSM dem Gerät mit, dass über die Verbindung keine Daten mehr entgegengenommen oder verschickt werden können, ohne dass WSM oder Gerät beendet wurden. Gehen wir also mal davon aus, dass die Verbindung geöffnet ist und die Herdplatte mit dem WSM kommuniziert. Dann leitet der WSM die Nachrichten des Geräts an ein Backend weiter und umgekehrt werden Nachrichten vom Backend an das Gerät zurückgeleitet. Wenn es nur ein Gerät und nur ein Backend geben würde, wäre ich jetzt fertig mit der Präsentation. Das ist aber natürlich nicht alles.

[15] In Wirklichkeit gibt es ja außer eurer Herdplatte auch noch den Thermostat eures Nachbarn, die Dunstabzugshaube eurer Tante und noch jede Menge andere Geräte, die mit den Backend-Systemen kommunizieren sollen. Unser Deployment ist in vier verschiedene Regionen aufgeteilt, und in der größten Region, der Region Europa, haben wir aktuell etwa 2,5 Millionen Geräte, die zur gleichen Zeit mit Heimdall verbunden sind. Deshalb gibt es auch mehrere WSM-Pods, also mehrere Instanzen des WSM. Zum einen wird dadurch die Skalierbarkeit des Systems verbessert, und zum anderen verlieren im Falle eines Crashs nicht alle Geräte gleichzeitig die Verbindung. Vor diesen Instanzen liegt ein Load Balancer, der versucht, die Verbindungslast möglichst gleichmäßig zu verteilen, um Rechenressourcen möglichst effizient nutzen zu können. Der Load Balancer routet die Verbindungen von den Geräten zum WSM im Round-Robin-Algorithmus, also: eure Herdplatte verbindet sich zuerst und wird an die erste Instanz geroutet, danach kommt die smarte Glühbirne eures Freunds, die wird dann an die zweite Instanz geroutet, und nach der letzten Instanz beginnt das Spiel von vorne. Bei synchronen Aufrufen an das Backend kommt die Antwort an die richtige WSM-Instanz zurück. Allerdings führen synchrone Aufrufe zu zwei Nachteilen: zum einen muss der WSM auf die Antwort des Backends warten und so lange die Verbindung zum Backend offen halten. Wenn sehr viele Nachrichten auf einmal verschickt werden und das Backend langsam arbeitet, kann das zur Überlastung des WSM führen. Ein zweiter Nachteil von synchronen Aufrufen ist die stärkere Kopplung: die Verarbeitung der Nachricht schlägt nämlich fehl, wenn das Backend oder weiter innen liegende Systeme bei der Verarbeitung der Nachricht scheitern. Da sind asynchrone Aufrufe die bessere Lösung. Das heißt, dass entweder das Backend die Nachricht entgegennimmt und erst im Nachgang verarbeitet, oder dass der WSM die Nachricht an einen hochverfügbaren Message Broker schickt und die Backends die Nachricht in ihrer Geschwindigkeit zu einer späteren Zeit konsumieren können. Egal, für welche Lösung man sich hier entscheidet: das Backend muss eine Nachricht zurück an das Gerät senden, weiß aber noch nicht, mit welcher WSM-Instanz das Gerät verbunden ist. Übrigens hätten wir das selbe Problem auch ganz ohne asynchrone Aufrufe: sagen wir mal, euer Nachbar möchte seiner Heizung mitteilen, dass sie die Temperatur in der Wohnung auf 22 Grad hochregeln soll, weil er jetzt auf dem Heimweg ist. Dann muss das Heizungsbackend eine Nachricht an den Thermostat schicken. Wenn das Backend versucht, die Nachricht über eine zufällige Instanz des WSM zu schicken, ist die Chance nicht sehr hoch, dass der Thermostat gerade mit dieser Instanz verbunden ist.

Hier kommen der Forwarding-Service (kurz FORS) und eine Adress-Datenbank ins Spiel. Jeder WSM-Pod schreibt nach einer geöffneten Verbindung mit einem Gerät die Geräte-ID zusammen mit der eigenen Adresse in die Adress-Datenbank. Der FORS fragt jetzt für ein Gerät die richtige Adresse ab und kann Nachrichten vom Backend an die richtige WSM-Instanz weiterleiten. Konkret schaut der Ablauf also so aus: Gerät 1 baut eine Websocket-Verbindung zu WSM-Pod 1 auf. In der Folge teilt WSM-Pod 1 der Adress-Datenbank mit: Gerät 1 ist mit dem Pod verbunden, der Adresse 1 besitzt. An der Kommunikation vom Gerät zum Backend hat sich nichts geändert. Wenn jetzt aber das Backend eine Nachricht an das Gerät senden möchte, dann wird die Nachricht an unseren Forwarding-Service geschickt. Der Forwarding-Service fragt die konkrete Adresse des richtigen WSM-Pods bei der Adress-Datenbank an und leitet die Nachricht entsprechend weiter. Dann ist die Nachricht beim richtigen WSM gelandet und kann an das Gerät über die Websocket-Verbindung geschickt werden.

[20] Dazu kommt, dass es in Wirklichkeit nicht nur ein Backend gibt. Ein Message Mapping kann vom WSM genutzt werden, um zu entscheiden, an welches Backend ein konkreter Nachrichtentyp mit einer konkreten Version gesendet werden soll. Der Ablauf hier ist also: Das Gerät (der Einfachheit halber habe ich in diesem Bild nur noch ein Gerät) schickt die Nachricht mit dem Typ "/foo/config" und der Version 1 an den WSM. Der WSM findet mit Hilfe des Message Mappings heraus, dass Backend 1 für die Verarbeitung der entsprechenden Nachrichten verantwortlich ist und leitet die Nachricht entsprechend weiter. Wir sind also wie ein Postunternehmen dafür zuständig, dass die richtigen Nachrichten an den richtigen Empfänger gelangen, aber nicht dafür, dass die Nachrichten inhaltlich auch sinnvoll sind. Es findet also bei Heimdall keinerlei Validierung der Nachrichten statt. Das Message Mapping ändert sich regelmäßig. Deshalb ist es wichtig, dass eine Rekonfiguration ohne Neustart der WSM-Pods möglich ist, da sonst ja Verbindungen gekappt werden müssten.

Der WSM hat noch diverse andere Aufgaben:

  • Er führt den TLS-Handshake durch. Das heißt: alle Informationen, die zwischen Gerät und WSM ausgetauscht werden, werden verschlüsselt ausgetauscht. Dabei muss sich sowohl der Server, also der WSM, beim Gerät authentifizieren, als auch das Gerät nachweisen, dass es sich tatsächlich um ein Gerät unseres Kunden handelt. Die Authentifizierungen finden statt, indem überprüft wird, dass Gerät und WSM beide Zertifikate besitzen, die von einer vertrauenswürdigen Entität, also einer Certificate Authority (kurz CA) des Kunden signiert wurden.
  • Bei der Validierung des Zertifikats, das das Gerät ausweist, gibt es noch ein paar Details zu beachten. Nämlich gibt es etwa 10 verschiedene ausstellende CAs, also Certificate Authorities, denen der WSM vertrauen soll. Manche dieser CAs haben Zertifikate ausgestellt, die inzwischen abgelaufen sind und die daher von einer Standard-Validierung nicht akzeptiert werden würden. Das Problem dabei: für Firmware-Updates müssen auch Nachrichten über Heimdall ausgetauscht werden, und die entsprechenden Geräte-Zertifikate können ohne ein Firmware-Update nicht aktualisiert werden. Deshalb muss Heimdall auf die Validierung des Gültigkeitszeitraums für die entsprechenden CAs verzichten.
  • Manche Geräte-Zertifikate sollen außerdem sofort abgelehnt werden, weil die entsprechenden Geräte defekt sind. Das wird über eine Datenbank mit blockierten Zertifikaten geregelt. Für das Blockieren eines Zertifikats ist wie beim Message Mapping kein Neustart des WSM notwendig, sodass auch hier Neuverbindungen vermieden werden.
  • Noch einmal andere Geräte sind in einem Quarantäne-Status. Für diese Geräte dürfen nur bestimmte Nachrichten versendet und empfangen werden, beispielsweise wieder Nachrichten im Zusammenhang mit Firmware-Updates. Wie die blockierten Zertifikate wird das über eine eigene Datenbank konfiguriert und benötigt keinen WSM-Neustart.
  • Dann muss der WSM noch den Websocket-Upgrade durchführen (dazu sage ich später noch mehr).
  • Schließlich gibt es noch einen Corporate Handshake, der vom Protokoll unseres Kunden vorgesehen ist. Bevor dieser Handshake abgeschlossen ist, dürfen keine anderen Nachrichten in beide Richtungen gesendet oder weitergeleitet werden.

[25] Hier ist noch einmal eine Zusammenfassung des gesamten Heimdall-Systems, soweit es für den Vortrag relevant ist. Die Grundidee ist also, dass der WSM so selten wie möglich neugestartet werden muss. Das erreichen wir, indem Konfiguration, die sich regelmäßig ändern könnte, externalisiert wird und ohne Neustarts geändert werden kann. Das sieht man in diesem Bild durch das Message Mapping und die beiden Datenbanken zum Blockieren von Zertifikaten und für den Quarantäne-Status.

Was passiert jetzt aber, wenn der WSM doch einmal neugestartet werden muss oder abstürzt? Wenn ein WSM-Pod kontrolliert beendet wird, werden die Verbindungen zu den entsprechenden Geräten nacheinander beendet. Dann verbinden sich die Geräte mit anderen Instanzen neu. Aktuell dauert dieser Prozess in unserer größten Stage mit etwa 2,5 Millionen Geräten knapp 3 Stunden. Da wir ja Round-Robin für das Load Balancing nutzen, hat der Ersatz-Pod, der hier gestartet wurde, danach deutlich weniger offene Verbindungen als die alten Pods. In der Praxis führt das nicht zu Problemen, denn die Last ist bei neuen Verbindungen mit Abstand am höchsten.

Falls ein Pod (beispielsweise aufgrund eines Bugs) unkontrolliert beendet wird, versuchen sich alle Geräte auf einmal neu zu verbinden. Das würde zur Überlastung des Systems führen, daher gibt es einen Rate Limiter, der dafür sorgt, dass sich Geräte nicht zu schnell wieder verbinden können. Natürlich ist das ein ungünstiger Zustand, da die Funktionalität der noch nicht wieder verbundenen Geräte eine ganze Weile eingeschränkt sein kann.

Jetzt kommen wir mal zum geplanten Fall: eine neue WSM-Version soll deployed werden. Das Deployment läuft dann so ab: In einem ersten Schritt werden 1/3 der Instanzen durch Instanzen der neuen Version als Canary-Deployment ersetzt. Diese neue Version läuft parallel zu der alten für eine Woche, bevor auch die übrigen Instanzen ersetzt werden. So können Fehler frühzeitig erkannt und behoben werden, bevor alle Geräte betroffen sind.

[30] Das bedeutet übrigens nicht, dass nach dem Canary-Deployment 1/3 der Verbindungen auf der neuen Version stattfinden. Die Wahrheit ist hier etwas komplizierter: die Geräte, die sich nach dem Abschalten mancher der alten Instanzen neu verbinden, verbinden sich ja genauso häufig mit jeder der Canary-Instanzen wie mit jeder der alten Stable-Instanzen. In dem 7-Tage-Zeitraum gleichen sich die Anzahl der verbundenen Geräte dann etwas aus, weil Geräte regelmäßig auch aus anderen Gründen die Verbindung verlieren und sich neu verbinden. Nach einer Woche werden die übrigen 2/3 der Instanzen ersetzt und wie vorhin haben dann die zuerst deployeten Canary-Instanzen mehr offene Verbindungen als die zuletzt deployeten. Wie gesagt führt das allerdings in der Praxis zu keinen Problemen und gleicht sich auf Dauer von selbst aus.

Jetzt habt ihr gesehen, wie das System tatsächlich aussieht. Natürlich haben wir in den gut 5 Jahren, in denen das Projekt existiert, auch dazugelernt und würden einige Dinge anders gestalten. Am Anfang des Vortrags habe ich ja schon gesagt, dass das Ziel wäre, den WSM so selten wie möglich updaten zu müssen. Dafür ist es hilfreich, wenn der WSM so wenige Aufgaben wie möglich bekommt. In einer idealen Welt sollte daher der WSM der kleinste Service im gesamten System sein. Die Realität ist: der WSM ist der mit Abstand größte Service des Heimdall-Systems.

Woran liegt das? Aktuell hat der WSM einige Aufgaben:

  • TLS und alles, was dazugehört: die Terminierung der TLS-Verbindung, die Validierung der Geräte-Zertifikate, die Ausnahmen zur Validierung der Zertifikate und das Blocklisting von Zertifikaten.
  • Der Websocket-Upgrade, also die Entgegennahme der initialen HTTP-Verbindung und der Wechsel zum Websocket-Protokoll
  • Der Corporate Handshake, der zu Beginn jeder Verbindung stattfinden muss
  • Das Message Routing an die Backends inklusive Offenhalten der Verbindungen und Warten auf Antworten
  • Die Quarantäne-Logik
  • Einige andere Workarounds, die im WSM diverse Spezialfälle abhandeln

Um also den WSM möiglichst klein zu bekommen, müssen möglichst viele dieser Aufgaben ausgelagert werden. Oder umgekehrt: die Aufgaben, die unbedingt notwendig zum Halten der Verbindung sind, sollten aus dem WSM extrahiert werden.

[35] Bevor ich einen Vorschlag vorstelle, wie wir das erreichen könnten, will ich noch einmal ein bisschen detaillierter erklären, wie das Websocket-Protokoll funktioniert. Das Gerät eröffnet zu Beginn eine TCP-Verbindung zum WSM. Es ist nicht besonders wichtig zu wissen, was TCP genau macht, sondern nur, dass man bei einer TCP-Verbindung Daten in beide Richtungen verschicken kann und dass die TCP-Verbindung jederzeit auf beiden Seiten geschlossen werden kann. Nach Öffnung der zugrundeliegenden Verbindung findet der TLS-Handshake mit Verschlüsselung und Authentifizierung statt. Ab diesem Zeitpunkt verläuft die Kommunikation verschlüsselt und der WSM kennt ein Zertifikat, das das jeweilige Gerät ausweist. Als nächstes wird vom Gerät der Websocket-Endpunkt aufgerufen und der WSM wechselt das Protokoll zum Websocket-Protokoll. Ab hier können beliebige Daten im Websocket-Protokoll zwischen Gerät und WSM hin und her geschickt werden. Dann passiert der Corporate Handshake und schließlich der Austausch von beliebigen anderen Nachrichten, beispielsweise über den Status der Geräte. Die Verbindung inklusive TLS-Terminierung muss von einem einzigen Server gehalten werden, wenn wir nicht komische Nichtstandard-Dinge mit Verschlüsselung tun wollen, was aus Security-Gesichtspunkten natürlich keine gute Idee ist. Allerdings könnte die gesamte Kommunikation, die nach der Entschlüsselung der Nachrichten, also unterhalb der ersten gestrichelten Linie, stattfindet, außerhalb des Services stattfinden, der die Verbindung hält.

Hier wäre daher unser Vorschlag, um die Verbindungen noch länger halten zu können. Vor die übrigen Systeme wird ein Service gesetzt, den ich hier "Connection Holder" genannt habe und der nur dafür zuständig ist, die TCP-Verbindung zu den Geräten zu halten, die TLS-Verschlüsselung zu terminieren und zu Validieren, dass die Geräte-Zertifikate von einem bekannten Issuer ausgestellt wurden. Nach der TLS-Terminierung wird die TCP-Verbindung einfach an das Äquivalent des jetzigen WSMs weitergetunnelt. Wenn die WSM-Instanz beendet wird, kann der Tunnel an eine andere WSM-Instanz weitergeroutet werden, ohne die Verbindung zum Gerät abzubrechen. Damit der WSM Zertifikatslogik wie Blocklisting durchführen kann, muss zu Beginn des Verbindungsaufbaus zwischen Connection Holder und WSM das validierte Geräte-Zertifikat mitgeschickt werden. Außerdem müssen die Verbindungen eine eindeutige ID bekommen, sodass die WSM-Instanzen beispielsweise persistieren können, ob für eine gegebene Verbindung bereits der Corporate Handshake durchgeführt wurde. Natürlich könnten auch andere Aufgaben aus dem WSM ausgelagert werden, hier mal exemplarisch das Message Routing inklusive Warten auf die Antwort des Backends.

[40] Schauen wir uns das ganze in der Laufzeitsicht etwas genauer an. Das Gerät öffnet also eine TCP-Verbindung inklusive TLS zum Connection Holder. Diese Verbindung soll jetzt möglichst lange bestehen bleiben. Der Connection Holder erstellt eine eindeutige Verbindungs-ID, die der WSM später nutzen kann, um Verbindungen zu identifizieren und ihren Status zu vergleichen. Der Connection Holder sucht sich per Load Balancing eine WSM-Instanz, zu der er eine TCP-Verbindung öffnet. Das Gerät öffnet eine Websocket-Verbindung zum Connection Holder, der wiederum eine Websocket-Verbindung zum WSM öffnet. Dort wird überprüft, ob das validierte Geräte-Zertifikat akzeptiert werden soll und gegebenenfalls kann der WSM an dieser Stelle die Verbindung sofort beenden. Andernfalls wird die Connection-ID persistiert, mit dem Status "hier existiert eine Verbindung, für die aber noch kein Corporate Handshake durchgeführt wurde". Die Antworten "101 Switching Protocols" sorgen dafür, dass die jeweiligen Websocket-Verbindungen geöffnet sind. Alle weiteren Nachrichten werden vom Connection Holder zwischen Gerät und WSM weitergetunnelt. Jetzt kann der WSM also wie gehabt den Corporate Handshake durchführen, würde danach auch wieder einen Status für die jeweilige Verbindung persistieren, und könnte dann Nachrichten wie zuvor weiterleiten. Wenn jetzt die TCP-Verbindung vom WSM beendet wird, öffnet der Connection Holder eine TCP-Verbindung zu einer anderen WSM-Instanz und versucht, auch dorthin eine Websocket-Verbindung zu etablieren. Durch die persistierte Connection-ID erkennt die zweite WSM-Instanz, dass der Corporate Handshake bereits durchgeführt wurde und behandelt die Verbindung entsprechend. Ab diesem Zeitpunkt werden Nachrichten an die zweite WSM-Instanz weitergetunnelt. Das Gerät merkt davon nichts.

Von innen betrachtet würde der Connection Holder so aussehen: Außen liegt der TCP Connector, der die TCP-Verbindung zum Gerät entgegennimmt und die Connection-ID erstellt. Dann kommt ein Filter, der für die TLS-Terminierung inklusive Extraktion des Geräte-Zertifikats zuständig ist. Zum Schluss noch der Websocket-Filter, der die Websocket-Verbindungen zum WSM verwaltet.

Was wären die Nachteile des vorgeschlagenen Refactorings? Zum einen natürlich die Entwicklungskosten, bestehend aus den Entwicklungskosten des Connection Holders, den notwendigen Refactorings im WSM sowie den notwendigen ausführlichen Tests, um zu gewährleisten, dass das System funktioniert wie geplant. Zum anderen käme in die Servicelandschaft bei Heimdall ein weiterer Service hinzu, der potenziell gewartet und beim Onboarding neuer Entwickler:innen berücksichtigt werden muss. Allerdings können die Nachteile relativiert werden, und es gibt auch einige Vorteile: zum einen ist das notwendige Refactoring im WSM minimal, denn nur die Logik für das Persistieren und Überprüfen des Verbindungsstatus kommt hinzu. Die Entwicklung des Connection Holder ist auch nicht sonderlich aufwändig, da er relativ wenige Aufgaben hat. Entsprechend hält sich auch der Overhead beim Onboarding in Grenzen. Der große Vorteil allerdings ist, dass der Connection Holder äußerst selten Updates benötigt. Hier ist zu erwarten, dass die Businesslogik sich sehr selten ändert, also werden Updates hauptsächlich aus Security-Gründen nötig werden. Der große Vorteil ist jetzt, dass WSM-Updates ohne Verbindungsneustarts möglich werden. Insbesondere führt das dazu, dass die Updates des WSM deutlich schneller stattfinden können und außen liegende Systeme weniger beeinflussen. Das führt zu einer verbesserten Time-To-Market bei neuen Features und zu verringerten Abhängigkeiten und Kommunikations-Overheads zu anderen Teams.

Zusammenfassend können wir schon im aktuellen System zuverlässig dafür sorgen, dass Konfiguration schnell und unkompliziert ohne Neuverbindungen geändert werden kann. Neuverbindungen komplett zu vermeiden dürfte nicht möglich sein, aber wir haben Ideen, wie wir uns in diese Richtung verbessern können. Ich hoffe, ich konnte euch einen guten Einblick in die Herausforderungen geben, vor die uns die langlaufenden Verbindungen in Zusammenhang mit Systemupdates stellen.

Hier seht ihr noch einmal, wie ihr mich erreichen könnt. Danke fürs Zuhören!