Serviceorientierte Architektur bei nine.ch

Philipp Nov 21, 2016

Serviceorientierte Architektur, besser bekannt als SOA, ist ein weit verbreitetes Architektur-Prinzip in der IT. Vereinfacht ausgedrückt werden einzelne Komponenten in einer Infrastruktur, abgekapselt voneinander, als Services umgesetzt. Dabei bieten diese entsprechende Schnittstellen, damit die Services miteinander kommunizieren können. Daraus ergeben sich Vorteile wie eine lose Kopplung, Skalierbarkeit, und ein einfacheres Deployment.

In diesem Blog-Post geben wir Ihnen einen Einblick, wieso wir uns bei nine.ch für dieses Architekturprinzip entschieden haben, wie wir es umgesetzt haben und welche Vor- und Nachteile sich daraus für uns ergeben.

Wieso nicht gleich Microservices?

Bevor wir näher auf SOA eingehen, möchten wir gerne erläutern, was Microservices sind und worin der Unterschied zu SOA besteht.

Bei Microservices handelt es sich ebenfalls um ein Architektur-Prinzip. Wie bei SOA komponiert man Applikationen in unabhängige Services. Die Philosophie von Microservices orientiert sich allerdings noch stärker an der Unix-Welt: ‘Do One Thing and Do It Well’. Ein Microservice soll möglichst überschaubar sein und als Richtwert von einer Hand voll Entwickler in unter einem Monat neu entwickelt werden können.

Wieso handelt dieser Blog Post also nicht von Microservices? Auch wenn wir bei nine.ch die Philosophie von Microservices mögen und einige unserer Services als Microservices bezeichnen können, macht es für uns trotzdem keinen Sinn, ausschliesslich auf Microservices zu setzen. Pragmatisch betrachtet kann in bestimmten Fällen mehr Aufwand entstehen, als dass es Nutzen bringt.

Deshalb bezeichnen wir unsere Infrastruktur als serviceorientiert. Wobei man Microservices dabei als spezifischeres Subset von SOA betrachten kann.

Was ist SOA?

Das Gegenteil von SOA wäre eine monolithische Applikation, welche alle Funktionen umfasst, die benötigt werden. Nehmen wir beispielsweise den Fall, dass wir für ein Hosting-Unternehmen eine Applikation benötigen, mit welcher Kunden und Server verwaltet werden können.

Es scheint plausibel, dass diese Funktionalitäten zusammengehören. Was ist aber, wenn beim Erfassen eines Servers ein virtueller Server aufgesetzt werden soll, Mails an Kunden verschickt werden müssen oder dem Kunden Zugriff über ein Kundenportal geboten werden soll? In all diesen Fällen wird unsere Applikation immer weiter anwachsen.

Nehmen wir nun den SOA-Ansatz. Hier wäre beispielsweise eine folgende Unterteilung der Applikation sinnvoll:

  • Kundenverwaltung
  • Serververwaltung
  • Kundenportal

Wobei die Kundenverwaltung der Meister der Kundendaten ist. In der Serververwaltung ist alles implementiert, was mit dem Aufsetzen der Server zu tun hat. Und über das Kundenportal kann der Kunde seine persönlichen Daten und Server verwalten.

Das Kundenportal braucht selbst keine Datenbank und greift lediglich auf die Kunden- und Serververwaltung zu. Die Kundenverwaltung braucht nichts von den Servern und die Serververwaltung nichts von den Kunden zu wissen (ausser einer globalen Kunden-Nummer).

Folgendes Diagramm veranschaulicht diesen Aufbau: Einfache SOA

Welche Vorteile ergeben sich jetzt aus diesem, etwas komplexeren Aufbau?

Loose Kopplung
Da die Applikationen nicht stark gekoppelt sind, können diese besser ausgetauscht, erweitert und skaliert werden.

Stabilität
Sollte eine der Applikationen nicht sauber funktionieren, da sich beispielsweise Fehler eingeschlichen haben, werden die anderen Applikationen davon nicht beeinträchtigt.

Nachhaltigkeit
Durch das Trennen der Applikation in ihre Verantwortungsbereiche verhindern wir die Pflege einer Riesen-Applikation. Dadurch wird die Code-Basis übersichtlicher und es kann unabhängig voneinander an den einzelnen Komponenten entwickelt werden.

Weitere Services und mehr Kommunikation

Natürlich ist eine IT-Infrastruktur selten so überschaubar. Bei nine.ch haben wir beispielsweise viele Services in Form von Daemons. Also Services, die immer laufen und auf gewisse Ereignisse warten, auf diese sie entsprechend reagieren.

Beispielsweise ein Daemon, welcher bei Änderungen an der Netzwerk-Konfiguration eines Servers die DHCP-Konfiguration auf den DHCP-Servern neu schreibt.

Möchten wir solche Daemons einbinden, müssen wir uns noch Gedanken über den geeigneten Kommunikationskanal machen. Im vorherigen Beispiel für eine SOA, kommuniziert die Applikation via HTTP. Dabei handelt es sich allerdings um eine ziemlich starke Kopplung, wobei gegenseitige Aufrufe sogar blockierend sein können.

Bei nine.ch setzen wir in diesem Fall auf einen Message-Bus (AMQP). Kurz zusammengefasst handelt es sich dabei um ein Protokoll, bei dem Nachrichten an einen Broker geschickt werden, welche dann von einem Consumer abgerufen werden. Abhängig von der Nachricht, kann der Consumer dann die entsprechende Logik ausführen.

Als konkretes Beispiel wird beim Ändern der Netzwerk-Konfiguration eine AMQP-Nachricht verschickt. Der Daemon, der in diesem Fall die DHCP-Konfiguration neu schreiben soll, tut dies sobald er die entsprechende Nachricht sieht.

