Protobuf ist Googles Antwort auf die Anforderungen an ein effektives, effizientes und zugleich flexibles Serialisierungsformat als Alternative zu JSON oder XML. Seine Vorteile ebnen den Weg für bahnbrechende Lösungen für die Probleme, mit denen moderne Unternehmen bei der Schaffung einer digitalen Systemlandschaft in der Cloud konfrontiert werden.
🌎 Read this article in english
Cloud native bedeutet neu zu denken
Die Konstruktion eines Fachwerkhauses mit traditionellen Methoden und Werkzeugen hat gewiss seinen Scharm und ist eine nicht zu verachtende Leistung. Moderne Null-Emissions-Häuser mit Smart-Home-Anbindung lassen sich damit allerdings nicht errichten. Und mal ehrlich, die Anzahl der Kunden, die händeringend ein Fachwerkhaus suchen, ist sehr gering.
Cloudbasierte Anwendungen stellen die Softwarearchitekten von heute vor neue und ungewohnte Herausforderungen. Sie benötigen moderne Verfahren die speziell auf die neuen Herausforderungen der Cloud ausgerichtet sind, damit die Anwendungen zuverlässig und zugleich ressourcenschonend operieren. Ob CPU, Arbeits- oder Festplattenspeicher, alles was weniger gebraucht wird, spart Kosten im Betrieb der Cloud und ist zugleich ein Schritt hin zu einer Green-IT.
Zahlreiche Herausforderungen
Ich kann nicht alle Herausforderungen in der erforderlichen Tiefe in diesem Artikel behandeln. Der Text würde so lang und kompliziert, dass niemand ihn zu Ende lesen würde. Stattdessen konzentriere ich mich auf die Serialisierung. Unter Serialisierung versteht man die Umwandlung von strukturierten Daten in ein für die Übertragung oder Speicherung geeignetes Format.
In modernen verteilten Systemen ist es entscheidend, ein schnelles und zuverlässiges Serialisierungsformat zu wählen. Die Serialisierung selbst ist nicht aufwändig. sie wird aber häufig benutzt. Die Entscheidung für ein optimales Format hat also einen großen Einfluss auf das Gesamtdesign der Cloudanwendung.
Ein gut gewähltes Format stellt sicher, dass Daten schnell und mit minimalem Overhead über das Netzwerk übertragen werden. Darüber hinaus ist ein zuverlässiges Format entscheidend um Fehler bei der Datenrekonstruktion zu vermeiden und damit die Datenintegrität sicherzustellen.
Automatisierung als Erfolgsfaktor
Aktuell ist JSON das von vielen präferierte Serialisierungsformat. Es hat im Laufe der Jahre XML den Rang abgelaufen. Der Vorteil von JSON, als für Menschen einfach zu erstellendes und lesbares Format, kommt aber gerade beim Einsatz für die Kommunikation zwischen Microservices nicht wirklich zum Tragen. Daten und Prozesse werden zwar durch menschliche Interaktion angestoßen, laufen danach aber ausschließlich nachgelagert zwischen Systemen ab und reagieren dabei eher auf Events als auf Benutzer.
Auch das Argument, dass Entwickler das Serialisierungsformat lesen müssen ist nicht mehr griffig. Cloud-Anwendungen laufen in Containern, die selbst durch Systeme, wie zum Beispiel Kubernetes, überwacht und kontrolliert werden. Manuelle Eingriffe sind dabei nicht das Mittel der Wahl um Probleme zu analysieren und zu beheben.
Auch das Aktualisieren der Anwendung erfolgt durch eine Continuous-Delivery-Pipeline in kurzen Intervallen, um so den Anforderungen des Marktes nach schnellen und ständigen Anpassungen gerecht zu werden. Die Automatisierung ist in diesem Rahmen alternativlos, gewährleistet sie doch den sicheren und, in Zeiten von Fachkräftemangel, günstigen Betrieb.
Gamechanger Protobuf
Ich werde in diesem Artikel kurz auf die Begriffe und Funktionsweise von Protobuf eingehen. Dann erläutere ich seine neuartigen Konzepte und Eigenschaften und inwiefern diese die Mängel von JSON beheben. Damit begründe ich, warum Protobuf eine überragende Verbesserung im Vergleich zu JSON ist und damit die nächste Stufe in der Entwicklung der Serialisierungsformate darstellt.
Sicher durch präzise Definition und starke Typisierung
Um Daten zu serialisieren, müssen sie zunächst einmal strukturiert beschrieben werden. Bei Protobuf werden die Datenstrukturen in Dateien mit der Endung .proto definiert. In dieser Proto-Definition wird ein Objekt durch eine Nachricht („Message") beschrieben. Eine Message kann eine beliebige Anzahl von Feldern („Fields") beinhalten. Ein Field hat einen Bezeichner, einen Typ und eine, für diese Message, eindeutige Nummer. Der Typ eines Feldes kann wiederum eine Message sein, wodurch eine Baumstruktur entsteht wie sie aus JSON und XML bekannt ist.
syntax = "proto3";
package example;
message Book {
string title = 1;
repeated Page pages = 2;
}
message Page {
string content = 1;
}
Das obrige Codebespiel beschreibt eine vereinfachte Datenstruktur für ein Buch („Book"). Das Buch hat einen Titel von Typ string, der eine beliebige Zeichenkette beinhalten kann. Das Buch verfügt darüber hinaus über beliebig viele („repeated") Seiten, die als je eine Message vom Typ „Page" hinterlegt werden. Die Seiten wiederum haben den Text der auf ihnen steht im Field „content" hinterlegt. Die explizite Angabe von Typen in der Proto-Definition hilft Fehler zu vermeiden und stellt die Konsistenz über Systemgrenzen hinweg sicher. Protobuf unterstützt dabei die gängigen Datentypen von Programmiersprachen. Zudem stellt Google eine Sammlung von erweiterten Typen, die sogenannten WellKnownTyps, bereit. Darüber hinaus können eigene Datentypen über selbst definierte Messages erstellt werden.
Hohe Produktivität durch Codegenerierung
Bei anderen Serialisierungsformaten wird viel wertvolle Entwicklungszeit damit verbracht die Datenstrukturen als Objekte in der Programmiersprache noch einmal anzulegen und bei Änderungen diese kontinuierlich nachzuziehen. Die Arbeit ist aufwändig, aber nicht sehr herausfordernd, was dazu führt, dass sich schnell Fehler einschleichen. Generische Mapper versprechen zwar den Aufwand zu reduzieren, sie sind allerdings in allen Fällen, wo man vom Normalanwendungsfall abweicht, selbst schwer zu konfigurieren.
Protobuf setzt daher auf eine automatische und kontinuierliche Codegenerierung und unterstützt dabei gleich mehrere Programmiersprachen. Aus der Proto-Definition wird direkt der Code für die Datenstruktur generiert, womit ein Großteil des Aufwands anderer Ansätze entfällt. Außerdem ist garantiert, dass Sender und Empfänger immer die gleiche Implementierung nutzen solange sie die selbe Version des Protoschemas haben. Der generierte Sourcecode kann zudem flexibel um zusätzliche Methoden ergänzt werden, um so die Benutzung von eigenen Datentypen komfortabler zu machen.
Streng definierter aber erweiterbarer Vertrag
Die Proto-Definition ist ein Schnittstellenvertrag („Contract") zwischen dem Sender und dem Empfänger. In Protobuf wird ausschließlich auf einfache Strukturelemente gesetzt. So bezeichnet das Keyword repeated eine Liste einer Message ohne Aussagen über deren genaue Anzahl zumachen[vgl. Abb. 1]. Einerseits führt dies dazu, dass der Sender mögliche Einschränkungen auf Empfängerseite nicht aus dem Contract herauslesen kann. Andererseits kann dieses auch als Chance gesehen werden den Vertrag flexibler und damit leichter erweiterbar zu gestalten. Die Möglichkeit den Vertrag leicht ändern zu können und gleichzeitig die Integrität der Anwendung beizubehalten, ist von einem unschätzbaren Wert für eine sich ständig weiterentwickelnde Systemlandschaft.
Einfache Schemaevolution
Bei dem Design von Protobuf wurde ein hoher Wert auf Kompatibilität gelegt. Eine Änderung ist dann abwärtskompatibel, wenn die neue Version eines Empfängers Nachrichten eines Senders einer alten Version verarbeiten kann. Andersherum ist eine Änderung dann vorwärtskompatibel wenn die neue Version eines Senders weiterhin mit der alten Version des Empfängers funktioniert.
Durch die Einhaltung von nur wenigen einfachen Regeln erhält man mit Protobuf sowohl Abwärts- als auch Aufwärtskompatibilität. So darf der Typ und die Nummer eines Fields nie geändert werden. Eine Message und ein Field können nicht gelöscht werden. In der Syntax proto3 wird zudem auch auf die Definition von Pflichtfeldern verzichtet, da Erweiterungen eines Vertrags immer optional sein müssen, um die Kompatibilität zu erhalten.
Kompatibilität für Zero-Downtime
Abwärts- und Vorwärtskompatibilität sind besonders dann wichtig, wenn man nicht gewährleisten kann, dass Sender und Empfänger und alle Nachrichten gleichzeitig auf eine neue Version einer Schnittstellenbeschreibung aktualisiert werden können. Dies ist für Cloudanwendungen eine wichtige Eigenschaft.
Volle Kompatibilität ermöglicht es einen Sender und einen Empfänger unabhängig voneinander auszurollen, wobei auf eine aufwändige Koordinierung der Reihenfolge verzichtet und Continuous-Delivery somit erst ermöglicht wird. Der Einsatz einer modernen Softwarelösung für das Management von containerisierten Anwendungen, wie zum Beispiel Kubernetes, ermöglicht zudem ein automatisches Rolling Update. Dabei wird eine neue Version der Anwendung ohne Downtime im laufenden Betrieb ausgerollt. Die Benutzer bekommen davon nichts mit, was einen unterbrechungsfreien Service und ein optimales Kundenerlebnis erlaubt.
Überragende Effizienz da binär und minimalistisch
Bei Protobuf werden die Nachrichten im Binärformat serialisiert. Dabei werden nur die Nummer und der jeweilige Wert des Feldes einer Nachricht gespeichert. Um die Nachricht später auslesen zu können, benötigt man deshalb die Proto-Definition. Damit verzichtet die Serialisierung bewusst auf unnötigen Ballast, die für den eigentlichen Nutzen nicht notwendig sind. Durch die geringe Datenmenge ist das Erzeugen und Lesen von Nachrichten somit sehr schnell.
Allerdings kann es durch die minimale Speicherung der Nachricht und die hohe Kompatibilität bei Fehlern in der Entwicklung zu unerwartetem Verhalten kommen. So können Nachrichten unter Umständen durch eine fremde Proto-Definition deserialisiert werden, ohne dass ein Fehler auftritt. Deshalb ist es zwingend notwendig die Benutzung von Protobuf durch automatisierte Tests abzusichern. Mit diesen kann auch die Kompatibilität zu alten Versionen sichergestellt werden.
Eine manuelle Fehleranalyse von Nachrichten im Einzelfall ist einfach möglich, indem man die Binärinformationen in ein Objekt umwandelt. Zudem lassen sich Nachrichten einfach in ein JSON-Format konvertieren. Der dafür notwendige Code wird entsprechend der Proto-Definition vollständig generiert. Es können so auch LegacySysteme, die ausschließlich mit JSON arbeiten können, an moderne Anwendungen angeschlossen werden. Die Vorteile von Protobuf können hierbei zumindest teilweise genutzt werden.
Fazit
Kein Serialisierungsformat, weder Protobuf noch JSON, darf als „Goldener Hammer" verwendet werden. Protobuf ist daher sicher keine Alternative zu JSON für alle Anwendungsfälle und wurde auch nicht dafür entwickelt. Die Stärken von Protobuf machen es zu einem flexiblen und zugleich besonders effizienten Serialisierungsformat. Der Fokus des Einsatzgebietes liegt dabei primär auf dem Datenaustausch zwischen Softwaresystemen. Es kann daher besonders einfach überall dort eingesetzt werden, wo im Rahmen der Digitalisierung automatisierte Prozesse geschaffen werden.
Die initiale Einführung von Protobuf mag einen Einarbeitungs- und Lernaufwand bedeuten, der sich aber durch die einheitliche Verwendung des Serialisierungsformats für möglichst viele Anwendungsfälle schnell wieder auszahlt. Durch den hohen Automatisierungsgrad und die Codegenerierung kann sich die Entwicklung besser auf ihre eigentliche Aufgabe - das Lösen von Problemen - konzentrieren.
Jetzt sind deiner Kreativität keine Grenzen mehr gesetzt, um basierend auf Protobuf Lösungen für deine Domäne zu entwerfen. Ich bin sehr gespannt auf deine Ideen und Vorschläge. Denn streben wir nicht letztlich alle danach, unsere Software durch ein erstklassiges Design kontinuierlich zu verbessern und damit zum Erfolg zu führen?
In zukünftigen Artikeln werde ich selbst einige konkrete Beispiele liefern, wie ich Protobuf in der Vergangenheit eingesetzt habe. Am besten folgst du mir, um keinen meiner zukünftigen Artikel zum Thema Protobuf zu verpassen.
Top comments (0)