MealDB Chatbot mit Google Dialogflow

Ein Projekt von Ronja Brauchle, Julia Cypra und Lara Winter

Einleitung

Gab es bereits drei Tage hintereinander Pasta mit Pesto? Ist das einzig abwechslungsreiche in deinem Speiseplan die Entscheidung ob die klassische Tiefkühlpizza mit Salami oder die extravagantere Wahl des Flammenkuchens nach Bauernart in den Ofen geschoben wird?  Unser MealBot hilft genau bei diesen monotonen und inspirationslosen Phasen: Er schlägt Rezepte basierend auf Lebensmitteln vor, die man gerade zuhause liegen hat; er kann nach Länderküchen und Essensvorlieben Mahlzeiten heraussuchen oder einfach zu einer dir bereits bekannten Mahlzeit das Rezept ausgeben.

Wir haben für das Projekt Dialogflow von Google verwendet, das eine Engine basierend auf NLU (Natural Language Understanding) ist und mit der man intelligente Chatbots erstellen kann. Durch das Anbinden an die MealDB (https://www.themealdb.com/) mithilfe der MealAPI kann unser Chatbot dem User hunderte von Rezepten ausgeben. Der MealBot wurde in Telegram integriert und ist somit dort für jeglichen Chitchat anzutreffen.

Entwurf und Architektur

https://cloud.google.com/static/dialogflow/es/docs/images/fulfillment-flow.svg

Die obige Abbildung visualisiert die Auftragsausführung nach einer Benutzereingabe. Wie bereits erwähnt, ist unser Chatbot in den Messengerdienst Telegram integriert, von dort wird die Benutzereingabe weiter an Dialogflow geleitet. Dank der in Dialogflow integrierten KI kann die Benutzereingabe einem der passenden individuell erstellten Intents zugeordnet werden. Dabei werden außerdem auch bestimmte Parameter aus der Eingabe extrahiert. Ein Intent kann eine vorgefertigte statische Antwort beinhalten, es kann aber auch unter dem Punkt „Fulfillment“ ein Webhook Aufruf aktiviert und somit passender Code getriggert werden. Im Falle eines Webhook Aufrufes werden die extrahierten Parameter, sowie weitere Informationen zu dem zugeordneten Intent in einer JSON HTTPS POST Anfrage, dem Fulfillment Request, an den Webhhokdienst geschickt. Der Webhook kann selbst gehostet werden, dieser muss dann HTTPS POST Anfragen in Form von JSON verarbeiten. In unserem Fall haben wir den Code zur Auftragsausführung im Inline-Editor von Dialogflow erstellt und somit in einer Cloud Function bereitgestellt. Die Cloud Function wird dann durch den Dialogflow getriggert und erhält die Daten aus der JSON Anfrage. Die Cloud Function besteht lediglich aus einer index.js, die Funktionen für die jeweiligen Intents enthält. Durch das passende Intent Matching wird dann auch die jeweilige Funktion ausgeführt. In dieser Funktion wird unsere externe API, die MealDB, abgefragt. Dabei wird je nach Intent ein zugehöriger Endpoint mit den passenden Parametern angesprochen. Die Antwort der MealDB Abfrage wird dann zusammen mit anderen Daten in der Webhook Antwort wieder an Dialogflow zurückgeschickt. Dialogflow extrahiert aus der Antwort die benötigten Daten und sendet diese letztendlich an Telegram, sodass der Endbenutzer die Antwort erhält.

Die untenstehende Abbildung verdeutlicht nochmal den Ablauf mit den von uns benutzten Technologien.

Der Vorteil von Cloud Functions ist, dass diese serverless, günstig und skalierbar sind. Das heißt die Cloud Function ist ereignisgesteuert und wird nur bei einem Event getriggert. Dadurch und wegen der Skalierbarkeit halten sich die Kosten gering.

Basics aka die Bausteine von Dialogflow

Intents

Intents ermöglichen es dem Agenten die Motivation hinter einer bestimmten Benutzereingabe zu verstehen. Jeder Intent stellt eine Aufgabe oder Handlung dar, die der Benutzer ausführen möchte. Im folgenden Bild sieht man die von uns für den MealBot erstellten Intents inklusive der Erklärung dieser.

Ausdrücke, die dasselbe bedeuten, aber auf unterschiedliche Weise konstruiert werden, werden demselben Intent zugeordnet. Somit kommen wir direkt zum ersten Bestandteil (von dreien) eines Intents, und zwar zu den Trainingsformulierungen:

1.Trainingsformulierungen

Trainingsformulierungen sind Beispielsätze für das, was der Endnutzer sagen könnte. Wenn der Endnutzerausdruck einer dieser Sätze ähnelt, stimmt Dialogflow mit dem Intent überein. Jedoch muss man nicht jede denkbare Formulierung angeben, da das integrierte maschinelle Lernen die Liste automatisch um ähnliche Äußerungen erweitert.

2. Parameter

Parameter sind die aus dem Benutzerausruck extrahierten Werte (in der ersten Trainingsformulierung wären es “garlic” und “salt”). Jeder Parameter hat einen Entitätstyp (siehe Abschnitt Entities; hier “Ingredients”). Der bzw. die Parameter werden je nach Intent an den passenden Endpoint geschickt. Aus dem von der Meal API zurückgeschickten Datensatz formt man dann eine Antwort, die dem User ausgegeben wird.

3. Antwort

Bei den meisten Intents konstruieren und formatieren wir die Antwort im Inline-Editor, wo wir mit dem von der API zurückgeschickten Datensatz direkt weiterarbeiten können. Bei Smalltalk bezogenen Intents, die keine API-Anfrage benötigen, wird die Antwort per GUI angegeben:

Beispiel Intent “thanks”

Man unterscheidet bei Antworten zwischen zwei Arten:

1.Standard-Antwort: Bot antwortet auf die Frage und ist anschließend bereit weitere unspezifische Fragen zu beantworten. 

Bsp: Intent “random-meal” : Der User fragt, ob der Bot irgendein Rezept vorschlagen könnte -> Der Bot gibt direkt eins aus und ist bereit, andere Fragen zu beantworten.

2. follow-up-intents: Bot antwortet auf die erste Frage, erwartet dann aber vom User weitere Eingaben, die sachlich auf die erste Frage aufbauen.

Bsp: alle “filter-by” Intents: Der User fragt beispielsweise nach chinesischem Essen, woraufhin der Bot ihm 3 Rezepte vorschlägt und er vom User erwartet, eins auszuwählen.

Entities

Entities werden verwendet, um bestimmte Informationen herauszufiltern, die der Benutzer erwähnt. Sie nehmen nützliche Daten auf und stellen sie zur weiteren Verarbeitung bereit. Man unterscheidet zwischen zwei Arten:

1.System entities, die bereits in Dialogflow enthalten sind und mit denen der Agent ohne zusätzliche Konfiguration Informationen zu einer Vielzahl von Konzepten extrahieren kann.

Bsp: Dialogflow erkennt direkt eine Zeitangabe, ein Datum oder eine Zahl (sys.time, sys.date, sys.number)

2. Developer entities definiert der Entwickler anhand seines individuellen Datensatzes selbst. Bezüglich der Parameter, die wir an die Endpoints der Meal API schicken, haben wir folgende Entities definiert:

“Ingredients”-Entität: Lebensmittel, die in der MealDB vorhanden sind und die der Agent bei einem Benutzerausdruck identifizieren sowie extrahieren könnte

Entity Dilemma

Um eine Benutzereingabe richtig zu verstehen und die passenden Parameter herauszufiltern, muss Dialogflow die zugehörigen Entitys kennen. Denn ist ein Entity vorher nicht bekannt, kann Dialogflow dies auch nicht erkennen und somit eine Eingabe auch nicht dem passenden Intent zuweisen. Sollte der Benutzer zum Beispiel eingeben: „I want to cook pancakes.“, Dialogflow aber nicht weiß was pancakes sind, kann er damit nichts anfangen. Aus diesem Grund mussten wir alle möglichen Gerichte, Länder, Kategorien und Zutaten als Entitys abspeichern. Bei den Kategorien und Ländern ging dies auch relativ schnell. Bei dem Entity „AreaAdjective“ mussten wir ein Adjektiv herausfiltern, da der API Endpoint nur diese akzeptiert hat. So funktioniert zum Beispiel eine Abfrage mit „italian“, wohingeben „Italy“ keine Ergebnisse liefert. Durch das Hinzufügen von Synonymen konnten wir das Problem aber schnell lösen, denn so wird „Italy“ automatisch zu „italian“ umgewandelt. Bei den Gerichten und Zutaten hat es sich aber ein bisschen schwieriger gestaltet. Denn es gibt keinen Endpoint bei der MealDB, mit welchem man alle vorhandenen Rezepte abfragen kann, man kann lediglich alle Rezepte mit einem bestimmten Anfangsbuchstaben abfragen. Deshalb haben wir uns eine kleine Hilfsfunktion erstellt, die in einer Schleife Abfragen mit allen möglichen Buchstaben macht. Die einzelnen Zwischenergebnisse haben wir dann in ein Array gepushed, sodass wir zum Schluss alle möglichen Rezepte zusammen hatten. Diese Rezepte haben wir uns dann ausgeben lassen über die Konsole und als CSV Format in dem Entity „Ingredients“ hochgeladen. Dazu der passende Code, der vielleicht nicht der schönste ist, aber funktioniert hat.

Die Zutaten konnten wir zwar alle über einen Endpoint abfragen, da es aber viel zu vielen waren, um sie von Hand als Enitiy einzugeben, haben wir uns dafür auch eine Hilfsfunktion erstellt. Mit dieser Funktion haben wir die Abfrage formatiert und wieder ausgegeben, sodass wir alle Zutaten auf einmal im CSV Format hochladen konnten. Der Code dazu funktioniert ähnlich wie der obere.

Kontext

Schon mal an einer regen Diskussion von Fremden vorbeigelaufen und Phrasen aufgeschnappt, die für einen als Außenstehender überhaupt keinen Sinn ergeben haben? 

So wie Menschen einen Kontext brauchen, um herauszufinden, was ein bestimmtes Wort oder bestimmter Satz bedeutet, benötigen auch Chatbots sie. Ohne Kontext könnte das Wort bzw. der Satz absolut keine Bedeutung haben oder etwas völlig anderes bedeuten als die ursprüngliche Absicht des Benutzers

Unser persönliches (philosophisches) Kontext-Dilemma

Wie bei den Intents oben bereits kurz skizziert, ist unser Rezept-Vorschlag-Konzept wie folgt aufgebaut: Der Benutzer fragt idealerweise nach einem Rezept basierend auf einer Länderküche, Essenskategorie etc. Darauffolgend schlägt der Agent ihm bis zu 3 Rezepte vor, von denen sich der Benutzer für eins entscheiden kann. Wie man bereits schon ahnen könnte, ist hier ein Kontext erforderlich, damit der Chatbot Aussagen wie “Option 2”,“Ich will das erste” auch zuordnen kann.

Mit voller Motivation haben wir für jeden Intent einen follow-up intent zusammengeklickt, der genau diese Auswahl anhand der Nummerierung der vorgeschlagenen Rezepte erkennen sollte. Somit wurde logischerweise für jeden Intent ein eigener Output-Kontext erstellt, der bei dem jeweiligen follow-up Intent als Input-Kontext wieder eingespeist wurde. Schnell wurde uns beim Code-Schreiben bewusst, dass eigentlich jeder follow-up intent die selbe Logik implementiert, und zwar zu erkennen welches Rezept ausgewählt wurde und dieses formatiert an den User zurückzugeben. Die Idee schlich sich herein, alle individuellen Kontexte der Intents in einen zusammenzufassen und diesen einen bequem in einer Funktion zu verwalten und für alle follow-up intents aufzurufen. Wir gaben der Idee nach, da alles nach unseren Erwartungen richtig ausgegeben wurde. Trotzdem fühlt sich die Lösung nicht ganz “clean” an, da sprachwissenschaftlich gesehen eigentlich jeder Intent vom Inhalt her einen eigenen Kontext verdienen sollte: Ob man gerade nach einer Essenskategorie oder Länderküche gefragt hat, sollte in einer echten Konversation schon einen Unterschied machen. Programmatisch hat es uns die Sache jedoch wesentlich erleichtert.

API Routen

axios.get(“https://www.themealdb.com/api/json/v1/1/categories.php “)

Auflisten aller meal categories. Wird genutzt, um die Beschreibung einer vom Endnutzer eingegebenen Kategorie herauszufiltern und auszugeben.

axios.get(“https://www.themealdb.com/api/json/v1/1/random.php“)

Ausgabe des Rezeptes eines random meals.

axios.get(“https://www.themealdb.com/api/json/v1/1/filter.php”, { params: { a: inputArea } })

Filtern der Gerichte nach einem vom Endnutzer eingegeben Land. Wird genutzt um drei random Gerichte dieses Landes als Optionen dem Nutzer zur Verfügung zu stellen

axios.get(“https://www.themealdb.com/api/json/v2/9973533/filter.php”, { params: { i: paramsIngredients } })

Filtern der Gerichte nach einer oder mehreren vom Endnutzer eingegeben Zutaten. Wird genutzt um drei random Gerichte mit diesen Zutaten als Optionen dem Nutzer zur Verfügung zu stellen.

axios.get(“https://www.themealdb.com/api/json/v1/1/search.php”, { params: { s: inputMeal } })

Filtern der Gerichte nach einem vom Endnutzer eingegeben Gericht. Wird genutzt um bis zu drei Arten dieses Gerichtes als Optionen dem Nutzer zur Verfügung zu stellen.

axios.get(“https://www.themealdb.com/api/json/v1/1/filter.php”, { params: { c: inputCategory } })

Filtern der Gerichte nach einer vom Endnutzer eingegeben Kategorie. Wird genutzt um bis zu drei Optionen aller Gerichte aus dieser Kategorie als Optionen dem Nutzer zur Verfügung zu stellen.

axios.get(“https://www.themealdb.com/api/json/v2/9973533/lookup.php”, { params: { i: mealId } })

Suche nach einem bestimmten Gericht durch den Parameter id und Ausgabe des Rezeptes.

Beispiel Cloud Function for Firebase – FilterByArea:

In der Funktion wird als Parameter der Webhook Client agent übergeben. Über diesen bekommt die Variable InputArea als Wert den Parameter des Entitätstyps “AreaAdjective”, der vom Nutzer eingeben und von Dialgogflow erkannt  und extrahiert wurde. Mit Hilfe der Bibliothek axios wird auf die MealDB zugegriffen. Dabei wird die URL mit inputArea übergeben.  Als Antwort kommen bei res nun die Daten aus der MealDB zurück. Diese werden an die Funktion handleResult() übergeben, welche die Daten filtert. Letztendlich werden die gefilterten Daten über agent.add() zur Antwort, die dem Endnutzer dann angezeigt wird.

Chatbot in Action

1. Intents und Entitäten: Die Nutzereingabe wird mit Hilfe der Trainingssätze und dem Parameter mit dem Entitätstyp dem passenden Intent zugeordnet, dem “filter-by-ingredients” Intent. Somit kommt die passende Antwort zurück. Die Nutzereingabe carrot wird als Parameter “Carrots” des Entitätstypen “ingredients” erkannt. Dialogflow kann dies zuordnen, auch mit anderer Groß – und Kleinschreibung bzw. Ein – oder Mehrzahl.

2. FollowUpIntent: Option 0: Dialogflow erkennt die 0 als passend zu den Trainingssätzen vom Intent “filter-by-ingredients – zero”. Dieser ist ein FollowUp Intent auf “filter-by-ingredients”.

3. Kontext:  Die Nutzereingabe wurde dem “filter-by-area” Intent mit dem Parameter “areaAdjective” = thai zugeordnet. Außerdem wurde der Kontext “user-data” hergestellt. Der Nutzer gibt nun die Option 2 an und der Chatbot befindet im FollowUpIntent “filter-by-area – options” mit dem Parameter value = 2. Das passende Rezept wird ausgegeben. Gibt der Nutzer nun die Option 3 ein, so wird wieder das passende Rezept ausgegeben. Der Chatbot kann die 3 deswegen immer noch als number Parameter des FollowUpIntent “filter-by-area – options” erkennen, da er sich noch im Kontext  “user-data” befindet. Für solche Zusammenhänge ist also der Kontext nötig.

4. Problem: Lasagna Problem: Unter der Option Lasagna kann der Chatbot nichts finden. Unter der Option Lasagna Sandwich jedoch schon. Die Erwartung des Endnutzers könnte allerdings sein, bei der Suche nach Lasagna alle Rezepte die Lasagna im Namen haben zu finden, u.a. Lasagna Sandwich. Die Meal Optionen im Chatbot sind allerdings an die in der MealDB gebunden und in der MealDB gibt es kein Gericht Lasagna. Demnach gibt es in der “Meal” Entitäten Liste auch keine Lasagna. Dialogflow sucht die Entitäten nach Lasagna ab, kann aber keinen genauen Treffer finden und den Wortteil “Lasagna” aus “Lasagna Sandwich” nicht extrahieren und als richtig erkennen. Der Nutzer muss also den gesamten Namen des Gerichts angeben.

Testing

Zum Testing haben wir leider nur wenig gefunden, vor allem zu automatischen Tests, um den Dialogflow als Ganzes zu testen. Zwar gibt es in der Dialogflow GUI die Möglichkeit einzelne Sätze zu testen, wobei auch der zugehörige Intent, Context sowie die extrahierten Parameter angezeigt werden, was auch sehr hilfreich zum Debuggen war. Der nebenstehende Screenshot zeigt, wie dies dann aussieht. So werden zum Beispiel unter dem Punkt „Contexts“ die passenden Contexte angezeigt, da es sich um einen follow-up Intent handelt. Außerdem wurde der passende Intent „filter-by-area“ zugeordnet, sowie der Parameter „italian“. Unter dem Punkt „Diagnostic Info“ kann man noch zusätzlich die JSON Anfrage und Antwort vom Webhook anschauen.

Jedoch kann man in der Google Cloud Console die Cloud Function testen, wie der untenstehende Screenshot zeigt.

Dazu kopiert man die JSON Webhook Anfrage aus der obigen „Diagnostic Info“ und startet den Test. Wie man sehen kann, funktioniert die Anfrage und die passende fulfillmentMessage mit der MealDB Antwort kommt zurück. Außerdem werden darunter auch die Logs angezeigt.

Unser Fazit mit Dialogflow

Vorteile

  1. Dialogflow basiert auf einem sehr intuitiven Konzept; Intents, Entities etc. versuchen die Charakteristiken der natürlichen Sprache nachzustellen, sodass es einem leicht fällt die Funktionsweise eines Chatbots nachzuvollziehen.
  2. Die GUI ist sehr einfach und simpel gehalten; man konnte sich auch ohne Hilfe der Dokumentation schnell zurechtfinden.
  3. Da die KI bereits zur Verfügung gestellt wird, sind keine tieferen Kenntnisse in dem Gebiet notwendig.
  4. Der 90 Tage Testzeitraum war mit circa 300$ Guthaben mehr als ausreichend für einen Chatbot in unserem Rahmen

Nachteile

  1. Der größte Nachteil von Dialogflow war das sehr lange Deployen der cloud functions; ein Durchgang hat circa drei Minuten gedauert. Von daher war es ziemlich nervig, wenn auf Anhieb was nicht funktioniert hat und man bei jedem Rumprobieren, selbst wenn man nur eine Kleinigkeit geändert hat, drei Minuten warten musste. Bei einem tiefergehenden/umfangreicheren Problem, dass von mehreren Codestellen verursacht wurde, kann man sich die Frustration bei dem Fixen mit dieser Wartezeit wahrscheinlich gut vorstellen.
  2. Alle Funktionen mussten in einer einzigen file geschrieben werden. Es kam nicht selten vor, dass paar von uns parallel an der Datei gearbeitet haben, sodass wenn einer das Deployen gestartet hat, die Änderung des anderen verworfen wurden. Wenn eine Person das Deployen gestartet hat, konnten die anderen währenddessen auch nichts abspeichern, da es sofort gecancelled wurde.
  3. Der Inline-Editor ist eher rudimentär aufgebaut und weit von einer vollwertigen IDE entfernt. Es fängt bei banalen Kleinigkeiten an, wie dass man nicht erkennt, welche öffnende Klammer zu welcher schließenden gehört. Aber auch, dass keine Liste an verfügbaren Funktionen vorgeschlagen wird und dass viele Syntaxfehler toleriert werden, die beim Deployen aber zu Errors führen.
  4. Die Dokumentation von Dialogflow ist unvollständig und bleibt sehr oberflächlich. Wir haben viel Stackoverflow benutzt aber mussten letztendlich auch viel Herumprobieren.

Ausblick

Rezepte

Unser Zeitplan ist gut aufgegangen. Da unser Zeitraum – u.a. wegen der limitierten Zeit der Testversion – jedoch begrenzt war, konnten  wir nicht alle erdenklichen Intents in den Chatbot einbauen. Eine Möglichkeit den Chatbot zu erweitern wäre beispielsweise das Erstellen eines dritten FollowUpIntents auf die FilterBy Intents. Dieser würde daraus bestehen, dass der Endnutzer die Option wählt, drei weitere random Meals heraus zu filtern, sofern es genug weitere Gerichte gibt. Im Code müsste ein Teil eingebaut werden, der garantiert, dass die ersten drei Gerichte sich nicht wiederholen und nicht noch einmal mit ausgegeben werden. Der Intent würde außerdem voraussetzen, dass vorher mindestens drei Gerichte ausgegeben wurden. 

Webhook

Um Code nach der Zuordnung zu einem passenden Intent auszuführen, haben wir in Dialogflow unter dem Punkt „Fulfillment“ den Inline-Edior benutzt. Dort gibt es eine index.js und eine index.json, in welchen der gesamte benötigte Code erstellt wird. Der Code wird dann automatisch in Form von einer Cloud Function bereitgestellt und wenn nötig getriggert. Wie aber bereits erwähnt, hat sich das Arbeiten an einer einzigen Datei schwer schwierig gestaltet und das lange Deployen die Arbeit zusätzlich erschwert. Deshalb wäre es bei größeren Projekten mit mehr Intents durchaus eine Überlegung wert, den Webhook selbst zu hosten und die JSON Anfragen zu verarbeiten. So hätte man mehr Kontrolle und kann außerdem besser zusammenarbeiten und debuggen, da das lange Deployen entfällt. Um selbst den Webhook zu hosten, muss dieser ein paar Anforderungen erfüllen:

·   Der Webhook muss HTTPS POST Anfragen verarbeiten, HTTP wird nicht unterstützt

·   Die URL für Anfragen muss öffentlich zugänglich sein

·   JSON Anfragen müssen verarbeitet werden und eine JSON Antwort muss zurückkommen

Improve your storage I/O performance today

an article by Lucas Crämer and Jannik Smidt

DISCLAIMER

This post tries to keep the complexity manageable while making a point clear. We are not systems engineers/kernel developers, so feel free to point out any mistakes/misunderstandings. This post probably does not present anything new for people who are working in systems engineering and/or kernel development.

Why is that of any interest to an application developer?

Storage is getting faster and faster, while the performance of single CPU cores does not increase to the same degree. Blazingly fast NVMe Storage Devices have reached PCs, Smartphones, Gaming Consoles, and Server Systems in the Cloud. The importance of fast and low latency storage in the cloud can not be understated. AWS recently even went that far to develop and release their own SSDs (AWS Nitro SSD) based on the AWS Nitro System for specific EC2 instance types [1]. 

Many application developers are not particularly educated about storage hardware, kernels, and file system APIs. This post is basically what application programmers should know when programming with modern storage devices in mind.

Continue reading

TLA+ and PlusCal Appetizer

“Temporal logic of actions (TLA) is a logic developed by Leslie Lamport, which combines temporal logic with a logic of actions. It is used to describe behaviours of concurrent systems.” [1]

TLA+ is a formal specification language built on top of the TLA logic. It is used to design and verify the correct behavior of programs and is especially useful in distributed and concurrent systems. PlusCal is a formal specification language as well that gets transcompiled to TLA+. It is used to specify algorithms.

Continue reading

An overview of Large Scale Deep Learning

article by Annika Strauß (as426) and Maximilian Kaiser (mk374)

1. Introduction

One of the main reasons why machine learning did not take off in the 1990s was that the lack of computational power and  the size of data sets, available at that time

Since then, a lot has changed and machine learning methods have found their way into the field of ultra large systems (ULS) like f.e. Google, where they have been used very successfully for quite some time.

Two main areas of application can be distinguished:

  • Learn better ML models faster with very large data sets and very high computing power by parallelizing and distributing different components of the ML computation.
  • Deep Learning methods are developed, trained and applied to control, understand, improve and optimize specific areas within a ULS, e.g. replace multiple overcomplicated subcomponents with a single, machine learned model that still does the same job
Continue reading

WebAssembly: Das neue Docker und noch mehr?

If WASM+WASI existed in 2008, we wouldn’t have needed to created Docker. That’s how important it is. Webassembly on the server is the future of computing. A standardized system interface was the missing link. Let’s hope WASI is up to the task!

Tweet, Solomon Hykes (Erfinder von Docker), 2019

Dieser Tweet über WebAssembly (WASM) des Docker-Erfinders gibt einen Hinweis auf die mögliche Innovationskraft dieser Technologie. Der vorliegende Artikel vermittelt zunächst die wichtigsten technischen Grundlagen von WebAssembly, welche zum weiteren Verständnis notwendig sind. Anschließend wird der WASI-Standard näher beleuchtet, welcher die Brücke zur Containervirtualisierung schlägt. Schließlich betrachten wir mit Krustlet (Kubernetes) und wasmCloud zwei existierende Cloud-Technologien, die zentral auf WebAssembly basieren.

Continue reading

SLOG – Deterministische Datenbanksysteme die Lösung für alle* Probleme?

*zumindest im Bereich georeplizierter Datenbanken

Wir leben in einer globalisierten Welt, in welcher wir Anwendungen auf der ganzen Welt nutzen können. Egal wo wir gerade sind, können wir auf diese Programme und Daten zugreifen. Doch diese Möglichkeit stellt Softwaresysteme heutzutage vor große Herausforderungen. Nutzer möchten so schnell wie möglich auf Daten zugreifen und gehen davon aus, dass die Daten, die sie bekommen auch korrekt und auf dem richtigen Stand sind. Um die Verfügbarkeit der Daten für die Nutzer zu erhöhen, werden moderne Datenbank- und Softwaresysteme repliziert. Das heißt es werden Kopien derselben Daten hergestellt und regelmäßig abgeglichen, um die Daten auf dem gleichen Stand zu halten. Moderne Anwendungen replizieren Daten also über geografische Regionen hinweg. Jedoch zwingen bestehende Datenbanksysteme, welche geografische Replikationen unterstützen, die Nutzer auf mindestens eines der folgenden Merkmale zu verzichten, um eine hohe Verfügbarkeit zu erreichen:

  • Strict Serilizability: Bei strikter Serialisierbarkeit scheinen die Operationen in einer bestimmten Reihenfolge zu erscheinen, die mit der Echtzeit-Reihenfolge der Operationen übereinstimmen. Das heißt wenn zum Beispiel Operation A abgeschlossen ist, bevor Operation B beginnt, sollte A in der Serialisierungsreihenfolge vor B erscheinen. Die Serialisierbarkeit ist der Ausführungsplan für die parallele Ausführung mehrere Transaktionen. Es gibt die Reihenfolge vor, in welcher die einzelnen Operationen der Transaktion ausgeführt werden und es verhält sich wie ein System, das auf einer einzigen Maschine läuft und die Transaktionen sequenziell verarbeitet.
  • Low-latency writes: Um strikte Serialisierbarkeit zu erreichen muss auf Schreibvorgänge mit geringer Latenz verzichtet werden. Um die strenge Serialisierbarkeit in georeplizierten Datenspeichern zu garantieren, muss es mindestens ein Koordinationsprotokoll geben, um einen Schreibvorgang auf alle Replikate zu übertragen. Genau diese Koordination ermöglicht zwar die strikte Serialisierbarkeit, erhöht aber die Latenzzeit bei jedem Schreibvorgang. Je weiter die Regionen voneinander entfernt sind, desto länger dauert es einen Schreibvorgang abzuschließen.
  • High transaction throughput: Im Allgemeinen wird die Geschwindigkeit eines Datenbanksystems anhand des Transaktionsdurchsatzes gemessen, ausgedrückt als Anzahl der Transaktionen pro Sekunde. In replizierten Datenbanken kann es zu einer bereichsübergreifenden Koordinierung kommen, das heißt wenn bei Lese- und Schreibvorgängen auf eine weiter entfernte Region zugegriffen werden muss. Normalerweise sind die mit dem Nutzer verbunden Daten stark auf den physischen Standort des Nutzers ausgerichtet. Beliebige Transaktionen können jedoch auf mehrere Datenelemente zugreifen, wobei jedes Datenelement in einer anderen Region verwaltet wird. Hier muss schließlich wieder eine regionsübergreifende Koordinierung stattfinden, dies ist zeitaufwändig. Das Zeitfenster in den kollidierenden Transaktionen nicht ausgeführt werden können ist groß und der Transaktionsdurchsatz verringert. 

Um die Probleme zu lösen, die sich zur Erfüllung der genannten Eigenschaften ergeben, gibt es unterschiedliche Ansätze. Ein Ansatz ist Determinismus. Was das genau heißt und wie es genau funktioniert wollen wir an dem System „SLOG“ genauer betrachten. SLOG ist laut dem Paper von Run et al. „SLOG: Serializable, Low-Latency, Geo-Replicated Transactions“ der erste Systementwurf, welcher alle drei genannten Eigenschaften erfüllt.

Nachdem im Folgenden die Probleme georeplizierter Datenbanken noch einmal genauer betrachtet werden, wird der Begriff Determinismus vor allem im Kontext von modernen Datenbanksystemen geklärt und das Prinzip wird anhand des Systems SLOG noch einmal genauer erläutert.

Was ist das Problem?

Die Probleme, die uns in replizierten Datenbanken begegnen, erschließen sich bereits aus der vorangegangenen Erklärung der drei Eigenschaften moderner Anwendungen. Im Folgenden wird das Ganze noch einmal Schritt für Schritt genauer betrachten und es wird klar, warum es zu diesen Problemen kommt.

Single-Node-Datenbanken – Datenbanken, die für eine einzige Maschine konzipiert wurden – funktionieren sehr gut. Wenn Kunde 2 den Artikel 3 kaufen möchte, werden diese zwei Items gelocked und erst dann sind die Änderungen möglich (vgl. Abbildung 1). In einem einfachen Datenbanksystem ist die Serialisierbarkeit also ohne großes Zutun garantiert und über die anderen zwei Eigenschaften muss sich gar nicht gekümmert werden, da diese in diesem Kontext noch gar nicht wirklich relevant sind.

Abbildung 1: Single-Node-DB

Bei Multi-Node-Datenbanken wird das ganze schon etwas schwieriger und es braucht ein bisschen mehr Anstrengung. Man spricht hierbei auch von einem Scalability Problem. Die Kunden und die Artikel sind nicht mehr wie im Single-Node-Beispiel auf einer Maschine, sondern auf vier Maschinen aufgeteilt. Jede Maschine nutzt nur den Code welcher relevant für ihn ist. Jedoch muss es irgendeine Kommunikation zwischen beiden Maschinen geben, die den Maschinen gegenseitig bestätig, dass jede Maschine das getan hat, was sie auch tun soll. Jede Maschine muss ihren Part der Transaktion eigenständig durchführen. Diese Kommunikationsproblem kann durch Locking oder auch durch eine Two-Phase-Commit-Protokoll gelöst werden (vgl. Abbildung 2). Hierbei ergibt sich jedoch aufgrund dieser Protokolle wieder ein neues Problem. Durch das gesamte Protokoll muss gelockt werden. Dies führt zu einer Reduzierung der Geschwindigkeit unserer Transaktionen, da die Zeiträume, über die die Locks gehalten werden müssen, lange sind.

Abbildung 2: Multi-Node-DB

Wenn wir jetzt aber repliziere Datenbanken haben, also Kopien der Datenbank auf der ganzen Welt verteilt, müssen solche Locks noch viel länger gehalten werden, was noch mehr Zeit benötigt.     

Durch das Nutzen von replizierten Datenbanken an verschiedenen Locations wird Nähe zu den Nutzern erreicht und um dadurch die Verfügbarkeit zu steigern. Hierbei wird eine Transaktion erst in der eigentlichen Location durchgeführt und danach – genauer gesagt nach dem das Commit-Protokoll durchgeführt wird – wird die die Datenbank synchron in allen Locations auf der ganzen Welt repliziert (vgl. Abbildung 3). Das Problem ist hier, wie bereits erwähnt, dass die Locks sehr lange gehalten werden müssen, bis die Replikation abgeschlossen ist.

Abbildung 3: Georeplizierte DB

War es bei den Multi-Node-Datenbanken noch so, dass die Latenz vom Commit-Protokoll das Problem war, ist es bei replizierten Datenbanken nun die Latenz unseres Replikationsprotokolls. Beide Protokolle verursachen Latenzen durch das Halten von Locks.

Genau diese Herausforderung kann durch Determinismus gelöst werden.   

Was ist Determinismus im Kontext von Datenbanken?

Determinismus gibt es in allen möglichen Fachgebieten, wie z.B. der Linguistik, der Biologie oder auch der Theologie. Laut Wikipedia ist „der Determinismus (von lateinisch determinare ‚festlegen‘, ‚Grenzen setzen‘, ‚begrenzen‘) die Auffassung, dass alle – insbesondere auch zukünftige – Ereignisse durch Vorbedingungen eindeutig festgelegt sind.“ Diese Definition trifft es im Zusammenhang mit verteilten Datenbanksystemen eigentlich schon ganz gut. Denn das ist was versucht wird in deterministischen Systemen zu erreichen. Genauer gesagt, wenn zwei getrennte Kopien des Systems die gleiche Eingabe sehen, dann sind sie in der Lage diese Eingabe unabhängig voneinander zu verarbeiten und aufgrund des Determinismus garantiert die gleiche Ausgabe (den gleichen Endzustand) zu ergeben.

Lange war die stärkste Garantie in Datenbanksystemen die Serialisierbarkeit. Hierbei wird sichergestellt, dass der Endzustand des Datenbanksystems auch bei der gleichzeitigen Verarbeitung vieler Transaktionen, dem entspricht, als hätte es alle Transaktionen seriell verarbeitet. Jedoch wird hierbei keine Garantie übernommen, in welcher seriellen Reihenfolge die Transaktionen verarbeitetet werden. Bei deterministischen Systemen wird aber die Äquivalenz einer seriellen Reihenfolge garantiert. Es gibt also eine Verarbeitung von Transaktionen in einer einzigen vorbestimmten seriellen Reihenfolge. Dadurch gibt es nur einen möglichen Zustand, in dem sich das System befinden kann, trotz des Vorhandenseins von potenziell nicht-deterministischem Code in der Transaktionslogik.

Um nur einen möglichen Endzustand zu erreichen, müssen moderne deterministische Datenbanksysteme bei einem Anfangszustand und einer definierten Eingabe in das System, die Eingaben vorverarbeiten.

Normalerweise arbeiten verschiedene Kommunikations-Threads, die es in bestehenden nicht-deterministischen Datenbanksystemen gibt, unabhängig voneinander. Für deterministische Datenbanksysteme ist diese Architektur nicht praktikabel, da Determinismus nur garantiert werden kann wenn es eine klare, allgemeine vereinbarte Eingabe gibt. Um diese Garantie aber zu erfüllen, muss eine Aufzeichnung der Eingabe erstellt werden, nach der sich das gesamte System richten kann. In einer Ein-Maschinen-Architektur zum Beispiel kann dies erreicht werden, in dem alle Transaktionen durch einen Thread geleitet werden, der die Eingabetransaktionen in der Reihenfolge aufzeichnet, in der er sie beobachtet.

Für die Erstellung eines solchen deterministischen Ausführungsplans für mehrere replizierte Datenbanksysteme im Vergleich zu herkömmlichen nichtdeterministischen Systemen ist mehr Wissen über die Transaktion erforderlich, bevor sie verarbeitet werden kann. Vor allem aber muss die gesamte Transaktion während des Planungsprozesses vorhanden sein. Außerdem erfordert die Vorausplanung in der Regel Kenntnisse darüber, auf welche Daten eine Transaktion zugreifen wird. Dieses Wissen wird entweder statisch aus der Inspektion des Transaktionscodes abgeleitet, durch konservative Schätzungen vorgenommen oder es werden Teile der Transaktion spekulativ ausgeführt. In georeplizierten, hochskalierbaren Systemen kann dies zum Beispiel durch ein Protokoll wie Paxos geschehen. Hierbei werden alle Transaktionen vor der Verarbeitung durch dieses Protokoll geleitet, um einen Konsensus über das System hinweg zu erzielen. Dies hat jedoch den Nachteil, dass jede Transaktion die regionsübergreifende Latenzzeit für die Ausführung von Paxos über die Regionen hinweg bezahlen muss.

Jedes System sieht in einem deterministischen System durch ein Konsensus-Protokoll wie Paxos dieselbe Eingabetransaktion, und solange sie dieselbe Eingabe sehen, werden sie in denselben Endzustand gelangen. Die einzige Koordination, die in einem deterministischen Datenbanksystem noch stattfinden muss, ist die Kommunikation, die erforderlich ist, um sich über die Eingabe in das System zu einigen. Jegliche andere Kommunikation wie zum Beispiel Locking oder Two-Phase-Commit-Protokolle werden dann nicht mehr benötigt und Determinismus verringert dadurch die Latenzzeit und verbessert den Durchsatz.

Die einzige Latenz, die wir jetzt noch haben ist die des Konsensus-Protokolls. Dies kann mit dem System SLOG gelöst werden, welches noch diesen Schritt weiter geht und versucht die Latenz, verursacht durch das globale Konsensus-Protokoll, zu entfernen.

Wie funktioniert SLOG?

SLOG ist nicht der einzige deterministische Ansatz. Jedoch ist SLOG der einzige Ansatz, welcher den globalen Konsensus eliminiert und dadurch alle drei Eigenschaften garantieren kann. Dieses System entfernt den globalen Paxos-Prozess, um die Latenzzeit zu verringern. Im Folgenden wollen wir SLOG oberflächlich betrachten und sehen wie SLOG diesen Schritt im Vergleich zu herkömmlichen deterministischen Ansätzen weitergeht.

Wie schafft es SLOG nun dieses Konsensus-Protokoll abzuschaffen? SLOG verwendet eine Master-orientierte Architektur. Hierbei wird jedes Datenelement in einer sogenannten „Home“-Region oder Heimatregion verwaltet, was bedeutet, dass jeder Datensatz einen primären Speicherort besitzt. Schreib- und linearisierbare Lesevorgänge eines Datenelements müssen an seine Heimatregion gerichtet sein und am primären Speicherort verarbeitet werden. Eine Region in SLOG ist eine Gruppe von Servern, die über ein Netzwerk mit niedriger Latenz verbunden sind. Jede SLOG-Region enthält eine Reihe von Servern, auf die die in dieser Region gespeicherten Daten aufgeteilt (und repliziert) werden. Ein Teil dieser Daten wird von dieser Region beherrscht (sie ist die Heimatregion für diese Daten) und der Rest ist eine Kopie von Daten aus einer anderen Heimatregion. Jedes Datenelement hat also seine primäre Location (Heimatregion), was so viel bedeutet wie Nutzer in Berlin haben ihre primäre Location in Berlin, Nutzer in Sydney haben ihre primäre Location in Sydney. Wenn ich als Berliner nun Daten aus Sydney lesen möchte, muss ich die Daten auch aus der Region Sydney lesen, weil diese Up-to-date sind.

Die Transaktionen in SLOG werden basierend auf dieser Aufteilung in Heimatregionen in zwei Kategorien eingeteilt:

  • Single-Home: Die Daten, auf die zugegriffen werden soll, haben ihr Home-Replika in derselben Region
  • Multi-Home: Die Daten, auf die zugegriffen werden soll, haben ihr Home-Replika in unterschiedlichen Regionen

Lese- und Schreibzugriffe auf nahe gelegene Daten erfolgen schnell und ohne regionsübergreifende Kommunikation. Für Lese- und Schreibvorgänge auf entfernte Daten sowie für Transaktionen, die auf Daten aus mehreren Regionen zugreifen, einer Multi-Home-Transaktion, fallen jedoch regionsübergreifende Kommunikationskosten an. Die Ausführung von Multi-Home-Transaktionen stellen auch das technisch schwierigste Problem bei der Entwicklung von SLOG dar. Das Ziel besteht darin, strenge Serialisierungsgarantien und einen hohen Durchsatz bei einer potenziell großen Anzahl von Multi-Home-Transaktionen aufrechtzuerhalten, auch wenn diese auf konkurrierende Daten zugreifen und eine Koordinierung über physisch entfernte Regionen hinweg erfordern.

Auch SLOG verwendet ein Koordinationsprotokoll, um denselben Endzustand zu erreichen und nutzt einen solchen deterministischen Ausführungsrahmen wie oben beschrieben, um Skalierbarkeits- und Durchsatzbeschränkungen zu überwinden. Jedoch ersetzt SLOG das globale Protokoll durch ein regionales Protokoll. In SLOG wird der globale, auf Paxos-basierte, Log entfernt und durch ein lokales Log-Protokoll, welches ebenfalls auf Paxos basiert, ersetzt. Jede Region unterhält ein lokales Eingabeprotokoll, das über Paxos auf ihren Servern implementiert wird. Dieses lokale Protokoll enthält nur Transaktionen, die voraussichtlich Daten verändern, die in dieser Region verwaltet werden. Dieses Eingabeprotokoll wird in Batches an alle anderen Regionen gesendet. Jeder Batch ist mit einer Sequenznummer gekennzeichnet und die anderen Regionen verwenden diese Sequenznummer, um sicherzustellen, dass sie keine Chargen aus dieser Region übersehen haben. Auf diese Weise ist jede Region schließlich in der Lage das vollständige lokale Protokoll von jeder anderen Region zu rekonstruieren

Angenommen wir haben eine Transaktion, welche nur auf Datenelemente aus einer Region zugreift (Single-Home-Transaktion), sieht das ganze wie in der folgenden Abbildung 4 aus:

Abbildung 4: SLOG-Single-Home-Transaction

Wenn nun eine Transaktion auf Datenelemente aus zwei verschieden Regionen auftritt (T3 und T5 in Abbildung 5), wird diese aufgeteilt. Man spricht dann von einer Multi-Home-Transaktion:

Abbildung 5: Multi-Home-Transaction

Das globale Paxos-Log, welches zuvor in anderen deterministischen Ansätzen für Multi-regionale Datenbanken vorhanden war, weicht einer lokalen Version eines solchen Paxos-Protokolls pro Region, welches nur noch asynchron an die anderen Regionen repliziert wird (vgl. Abbildung 6).

Abbildung 6: SLOGs lokale Protokolle

Die lokalen Protokolle werden in jede andere Region repliziert und sind unterschiedlich verschachtelt, was dazu führt, dass T3 zum Beispiel in jeder Region anders angeordnet ist (vgl. Abbildung 7), was aber nicht weiter problematisch ist, da die Daten disjunkt sind. 

Abbildung 7: SLOGs lokale Transaktionsreihenfolge

Die Regionen weichen nicht voneinander ab, da

  1. das globale Protokoll in jeder Region die ursprüngliche Reihenfolge der lokalen Protokolle, die es verschachtelt, beibehält.
  2. lokale Protokolle aus verschiedenen Regionen auf disjunkte Daten zugreifen.
  3. die deterministische Verarbeitungsmaschine sicherstellt, dass die Transaktionen so verarbeitet werden, dass das Endergebnis dem Ergebnis der Verarbeitung in der seriellen Reihenfolge entspricht, die im globalen Protokoll der jeweiligen Region vorliegt.

Single-Home-Transaktionen (T1, T2, T4) werden übertragen, sobald sie in ihrer Primärregion abgeschlossen sind.

Multi-Home-Transaktionen (T3, T5), die auf Daten in mehreren Regionen zugreifen, müssen auf die asynchrone Replikation des Eingabeprotokolls warten, bevor sie die Transaktion festschreiben können (sie müssen auf das Eintreffen des Protokolls warten). Die Transaktion wird verarbeitet, sobald die entsprechenden Protokollsätze in jeder lokalen Region vorhanden sind.

Durch die Aufteilung in Single-Home und Multi-Home wird realisiert, dass die meisten Transaktionen schnell sind (Single-Home). Auch wenn die Transaktionen in mehreren Regionen etwas langsamer sind, verschlechtern sich die Latenzen und der Durchsatz nicht so stark.

Fazit

Determinismus verringert die Latenzzeit und verbessert den Durchsatz, in dem es die Möglichkeit lokaler Deadlocks ausschließt und verteilte Commit-Protokolle wie z.B. Two-Phase-Commit reduziert, beziehungsweise gänzlich eliminiert. Experimente haben gezeigt, dass der Durchsatz bei deterministischen Systemen im Vergleich zu nicht-deterministischen Systemen bei zunehmender Konkurrenz deutlich besser performt (vgl. Abbildung 8).

Abbildung 8: Durchsatzvergleich deterministischer und nicht-deterministischer Systeme

Herkömmliche deterministische Systeme haben zwar weiterhin mit Latenzen (bzgl. des Konsensus-Protokolls) zu kämpfen, jedoch gibt es Systeme wie SLOG, die versprechen auch diese Latenz zu verringern oder sogar zu eliminieren, um alle drei in der Einleitung genannten Eigenschaften zu erfüllen.  

Für Datenbankreplikationen ist der offensichtlichste Vorteil deterministischer Datenbanksysteme die Gewährleistung, dass, solange alle Replikate denselben Input erhalten, diese nicht voneinander abweichen. Weitere Vorteile in der deterministischen Architektur sind auf jeden Fall die Skalierbarkeit, die Modularität und die Gleichzeitigkeit. Nicht-deterministische Ausfälle führen in einem deterministischen System nicht zu einem Transaktionsabbruch, da die Datenbank ihren Zustand zum Zeitpunkt des Absturzes immer wiederherstellen kann, was diese Systeme auch robuster gegen Fehler macht.

Auf den ersten Blick scheinen deterministische Architekturansätze in verteilten Datenbanken die Lösung für viele bekannte Probleme, doch leider ist dieser Ansatz nicht für alle Datenbankanwendungen praktikabel. Da für den Planungsprozess die gesamte Transaktion vorhanden sein muss, sind deterministische Datenbanksysteme schlecht geeignet für ORM-Tools und andere Anwendungen, die Transaktionen nur in Teilen an die Datenbank übermitteln.

Deterministische Datenbanksysteme haben sich als vielversprechender Weg zur Verbesserung der Skalierbarkeit, Modularität, des Durchsatzes und der Replikation von transaktionalen Datenbanksystemen erwiesen. Leider bieten alle neueren Implementierungen nur begrenzte oder gar keine Unterstützung für interaktive Transaktionen, so dass sie in vielen bestehenden Implementierungen bisher nicht eingesetzt werden können.

Quellen

Abadi, Daniel J. „SLOG: Serializable, Low-Latency, Geo-Replicated Transactions“. Gehalten auf der CMU Database Group – Vaccination Database Tech Talks (2021), CARNEGIE MELLON UNIVERSITY, 1. Februar 2021. https://www.youtube.com/watch?v=TAdiilOOvNI&t=645s.

„Determinismus“. In Wikipedia, 25. Dezember 2021. https://de.wikipedia.org/w/index.php?title=Determinismus&oldid=218485694.

Faleiro, Daniel J. Abadi, Jose M. „An Overview of Deterministic Database Systems“. Zugegriffen 15. März 2022. https://cacm.acm.org/magazines/2018/9/230601-an-overview-of-deterministic-database-systems/fulltext.

Ren, Kun, Dennis Li, und Daniel J. Abadi. „SLOG: Serializable, Low-Latency, Geo-Replicated Transactions“. Proceedings of the VLDB Endowment 12, Nr. 11 (Juli 2019): 1747–61. https://doi.org/10.14778/3342263.3342647.

„Strict Serializability“. Zugegriffen 23. März 2022. https://jepsen.io/consistency/models/strict-serializable.

„Transaction throughput“. Zugegriffen 23. März 2022. https://docs.oracle.com/cd/E17276_01/html/programmer_reference/transapp_throughput.html.

Featured image: https://www.keysight.com/content/dam/keysight/en/img/prd/ixia-homepage-redirect/network-visibility-and-network-test-products/Network-Monitoring.jpg

Games aus der Cloud, wo sind wir und wohin geht die Reise?

Cloud Gaming – flüssiges Zocken auch mit schlechter Grafikkarte? (esports.com)

Was genau ist Cloud Gaming?

Cloud Gaming lässt sich mit Remote Desktops, Cloud Computing und Video on Demand Diensten vergleichen. Im Grunde beinhaltet Cloud Gaming das Streamen von Videospielen aus der Cloud zum Endkunden. Dabei erfasst und überträgt der Client seine Nutzereingaben (bspw. Maus, Tastatur, Controller) an den Server. Während dieser wiederum die Gesamtspielweltberechnung sowie Nutzereingaben-Auswertung bewältigt. Der Client stellt lediglich die Kapazität bereit, die Frames in der gewünschten Qualität gestreamt zu bekommen. Wesentliche Vorteile ergeben sich für leistungsschwache Geräte, während der offenkundige Nachteil in der Notwendigkeit einer gut ausgebauten Dateninfrastruktur liegt.

Neben Game Streaming gehört zum Cloud Gaming auch das Hosten von Serverinstanzen für Onlinespiele, sowie das Bereitstellen von Plattformdiensten (bspw. Bestenlisten, Chatsysteme, Authentifizierung etc.). Wesentlicher Bestandteil ist des Weiteren das Angebot von leistungsfähigen Downloadservern.

Plattformdienste und etablierte Nutzung der Cloud

Plattform- oder Onlinedienste bieten Schnittstellen, welche Spielemetadaten zur Verfügung stellen. Diese Dienste Umfassen in der Regel Funktionalitäten wie Bestenlisten, Chat- und Gruppensysteme sowie Onlinelobbys, aber auch Metadienste wie Authentifizierung, Analyse, Zuordnung von Spieleridentitäten und Matchmaking. Hierbei können Dienste sowohl öffentlich im Internet als auch intern für andere Dienste zur Verfügung stehen. Während diese Systeme zu Beginn ihres Aufkommens noch als einzelne Monolithen bereitgestellt wurden, bieten heutige Cloudbetreiber solche Dienste als Microservices an. Dies sorgt dafür, dass sich die hohe Skalierbarkeit der Cloud auf die Plattformdienste übertragen lässt. Diese Skalierbarkeit ist vor allem deshalb wichtig geworden, da der Spielemarkt in den letzten Jahren stark gewachsen ist und auch die Spiele selbst immer ressourcenintensiver geworden sind. Als gutes Beispiel kann man hierfür eine der größten Spieleplattformen hernehmen: Steam. Steam integriert viele der angebotenen Spiele in die eigenen Plattformdienste. Dies umfasst Beispielsweise eine Freundesliste, Chatsysteme, Matchmaking und Verbindungssysteme. Zusätzlich wird auch die dahinter liegende Infrastruktur für die Vermarktung der Spiele von Steam gestemmt. Dies umfasst einen Webshop und Downloadserver.

Der große Aufwand und die Nachfrage nach diesen Diensten zeigen sich anhand des weltweiten Datenverkehrs von Steam. So kommt zum Zeitpunkt dieses Blogeintrags allein der deutsche Datenverkehr auf über 35 Petabyte innerhalb der letzten 7 Tage. Und dies wiederum entspricht lediglich ca. 4,3% des weltweiten Datenvolumens.

Aufnahme der Steam Statistiken am 16.03.2022 um 14.48 Uhr – Steam: Game and Player Statistics (steampowered.com)

Diese Zahlen steigen vor allem dann rasant an, wenn es zu speziellen Aktionen kommt, wie etwa dem Release eines neuen, stark erwarteten Spieles oder Sale-Aktionen vergleichbar mit einem Black-Friday für Games. Hierbei kommt es dazu, dass teilweise Millionen von Spielern gleichzeitig das neue Produkt erwerben und herunterladen wollen.

Diese starke Belastung spüren aber nicht nur Shop- und Downloadserver, sondern natürlich auch die klassischen dedizierten Spieleserver selbst. Gerade beim Release eines neuen Massive Multiplayer Onlinespiels (MMO) oder einer neuen großen Inhaltserweiterung versuchen sich gleichzeitig mehrere tausende Spieler auf den Spieleservern einzuloggen, während es zum Normalbetrieb meist nur ein Bruchteil der User ist. Auch hier hilft die hohe Skalierbarkeit der Cloud. Da solche Ereignisse normalerweise zu dem Betreiber bewussten und geplanten Zeiten auftreten können allerdings im Vorfeld schon Ressourcen reserviert und bereitgestellt werden.

Technische Herausforderungen des Game Streaming

Während Plattform- oder Onlinedienste auf die heute weit verbreiteten und gut etablierten Microservice Strukturen und Architektur zurückgreifen, eröffnen sich mit Games as a Service oder Game Streaming ganz neue Herausforderungen. Die Simulation des eigentlichen Spiels kann noch problemlos in einer emulierten Umgebung ablaufen und seine Inputs von außen beziehen, sowie das berechnete Resultat nach außen über einen Video stream abgeben. Das wahre Problem liegt allerdings in der Latenz. Bei Games handelt es sich im Gegensatz zu den meisten anderen Medien um ein interaktives Medium. Das heißt auf eine Aktion des Nutzers muss idealerweise eine unmittelbare Reaktion des Mediums erfolgen. Bei Game Streaming sind die Ansprüche daran besonders hoch, wenn es mit anderen interaktiven Medien wie einem Livestream mit Live Chat verglichen wird. Hier sind Verzögerungen von bis zu 1 Sekunde noch akzeptabel. Bei Spielen hingegen wird eine Latenz von wenigen Millisekunden erwartet. In dieser Zeit muss also die Eingabe beim Client registriert, an den Server geschickt, dort verarbeitet und ein neues Bild an den Client zurückgeschickt, decodiert und angezeigt werden.

Eine abstrahierte, allgemeine Darstellung der Abläufe eine Game Streaming Dienstes – CloudRetroPicture.png (787×492) (webrtchacks.com)

Was kann Cloud Gaming?

Viele Vorteile aus Cloud Computing und Video on Demand Diensten können sich direkt auf Game Streaming übertragen lassen.

  • Für das Spielen von Games aus der Cloud wird keine teure, eigene Hardware benötigt. Der Streamingdienst Betreiber stellt die nötige Hardware zur Verfügung, um das gewünschte Spiel auf einer maximalen Qualitätsstufe darstellen zu können.
  • Um die Wartung, Instandhaltung und Modernisierung der Hardwaresysteme kümmert sich der Streaming Anbieter. Für den Endkunden fallen dadurch keine hohen Einzelkosten an.
  • Spiele stehen jederzeit und überall auf vielen verschiedenen Endgeräten zur Verfügung. Auch leistungsschwache Geräte wie Smartphones, Smart TVs oder einfache Laptops können somit zum Spielen Hardwareintensiver Titel verwendet werden
  • Das Manipulieren und Betrügen in Online- und Singleplayerspielen wird durch das Streaming erheblich erschwert. Dies resultiert direkt aus der Begrenzung der Interaktionspunkte mit dem Spiel. Lediglich die Bildausgabe und die Nutzereingabe finden auf dem lokalen Gerät statt. Jegliche weitere Informationsverarbeitung, wie beispielsweise die Position eines Mitspielers bleiben dem Nutzer verborgen.

Neben den Vorteilen gibt es jedoch auch einige Nachteile:

  • Für Gamestreaming ist zwingend eine durchgehende, leistungsstarke Internetverbindung von Nöten. Denn im Gegensatz beispielsweise zum Video on demand kann bei Game Streaming kein Buffering verwendet werden. Dies ist bei Spielen allerdings nicht möglich, da der weitere Verlauf des Spieles direkt von den Eingaben des Spielers abhängig ist. Ein Verbindungsverlust führt somit zwangsläufig zu einer abrupten Unterbrechung der Spielsession.
  • Schwankungen in der Bandbreite führen zu einer Drosselung der Bildqualität und mindern damit das Spielerlebnis.
  • Das Übertragen bereits in Besitz befindlicher Spiele werden von vielen Anbietern nicht unterstützt. Dies kann dazu führen, dass Spiele entweder nicht zur Verfügung stehen oder nochmals auf der Streaming Plattform gekauft werden müssen.
  • Das Modifizieren der eigenen Spieldaten wird unterbunden, da nicht lokal auf die Spielinhalte zugegriffen werden kann. Dies verhindert, dass Spieler Modifikationen erstellen und ihr Spielerlebnis bei Bedarf individuell anpassen können.
  • Der Anbieter entscheidet welche Publisher und Franchise in seinem Portfolie aufgenommen werden. Dies erschwert vor allem kleine Studios oder Indie Entwickler sich auf dem Markt zu etablieren.
  • Spiele stehen zusätzlich nur solange zur Verfügung so lange sie sich im Angebot des Streamingdienst befinden oder dieser die Lizenzen hierfür besitzt.

Fazit

Cloud Gaming umfasst mehr als nur Game Streaming. Es ist bereits fester Bestandteil der heutigen Infrastruktur, da ein Großteil der Spiele auf Cloud-Dienste zurückgreift oder durch Plattformen wie bspw. Steam in diese integriert wird. Zwar steht Game Streaming an sich gerade erst in den Startlöchern, doch es würde mich nicht verwundern, wenn immer mehr Nutzer umsteigen oder zumindest teilweise auf dessen Vorteile zugreifen würden. Meiner Meinung nach wird es in absehbarer Zeit kein kompletter Ersatz für alle Spieler werden. Allerdings bin ich der Überzeugung, dass Game Streaming zum Netflix der Spieler wird, da es aufgrund der vorhandenen Technologien, Infrastruktur und Kunden über ein hohes Potential verfügt. Die Entwicklung der Streaming Ttechnologien steht allerdings erst an ihrem Anfang. Eine Weiterverfolgung wird sich in jedem Fall lohnen.

Quellen

Überblick über die Cloud-Gaming-Infrastruktur  |  Cloud Architecture Center  |  Google Cloud
Microservices – Wikipedia
Unreal Pixel Streaming in Azure – Azure Gaming | Microsoft Docs
Azure for Gaming – Azure Gaming | Microsoft Docs
Cloud-Gaming: Die besten Anbieter im Vergleich | heise Download
Cloud-Gaming im Vergleich: Die besten Spiele-Streamingdienste | NETZWELT
Cloud Gaming – flüssiges Zocken auch mit schlechter Grafikkarte? (esports.com)
Cloud gaming – Wikipedia
Xbox Cloud Gaming – Wikipedia
What is cloud gaming and how does it work? – Dot Esports
How Cloud Gaming and Streaming Games on Stadia and xCloud Works (makeuseof.com)
Open Source Cloud Gaming with WebRTC – webrtcHacks
Youtube: Google WebRTC project update & Stadia review

Optimizing Practical Byzantine Fault Tolerance in Wireless IoT Blockchain Networks

Don’t we all appreciate a little help in our everyday lives? “Alexa, turn on the lights in the living room.”
Voice assistants, smart lights and other smart home devices are all part of the Internet of Things (IoT). Those and other possible applications of IoT devices increase continuously and with it the overall number of connected devices. According to IoT Analytics Research, there are already over 12.3 billion connected IoT devices around the world, whereas most of them are wireless.

But how can we guarantee security, trust and liveliness in such networks?

Global IoT Market Forecast From IoT Analytics Research (https://iot-analytics.com/product/state-of-iot-summer-2021/ / https://iot-analytics.com/number-connected-iot-devices/)

Today, we will gain an insight into how byzantine fault tolerance can be achieved in wireless IoT networks. In particular, we will look at an analytical modeling framework by Onreti et al. for applying the Practical Byzantine Fault Tolerance (PBFT) algorithm to such networks. Furthermore, we will see which restrictions apply and how the viable area for these networks can be obtained. For more details, take a look at the original paper “On the Viable Area of Wireless Practical Byzantine Fault Tolerance (PBFT) Blockchain Networks” by Onreti et al. [2].

IoT and Blockchain

All devices (or nodes) in a fully autonomous IoT network communicate in a distributed way. However, this communication style is not an easy task as nodes need to agree on the validity of communicated data. The approach, for achieving the necessary level of security and trust, is to apply an appropriate consensus method. As the principle of agreeing on new data is the same as in blockchain, its consensus methods can also be applied to IoT networks. However, commonly used methods such as proof of work and proof of stake rely on computational power – a limited resource for most IoT devices. This is where wireless PBFT protocol comes in handy.

Practical Byzantine Fault Tolerance (PBFT)

Here, (wireless) PBFT refers to a blockchain consensus method with low computational complexity and power suited for asynchronous IoT environments.

The protocol consists of the following three phases

  • pre-prepare
  • prepare
  • commit

during which nodes communicate via wireless channels. Phase one is triggered as soon as a client node’s IoT request is received. The node receiving said request is referred to as header node, whereas all other nodes in the network are called replica nodes. In other words, a PBFT network is composed of several replicas and one leader, whereby the leader is reselected when it turns faulty or breaks down.
The protocol guarantees liveliness and safety as long as no more than (n-1)/3 of n replica nodes are faulty: f ≤ (n-1)/3.

The Protocol

Diagram: communication procedure for a client’s transaction or exchange of information [1],[2]

The following steps describe the procedure from a request to a new block on the blockchain:

  1. request: A client device sends a request to the header node of the network.
  2. pre-prepare phase: The header node receives said request and broadcasts a pre-prepare message to the replica nodes.
  3. prepare phase:  When a replica accepts a pre-prepare message, it enters the prepare stage. In this stage the replica broadcasts a prepare message to the network (including itself).
    Before entering the next phase, a node needs to receive 2f prepare messages from different (but not necessarily other) nodes. In addition, those messages need to match the previous pre-prepare message.
  4. commit phase: After receiving the necessary messages, a node will furthermore broadcast a commit message (including to itself).
    Before leaving the commit phase, a node needs to receive 2f+1 matching commit messages from different nodes. Those 2f+1 messages usually contain a message from itself and the header.
  5. reply: As soon as a node meets the previously mentioned condition, it will send a reply to the client.
  6. consensus & record: The client receives replies from the other nodes and proceeds as soon as the network reaches consensus in the form of f+1 matching reply messages. Lastly, the client records the transaction on the blockchain.

For more details of the original algorithm from 1999, take a look at “Practical byzantine fault tolerance” by M. Castro and B. Liskov [1].

Wireless PBFT: Assumptions & Restrictions

Onreti et al. [2] make the following assumptions about the PBFT network:

  • Replica nodes are evenly distributed inside a circular area with radius R. Henceforth, λ denotes the density of n replicas inside this network area.
  • The wireless network is noise limited: all replica nodes have equal receiver sensitivity, denoted by β1

Based on the those assumptions, a header or replica node’s coverage radius Ri is defined by:

Ri = d0 [PiK/β1]1/γ ,

with:

  • do: reference distance for antenna far field
  • Pi: node’s transmit power
  • β1: receiver sensitivity
  • K: unit-less constant, dependent on antenna characteristics
  • γ: pathloss exponent.

This formula highlights the main restrictions of the network’s nodes. Besides that, most IoT devices are further restricted by limited bandwidth and battery power. For this reason, the nodes’ workload should be kept as small as possible.

Based on the PBFT algorithm, there are further restrictions:

  1. The header node’s coverage area A1 needs to contain at least 3f+1 replicas:
    A1λ ≥ 3f + 1
  2. For a non-faulty replica node, the coverage area A2 needs to overlap with the header node’s area A1. This intersection must contain at least 2f-1 other replica nodes:
    A2λ ≥ 2f − 1
  3. Furthermore, a client’s coverage area A3 (while overlapping with A1), needs to contain at least f+1 replicas:
    A3λ ≥ f + 1

The third constraint guarantees a successful reply to the client.
Constraints 1 and 2 guarantee the security and liveliness of the protocol and its three phases. Those constraints define the needed minimum of nodes for wireless PBFT. For a fixed number of faulty replicas f, additional nodes decrease the performance, as there are more messages (to be processed) as the protocol needs.

Viable Area

The viable area describes that (sub-)area of the network that fulfills all the constraints of wireless PBFT. This means, the number of nodes (and their placement in the area) need to be given such that:

  1. the header node can reach a minimum of 3f+1 replica nodes; where f denotes the number of faulty nodes
  2. a minimum number of matching messages (sent by different nodes) in the prepare (2f) and commit phase (2f+1) is achievable. This leads to:
    Every single replica needs to be reachable by a minimum of 2f-1 other replicas.
  3. a client node (located in- or outside of the network) can receive a minimum of f+1 matching replies

Furthermore, the concept of viable area is defined for a given view, which is determined by its specific header node. In other words, the view changes as soon as another node takes the turn in leading the network. A change of view happens at the latest when the current header fails or breaks down. Thereby the choice of header is well-defined by the view number v and the number of nodes n by i = v (mod n), where i denotes the index of the node in the network.

By determining the viable area, we can minimize the activation of nodes in the network. The smaller the nodes’ broadcast radius, the less nodes are activated. Thus, by minimizing the nodes’ coverage radius, we save energy and improve the performance.

All things considered, the viable area is dependent on:

  • the number of replicas nodes n in the network
  • the number of faulty replicas nodes f in the network
  • the transmit power of header/replica nodes
  • nodes’ receiver sensitivity
  • pathloss components

(Mathematical) Approach for Determining the Viable Area

In order to find a minimum, the mathematical approach is to solve an objective function.
In this case, we are searching for the minimal coverage radius of the header and replica nodes. As the pathloss exponent γ and receiver sensitivity β1 can be considered fixed, this is the same as minimizing the nodes’ transmit powers Pi. Thus, the objective function is:

minimize P1 + P2

whereby P1 is the header’s transmit power and P2 is the transmit power of a typical replica node, that is at the very edge of the area.
Based on the header’s placement, and therefore the shape of the areas A1 and A2, the terms describing the protocol’s first two constraints differ. There are two different cases as depicted below:

Case 1: Viable area of PBFT network with the header located at the origin. [2]
Case 2: Viable area of PBFT network with randomly located header node. [2]

,,: all nodes of the network (area)

,: nodes inside header node’s coverage area

: nodes inside replica node’s coverage area

In case 1, the header is located at (or near) the origin and has a circular coverage area A1 dependent on its coverage radius. In the second case, A1 is no longer circular but rather an intersection of two circular areas; i.e. A1 is additionally dependent on the header’s distance to the origin and the radius R of the network. In this case, the reference “replica on the edge” for the second constraint is located at an intersection point (h1 or h2), which represents the minimal possible A2.
In both cases, we adjust the coverage radiuses Ri (respectively the transmit power Pi) such that the areas fulfill the first two constraints of the protocol.

Solving for Pi

So far, we have an objective function with two constraints. In order to find reasonable results, we furthermore restrict the searched parameters:

In this case this means that the transmit powers Pi need to be limited. We set the header node maximum transmit power P1max, such that the header can still reach every node in the network, if needed. Furthermore, we set the maximum of P2 such that P2max = αP1max , with α > 1, i.e. P2max is greater than P1max.
As a consequence, we restrict P1 and P2 by:
0 ≤ P1 ≤ P1max
0 ≤ P2 ≤ P2max

With this additional constraint, we can solve the objective function using a classic method and denote its result as P1* and P2*.

Up to this point, the third constraint for wireless PBFT has been ignored. This constraint focuses on the last step in the protocol: the reply to the client. Thus, we need a coverage area A3 (dependent on the given P1*), such that at least f+1 replicas can reach the client. Based on the client’s receiver sensitivity β2 and its distance to the header node, we can use a linear search method for determining the transmit power Pc of a replica needed for replying to the client.

Illustration of the minimum broadcast transmit power required
by the replicas when responding to the client (IoT device). [2]

Numerical Results

Effect of the number of faulty nodes on the header and replica nodes transmit power,
λ = 1/(π1000) nodes/m2. [2]
Effect of the number of faulty nodes on the header and replica nodes transmit power,
λ = N/(π10002) nodes/m2, N = 811, 1000. [2]

The previous diagrams show the transmit powers of header and replica nodes in relation to the number of faulty nodes. The values have been determined for a view with the header at the origin. Further system parameters for these results can be found in [2].

Both diagrams show that the transmit power of header and replica nodes increases with the number of faulty nodes. That is because their coverage areas need to include more nodes.
Furthermore, the right diagram shows two more important points. First, a higher node density reduces the needed transmit power. Second, we can see the restrictions of the transmit power: it is not only restricted by (n-1)/3, but also by the maximal transmit power P1max resp. P2max.

Effect of the number of faulty nodes on the replica transmit
power during the reply phase, λ = 1/(π1000) nodes/m2. [2]

Last but not least, the diagram to the left shows the increase of transmit powers with increasing number of faulty nodes f. As expected, the needed replica’s transmit power Pc increases with the distance d1 of the client to the header; but in particular, we can also see that it really ramps up with an increase in faulty nodes f.

Critique: Advantages and Drawbacks of Wireless PBFT

Applying PBFT to IoT blockchain networks has clearly benefits over other methods, as it needs less resources. But how applicable is this approach to an existing network? It seems rather questionable, whether an existing network can fulfill the required assumptions. When the nodes are not evenly distributed, this approach for determining the viable area can not be applied. Furthermore, the needed noise limitation might not be given. However, when the assumptions are met, the constraints for A1 and A2 of the viable area can also be used to check whether a transaction is indeed successful [2].

The last point seems rather important. If anything in the network changes, it probably has an impact on the viable area and thus on the needed transmit powers. The PBFT algorithm has some mechanism in place to change the view, if needed – but Onreti et al. do not address what exactly happens when nodes crash or have exhausted their battery.

Besides verifying successful transactions, constraints 1 and 2 of the viable area can be used in the design for a new network – in particular for determining the radius R. [2] We might say we have a trade-off between energy savings (per node) and the overall number of nodes for a network. When we add additional nodes – to an otherwise similar network – we increase the node density. If the number of faulty nodes stays the same, this leads to energy savings. However, there is no guarantee that the rate of faulty nodes does not increase with the number of overall devices; and even though a higher node density decreases the needed transmit power, additional nodes bring other costs with them (e.g. maintaining the network).

Open Questions

Some questions persist: Who keeps track of the number of nodes n? Can the number of nodes change? When nodes turn off due to an exhausted battery, do we just consider them faulty or remove them (i.e. n reduces and node’s indices change)? Removing nodes from the network, would at least mess with the assumed node distribution. For that reason, it seems likely that we just consider exhausted nodes faulty. That brings us to the next question: Who keeps track of the number of faulty nodes? How big is the resource consumption for determining the number of faulty nodes? Who calculates the minimal transmit powers and how often are they recalculated? And what happens if the noise increases?

I would like to see a direct comparison of the power consumption of a test PBFT network, with the same network using another consensus method. Furthermore, numerical results for the case of a header at the edge of the network (worst case of case 2) would be interesting; as well as some sort of ratio of possible views in a network in relation to the header placement (i.e. case 1: case 2).

Last words

Actually, researchers have done a fair amount of work surrounding pBFT/PBFT in the past 2 years, further optimizing the original consensus method. Some of the work, namely SHBFT [3] and G-PBFT [4], (even though not specifically focusing on wireless) also address blockchain IoT networks explicitly. Even though PBFT has already been elaborately examined in 1999, the current research further emphasizes that byzantine fault tolerance is still not that easy to achieve.

On a final note I would like to say: Consensus methods often have such easy rules – in theory – as long as you don’t have to implement them.


Sources

[1] M. Castro and B. Liskov, “Practical byzantine fault tolerance”, Third Symposium on Operating Systems Design and Implementation, New Orleans, USA, Feb. 1999
[2] https://ieeexplore.ieee.org/abstract/document/9013778
O. Onireti, L. Zhang and M. A. Imran, “On the Viable Area of Wireless Practical Byzantine Fault Tolerance (PBFT) Blockchain Networks,” 2019 IEEE Global Communications Conference (GLOBECOM), pp. 1-6, doi: 10.1109/GLOBECOM38437.2019.9013778, 2019
[3] https://doi.org/10.1007/s12083-021-01103-8
Li, Y., Qiao, L. & Lv, Z. “An Optimized Byzantine Fault Tolerance Algorithm for Consortium Blockchain”, Peer-to-Peer Netw. Appl. 14, 2826–2839, 2021 https://doi.org/10.1007/s12083-021-01103-8
[4] Lao L, Dai X, Xiao B, Guo S,” G-PBFT: a location-based and scalable consensus protocol for IOT-Blockchain applications”, 2020 IEEE International parallel and distributed processing symposium (IPDPS). IEEE, pp 664–673, 2020

Security Strategies and Best Practices for Microservices Architecture

Microservices architectures seem to be the new trend in the approach to application development. However, one should always keep in mind that microservices architectures are always closely associated with a specific environment: Companies want to develop faster and faster, but resources are also becoming more limited, so they now want to use multiple languages and approaches. Therefore, it is difficult to evaluate a microservice architecture without reference to the environmental conditions. However, if you separate these external factors, you can still see that a microservice architecture offers much more isolation than other architectures – and can also handle security measures better than, for example, monolithic approaches due to today’s techniques and tools.

Continue reading

Logging im großen Maßstab mit Grafana Loki

Heutzutage erzeugen die meisten Systeme und Anwendungen Logging-Daten die für Sicherheits- und Überwachungszwecke nützlich sind, z. B. für die Fehlersuche bei Programmierfehlern, die Überprüfung des Systemstatus und die Erkennung von Konfigurationsproblemen oder sogar Angriffen. Treten Ereignisse innerhalb einer Anwendung auf, werden diese von integrierten Protokollierungsfunktionen erfasst und mit zusätzlichen Metadaten aufgezeichnet. Mit dem Wachstum von Microservice-Anwendungen ist die Protokollierung für die Überwachung und Fehlerbehebung dieser Systeme wichtiger als je zuvor. 

Besitzt man beispielsweise nur einen kleinen Webserver, ist es evtl. noch möglich die erzeugten Logs täglich zu kontrollieren. Nur wie sieht es aus wenn mitten in der Nacht etwas passiert? Oder beim Betrieb eines großen verteilten Systems? Wie können diese Daten zentral gesammelt und sinnvoll genutzt werden? Hier kommen Log-Aggregation-Systeme ins Spiel, welche bei den Anforderungen an die Beobachtbarkeit und den Betrieb jedes großen, verteilten Systems unterstützen.

In diesem Blogpost möchte ich auf den relativ neuen und immer populärer werdenden Logging-Stack Grafana Loki eingehen. Wie ist es aufgebaut? Wo sind die Unterschiede zu beispielsweise ELK (Elasticsearch, Logstash und Kibana). Was macht es so besonders und warum ist es für große Firmen wie Red Hat interessant, welche in ihrer neuesten Version OpenShift 4.10 Grafana Loki Support anbieten werden?

Continue reading