Mit diesem Aufbau weiss weder der Daemon etwas von der Serververwaltung, noch die Serververwaltung vom Daemon. Ausserdem kann ohne jegliche Anpassung an dem bestehenden Aufbau, einfach ein weiterer Consumer der Nachrichten angehängt werden. Beispielsweise ein Daemon, der bei Änderungen der Netzwerkkonfiguration die Firewall-Regeln neu schreiben soll.

Folgendes Diagramm visualisiert dieses Konzept: daemons-with-amqp

Einbinden von Legacy-Applikationen

Ein weiteres Szenario, welches in unseren Augen wichtig ist, möchten wir noch aufzeigen - den Umgang mit Legacy-Applikationen. Also ältere Applikationen, die über lange Zeit angewachsen sind. Man würde sie am liebsten ersetzen, wofür aber oft Zeit und Ressourcen fehlen. Also lebt man mit ihnen, möchte sie aber möglichst wenig erweitern.

Wie bindet man nun aber eine solche Applikation in eine SOA-Infrastruktur ein, ohne diese beispielsweise um eine REST-Schnittstelle zu erweitern?

Bei nine.ch haben wir zum Beispiel eine in die Jahre gekommene PHP-Applikation, in welche wir nur wenig Aufwand investieren. Trotzdem enthält sie relevante Informationen und es existieren Abhängigkeiten. Da man sie also nicht einfach ersetzen kann, haben wir uns für den Ansatz entschieden, sie mit einer Connector-Applikation in unsere Infrastruktur einzubinden. Folgendes Diagramm visualisiert dies: Legacy Applikation

Bei der Connector-Applikation handelt es sich lediglich um eine API, über die auf die Daten der Legacy-Applikation zugegriffen werden kann. Der grösste Vorteil ist dadurch, dass nur noch eine direkte und klar spezifizierte Abhängigkeit zur Legacy-Applikation existiert, nämlich die des Connectors. Sollte der Tag kommen, an dem die Legacy-Applikation ausgetauscht wird, muss lediglich die Implementation des Connectors angepasst werden.

Weitere Tipps für SOA

Wir möchten hier noch einige Tipps zusammenfassen, welche das Entwickeln in einer SOA sowie dessen Pflege vereinfachen:

Alle Apps gleich aufbauen

Bei nine.ch setzen wir auf Ruby und Ruby on Rails. Daraus ergibt sich der Vorteil, dass man sich in der Applikation sofort zurechtfindet, da alle Applikationen gleich aufgebaut sind.

Monolithen im Zaum halten

Auch wenn wir viele Services haben, heisst das nicht, dass wir keine Monolithen haben. Beispielsweise hat unsere Kundenverwaltung einen grossen Umfang angenommen. Das muss aber nicht schlecht sein. Wichtig dabei ist, dass man Monolithen im Zaum hält, indem man bei neuen Funktionen immer genau überlegt wo diese hingehören.

Effizientes Deployment

Zum effizienten Entwickeln ist ein effizientes Deployment unabdingbar. Bei nine.ch setzen wir dafür auf ChatOps. Möchten wir eine neue Version eines Services verteilen, reicht eine Zeile im Chat und ein Bot veröffentlicht entsprechend die neueste Version automatisch.

Tests, Tests, Tests!

Man kann es nicht genug erwähnen. Tests sind unumgänglich für eine nachhaltige Software-Infrastruktur. Sie gewährleisten die Funktionalität der Services, auch nach grösseren Änderungen. Mit einer umfangreichen Test-Suite wird das Entwickeln eines neuen Features oder Ändern bestehender Funktionalitäten kein Hoffen, dass noch alles klappt. Daraus ergibt sich eine Sicherheit, die wir beim Entwickeln nicht mehr missen wollen.

Fazit

Bei nine.ch setzen wir stark auf SOA (und Microservices). In Zahlen umfasst unsere Infrastruktur mittlerweile mehr als 25 Services. Nachfolgend eine kurze Zusammenfassung über die Vorteile sowie Nachteile, die sich für uns daraus ergeben:

Vorteile

  • Kapselung: Kleine abgekapselte Applikationen haben einen klar definierten Aufgabenbereich und können daher einfach ersetzt und weiterentwickelt werden.
  • Deployment: Vereinfachtes Deployment, da Änderungen jeweils weniger umfangreich sind und somit schnell ausgerollt werden können.
  • Verteilt: Bei einem Problem oder Ausfall ist nur ein kleiner Teil der Infrastruktur betroffen. Einzelne Services lassen sich nach Anforderung skalieren.

Nachteile

  • Entwicklungsprozess: Für die Entwicklung an einzelnen Komponenten müssen abhängige Services ebenfalls in der Entwicklungsumgebung betrieben werden. Dies kann im Entwicklungsprozess zu einem Overhead führen.
  • Komplexes Gesamtsystem: Den Überblick über die gesamte Infrastruktur zu behalten, ist nicht immer einfach. Insbesondere die Entscheidungen, welche Services für welche Aufgaben verantwortlich sind, müssen wohlüberlegt sein.
  • Höherer Wartungsaufwand: Der Wartungsaufwand von mehreren unterschiedlichen Applikationen ist grundsätzlich höher. Dies ist zum Beispiel dann spürbar, wenn eine Sicherheitslücke in einem Framework geschlossen wird und mehrere Applikationen aktualisiert und ausgerollt werden müssen.

Wie man sieht, ist auch SOA nicht perfekt. Man muss stets darauf achten, die Übersicht über die komplette Infrastruktur zu bewahren und nicht durch wachsende Komplexität ineffizient zu werden. Gelingt dies, ist eine Service Orientierte Architektur die perfekte Umgebung um schnell, agil und qualitativ hochwertig zu entwickeln.