\documentclass[12pt,a4paper,parskip=half]{scrartcl} \usepackage[utf8]{inputenc} \usepackage[ngerman]{babel} \usepackage[T1]{fontenc} \usepackage{graphicx} \usepackage[colorlinks=true, linkcolor=black]{hyperref} \usepackage{todonotes} \title{Ringstats Dokumentation} \author{Justin Rost \\ 7208260 \and Michelle Reichelt \\ 7216628 \and Yasin Ergün \\ 7215184 } \date{\today} \begin{document} \maketitle \tableofcontents \newpage %Viele PC-Spieler suchen stetig nach neuen Tools um ihr Spielerlebnis zu optimieren und ihre Echtzeit Statistiken besser im Blick zu haben. Daher haben wir % Die Einleitung ist bla. % Fliessender uebergang ins Fazit \newpage \section{Anwendungsszenario} % Das nehmen wir direkt aus dem Proposal und schreiben es min eine seite lang. In diesem Kapitel zeigen wir, worum es bei Ringstats eigentlich geht und in welchen Situationen die Anwendung dem Spieler im Spiel weiterhilft. % Ein Spieler startet einen Bosskampf und kann in einem kleinen Fenster sehen, was für Resistenzen dieser Boss hat und welche Fähigkeiten er am häufigsten benutzt. % Spielerdaten werden live gespeichert und an den Server gesendet, damit der Spieler direkt sehen kann, welche Truhen und Sammelobjekte in der Nähe sind. % Die Gebiets-Checkliste zeigt bei einem Gebietswechsel an, welche Aufgaben der Spieler in dem neuen Gebiet hat. \subsection{Projektidee und Zielsetzung} Die Idee von Ringstats ist die Bereitstellung einer Schnittstelle zwischen dem aktiven Spiel und einer Datenbank mit hilfreichen Spielinformationen. Während des Spiels erfasst die Desktop Anwendung in Echtzeit Parameter des Spielers und schickt diese an die Datenbank. Zu diesen Parametern zählen z.B. die aktuelle Position oder Ausrüstung. Auf Grundlage dieser Live Daten stellt unsere Anwendung dann hilfreiche Informationen über Bosse oder Gegner in der Region des Spielers bereit. Zudem kann auch eine regionenbasierte Checkliste angezeigt werden, auf der sich weitere benutzerdefinierte Aufgaben befinden. All diese Informationen werden auf In-Game Panels eingeblendet. \subsection{Kernfunktionen und Anwendungsfälle} Um den Nutzen von Ringstats zu verstehen, haben wir folgende Kernfunktionen definiert: Die wichtigste Funktion ist das Erfassen der Spielerdaten in Echtzeit. Während der Spieler spielt, liest die Desktop Anwendung laufend aus, wo der Spieler gerade steht, wie viel Leben er hat, wie schnell er ist und was er ausgerüstet hat. Diese Daten werden direkt an die Datenbank geschickt, damit immer der aktuelle Stand vorliegt. Sobald der Spieler einen Gegner oder Boss anvisiert, blendet die Anwendung ein kleines Panel im Spiel ein. Darin sieht der Spieler die Resistenzen des Gegners und welche Fähigkeiten dieser am häufigsten benutzt. So weiß man direkt, worauf man sich einstellen muss. Zusätzlich gibt es eine Checkliste, die sich nach der Region richtet, in der sich der Spieler gerade befindet. Diese lässt sich mit einem Hotkey ein und ausblenden. Auf der Liste stehen zum Beispiel Items, Dungeons und Bosse. Der Spieler kann die Einträge filtern und selbst festlegen, ob sie automatisch abgehakt werden, sobald eine Bedingung erfüllt ist, oder ob er das lieber von Hand macht. Alle diese Daten landen nicht nur im Spiel, sondern sind gleichzeitig über die Internetseite abrufbar. Der Spieler meldet sich auf der Seite an und verbindet sich mit der Desktop Anwendung. Dann kann er seine Informationen auch im Browser einsehen. Damit das Ganze einen Sinn ergibt, hier ein paar typische Situationen aus dem Spiel: Der Spieler startet einen Bosskampf. In einem kleinen Fenster sieht er sofort, welche Resistenzen der Boss hat und welche Fähigkeiten am häufigsten kommen.\\ Während der Spieler durch ein Gebiet läuft, werden seine Daten an den Server geschickt. Dadurch sieht er direkt, welche Truhen und Sammelobjekte in seiner Nähe sind.\\ Wechselt der Spieler in ein neues Gebiet, zeigt die Checkliste an, welche Aufgaben in diesem Gebiet noch offen sind. \newpage \section{Dokumentation der Datenmodellierung} In diesem Kapitel schauen wir uns an, wie wir die Daten von Ringstats aufbauen und wie das Ganze in den verschiedenen Datenbanken aussieht. \subsection{Das konzeptionelle ER-Modell} Die komplexe Struktur der Spielwelt bilden wir mit einem Klassischen ER-Modell ab. Das Modell veranschaulicht, wie der Spieler (Player) über seine Ausrüstung (Gear) mit Waffen (Weapon), Rüstungen (Armor) oder Talismanen (Talisman) etc. verbunden ist. Fast alle dieser Gegenstände haben einen Typen (Type) und Effekte (Item\_Effect). Auch ist der Spieler (Player) immer in einer Region (Region), in der Gegenstände (Item) und Gegner (Enemy) aufzufinden sind. Das Modell dient in den folgenden Kapiteln als Grundlage für die Modellierung und den Vergleich. \begin{figure}[h] \centering \includegraphics[width=0.6\textwidth]{assets/er-modell} \caption{Konzeptionelles ER-Modell} \label{fig:er-modell} \end{figure} \newpage \subsection{Key-Value-Modellierung} Key-Value Datenbanken sind eine einfache und schnelle Lösung für die Speicherung von unstrukturierten Daten. Wir verwenden in diesem Kapitel Redis. \subsubsection*{Schlüsselaufbau} Keys sind Strings, die eindeutig zum identifizieren von Objekten verwendet werden. Diese starten immer mit dem Namen der Entität, gefolgt von einem Doppelpunkt und der ID des Objekts. Dabei werden alle Entitäten als Redis-Datentyp Hash Map gespeichert um die Daten effizient zu verwalten. Anhand dieses Systems bilden wir die Schlüssel wie folgt ab: % \paragraph{player} % player:{id} = { id, name, health, stamina, focus\_points, level, experience, region\_id} % player:{id}:weapon = { item\_id } % player:{id}:shield = { item\_id } % player:{id}:armor = { item:1, item:2, ... } % player:{id}:talisman = { item:1, item:2, ... } % player:1 = { 1, Jonas, 100, 100, 10, 1, 0, 1 } % \paragraph{region} % region:{id} = { id, name} % region:{id}:items = { item:1, item:2, ... } % region:{id}:enemies = { enemy:1, enemy:2, ... } % region:1 = { 1, limgrave } % region:1:items = [1, 19, 248, 2385] % region:1:enemies = [1, 245, 1234, 11211] % \paragraph{item} % item:{id} = { id, name, gear\_type, gear\_id, region\_id } % item:82347 = { 82347, coolestalisman, talisman, 1, 1 } % item\_effect:{id} = { id, description } % item\_effect:1 = { 1, Du hast mehr Ausdauer } % talisman:{id} = { id, item\_effect\_id } % armor:{id} = { id, item\_effect\_id, type\_id, weight, physical\_defense, magical\_defense} % weapon:{id} = { id, item\_effect\_id, type\_id, weight, damage } % shield:{id} = { id , item\_effect\_id , type\_id, weight, physical\_defense, magical\_defense, guard, damage } % type:{id} = { id, name } % type:1 = { 1, Dolch } % \paragraph{enemy} % enemy:{id} ={id, region\_id, name, health, level, damage} % enemy:{id}:items = { :1, item:2, ... } % dropt diese items % enemy:1 = { 1, 1, Tree\_Sentinel, 30000, 20, 70 } % enemy:1:items = [5, 10] \begin{table}[h] \centering \begin{tabular}{l l l} \hline \textbf{Datentyp} & \textbf{Key-Struktur} & \textbf{Attribute} \\ \hline \texttt{HMAP} & {item\_effect:\{id\}} & id, name, value \\ \texttt{HMAP} & {item\_type:\{id\}} & id, name \\ \\ \texttt{HMAP} & {weapon:\{id\}} & id, item\_effect\_id, item\_type\_id, weight, damage \\ \texttt{HMAP} & {armor:\{id\}} & id, item\_effect\_id, item\_type\_id, weight, defense \\ \texttt{HMAP} & {shield:\{id\}} & id, item\_effect\_id, item\_type\_id, weight, damage, defense \\ \texttt{HMAP} & {talisman:\{id\}} & id, item\_effect\_id \\ \\ \texttt{HMAP} & {item:\{id\}} & id, name, gear\_type, gear\_id \\ \\ \texttt{HMAP} & player:\{id\} & id, name, health, stamina, level, region\_id \\ \texttt{SET} & {player:\{id\}:weapon} & item\_id \\ \texttt{STRING} & {player:\{id\}:shield} & item\_id \\ \texttt{SET} & {player:\{id\}:armor} & item\_id \\ \texttt{SET} & {player:\{id\}:talisman} & item\_id \\ \\ \texttt{HMAP} & {region:\{id\}} & id, name \\ \texttt{SET} & {region:\{id\}:items} & item\_id \\ \texttt{SET} & {region:\{id\}:enemies} & enemy\_id \\ \\ \texttt{HMAP} & enemy:\{id\} & id, name, health, level, damage \\ \texttt{SET} & enemy:\{id\}:items & item\_id \\ \hline \end{tabular} \caption{Übersicht der Schlüsselstrukturen in Redis} \end{table} \newpage % \begin{table}[h] % \centering % \begin{tabular}{l l l} % \hline % \textbf{Datentyp} & \textbf{Key-Struktur} & \textbf{Beschreibung} \\ \hline % SET & \texttt{player:\{id\}:gear\_list} & Liste der Gear IDs, die einem Spieler zugeordnet sind \\ % \hline % \end{tabular} % \caption{Übersicht der Schlüsselstrukturen in Redis} % \end{table} \subsection{Dokumentenorientierte Modellierung} % Wie sieht das in z. B. MongoDB aus? Zeigt hier ein fiktives JSON-Dokument, das einen Gegner oder Spieler mit all seinen verschachtelten Eigenschaften beschreibt. Dokumentenorientierte Datenbanken speichern alles, was zusammengehört, gebündelt in einem Dokument. Wir verwenden in diesem Kapitel MongoDB. \subsubsection*{Aufbau der Dokumente} Jede Entität wird zu einem Dokument und liegt in einer eigenen Collection. Der Player hält von seiner Ausrüstung nur die ids fest, denn Weapon, Armor, Shield und Talisman liegen in eigenen Dokumenten und werden von vielen Player gleich gebraucht. So stehen ihre Grundwerte nur an einer Stelle und nicht bei jedem Player erneut. Genauso bekommen Item und Region ein eigenes Dokument, und Region und Enemy zeigen nur über die ids auf ihre Item und Enemy. So sieht das Dokument eines Player aus: \begin{verbatim} player { id: 1, name: "Jonas", health: 100, stamina: 100, level: 1, region_id: 1, weapon: [ 12 ], shield: 30, armor: [ 41, 42 ], talisman: [ 7 ] } \end{verbatim} Die id beim Player ist dabei die id des Item. Das Item zeigt über gear\_id auf die eigentliche Weapon, die in einem eigenen Dokument liegt und ihren item\_type und item\_effect direkt mitbringt: \begin{verbatim} weapon { id: 213, item_type: { id: 1, name: "Dolch" }, item_effect: { id: 4, name: "Stärke", value: 5 }, weight: 2, damage: 70 } \end{verbatim} \newpage Und so ein Enemy, der seine Item als id behält: \begin{verbatim} enemy { id: 1, region_id: 1, name: "Tree_Sentinel", health: 30000, level: 20, damage: 70, items: [ 5, 10 ] } \end{verbatim} Das Item liegt in einem eigenen Dokument und hält die Grundwerte fest: \begin{verbatim} item { id: 12, name: "Dolch", gear_type: "weapon", gear_id: 213 } \end{verbatim} Und die Region zeigt über die ids auf ihre Item und Enemy: \begin{verbatim} region { id: 1, name: "Limgrave", items: [ 12, 19, 248 ], enemies: [ 1, 245 ] } \end{verbatim} \newpage \subsection{Graph-Datenbank-Modellierung} Graph-Datenbanken legen den Fokus auf die Beziehungen zwischen den Objekten. Wir verwenden in diesem Kapitel Neo4j. \subsubsection*{Aufbau aus Knoten und Kanten} Jede Entität wird zu einem Knoten, der seine eigenen Werte direkt mitträgt. Die Verbindungen aus dem ER-Modell werden zu Kanten zwischen diesen Knoten. So lässt sich direkt verfolgen, welcher Player welche Weapon trägt oder welches Item ein Enemy fallen lässt. Die Knoten und ihre Werte bilden wir wie folgt ab: \begin{table}[h] \centering \begin{tabular}{l l} \hline \textbf{Knoten} & \textbf{Attribute} \\ \hline Player & id, name, health, stamina, level \\ Weapon & id, weight, damage \\ Armor & id, weight, defense \\ Shield & id, weight, damage, defense \\ Talisman & id \\ Type & id, name \\ item\_effect & id, name, value \\ Item & id, name \\ Region & id, name \\ Enemy & id, name, health, level, damage \\ \hline \end{tabular} \caption{Übersicht der Knoten in Neo4j} \end{table} Die Kanten verbinden die Knoten so, wie es schon das ER-Modell vorgibt: \begin{table}[h] \centering \begin{tabular}{l l l} \hline \textbf{Von} & \textbf{Kante} & \textbf{Nach} \\ \hline Player & has\_equipped & Weapon, Armor, Shield, Talisman \\ Player & is\_in & Region \\ Weapon, Armor, Shield & has & Type \\ Weapon, Armor, Shield, Talisman & has & item\_effect \\ Weapon, Armor, Shield, Talisman & is & Item \\ Region & has & Item, Enemy \\ Enemy & drops & Item \\ \hline \end{tabular} \caption{Übersicht der Kanten in Neo4j} \end{table} \newpage \section{Vergleich der Datenmodellierung} \subsection{Vor- und Nachteile des Key-Value-Modells} % Vorteil: Extrem schnell für euer Live-Streaming (Lese-/Schreibzugriffe). Nachteil: Komplexe Abfragen (z.B. "Zeige mir alle Waffen mit Stärke > 20") sind schwierig. Ein klarer Vorteil ist, dass Redis extrem schnell ist. Genau das brauchen wir, weil wir die Daten des Player laufend schreiben und gleichzeitig im Spiel und im Browser wieder auslesen. Über die Keys kommen wir direkt an ein Objekt, ohne lange zu suchen. Ein klarer Nachteil ist, dass komplexe Abfragen schwierig sind. Wollen wir zum Beispiel alle Weapon mit einem bestimmten item\_effect finden, müssen wir das in der Anwendung selbst zusammenbauen, weil Redis dafür keine fertige Suche mitbringt. \subsection{Vor- und Nachteile des dokumentenorientierten Modells} % Vorteil: Alles zu einem Spieler ist in einem JSON-Dokument gebündelt. Nachteil: Redundanzen, wenn z.B. Spieldaten wie "Waffen-Typen" bei jedem Spieler gespeichert werden. Ein klarer Vorteil ist, dass das Modell extrem leserlich und einfach zu modellieren ist. Jedes Dokument ist für sich verständlich und man sieht direkt, welche Daten zu einem Objekt gehören. Ein klarer Nachteil ist bei uns, dass das meiste über ids referenziert wird und nur wenig wirklich verschachtelt ist. Zwar bringt eine Weapon ihren item\_type und item\_effect direkt mit, aber Player, Item, Region und Enemy zeigen größtenteils nur über ids aufeinander. Dadurch nutzen wir die eigentliche Stärke des Modells kaum und haben am Ende vor allem viele einzelne Dokumente, die sich gegenseitig referenzieren. \subsection{Vor- und Nachteile des Graph-Modells} % \todo[inline]{Wir koennten Regionen Traversierung Pathfinding einbauen} Ein klarer Vorteil ist, dass sich Beziehungen sehr leicht abfragen lassen. Wir können zum Beispiel direkt verfolgen, welcher Player welche Weapon trägt oder welches Item ein Enemy fallen lässt, ohne die Verbindungen umständlich selbst zusammenzubauen. % \todo[inline]{Wir haben keine Beziehungen, die ueber mehrere Knoten hinweg gehen. Keine komlexen beziehungen wo der graph einen hohen nutzen mit sich bringt} Ein klarer Nachteil ist, dass Neo4j für unseren Fall überdimensioniert ist. Bei uns geht es vor allem darum, die Daten des Player schnell zu schreiben und wieder auszulesen, und nicht darum, ständig tiefe Beziehungen abzufragen. Für dieses einfache Schreiben und Lesen bringt der Graph mehr Aufwand mit, als er uns am Ende Vorteil bringt. \newpage % \section{Bau der app bis zur Endpräsi} \newpage \subsection{Fazit} % Mehr coole sachen die wir gelernt haben. % Warum wir uns fuer dieses Datenbankmodell entschieden haben. Wir haben die gleichen Daten aus unserem ER-Modell in drei Datenbanken abgebildet und dabei gesehen, wie verschieden das aussieht. In Redis haben wir alles über Keys und Hash Maps abgelegt und kommen so direkt an ein einzelne Objekte. In MongoDB liegt jede Entität als Dokument in ihrer Collection, und die Weapon bringt ihren item\_type und item\_effect gleich mit. In Neo4j ist jede Entität ein Knoten und die Verbindungen aus dem ER-Modell werden zu Kanten, also zum Beispiel has\_equipped oder drops. Aufgefallen ist uns, dass wir bei Redis und MongoDB mehrere Anfragen brauchen, weil vieles nur über ids aufeinander zeigt. Bei Redis ist das allerdings kein Problem, da diese extrem schnell im Vergleich zu den anderen beiden sind. Wollen wir zum Beispiel zu einem Player seine Weapon, holen wir erst den Player, dann das Item und dann die Weapon. So konnten wir gut vergleichen, was jedes Modell bei unseren Daten gut kann und was eher umständlich ist. % \todo[inline]{Noch etwas zu Graph, da wir keine Beziehungsketten haben.} Für Ringstats fällt unsere Wahl auf das Key-Value-Modell mit Redis. Der Grund ist einfach: Bei uns geht es vor allem darum, die Daten des Player laufend im Spiel und Browser zu schreiben und sofort wieder auszulesen. Genau dafür ist Redis gemacht. Über die Keys kommen wir direkt an ein Objekt und müssen nicht lange suchen. Die komplexen Abfragen, bei denen MongoDB oder Neo4j stark wären, brauchen wir kaum, und unsere Daten sind ohnehin nicht tief verschachtelt. Deshalb passt die schnelle und einfache Lösung am besten zu dem, was Ringstats braucht. \newpage \section{Marktrecherche} In der Zwischenpräsentation haben wir uns für das Key-Value-Modell entschieden. In diesem Kapitel schauen wir uns den Markt für Key-Value-Datenbanken genauer an. Wir stellen sechs Kandidaten vor, darunter ArangoDB eine multimodale Datenbank, und führen anschließend eine Nutzwertanalyse durch. \subsection{Betrachtete Datenbanken} \subsubsection{Redis} Redis ist ein In-Memory Key-Value Store und unsere Wahl aus der Zwischenpräsentation. Alle Daten liegen im Arbeitsspeicher, wodurch Lese- und Schreibzugriffe im Bereich von Mikrosekunden liegen. Neben einfachen Strings bringt Redis Datentypen wie Hashes und Sets mit, auf denen unser Schlüsselaufbau aus Kapitel~2.2 direkt aufsetzt. Seit Version 8 steht Redis wieder unter einer Open-Source-Lizenz (AGPLv3) und kostet uns damit nichts. \subsubsection{Memcached} Memcached ist eine verteilte In-Memory-Cache Datenbank und in Sachen Geschwindigkeit vergleichbar mit Redis. Dafür ist der Funktionsumfang bewusst klein gehalten: Es gibt nur einfache Key-Value-Paare, keine Datentypen wie Sets oder Hashes, und keine Persistenz. Unser Schlüsselaufbau mit SETs für Ausrüstung und Regionen lässt sich also nicht direkt abbilden Memcached steht unter der BSD-Lizenz. \subsubsection{ArangoDB (multimodal)} ArangoDB ist eine multimodale Datenbank und vereint Dokumente, Graphen und Key-Value-Zugriffe in einem System mit der gemeinsamen Abfragesprache AQL. Damit hätten wir unsere drei Modellierungen aus Kapitel~2 theoretisch in einer einzigen Datenbank abbilden können. Der Nachteil ist der Langsame zugriff auf die Daten. Seit Version 3.12 steht ArangoDB unter der Business Source License. Für unser Uni-Projekt ist das kostenlos, für einen kommerziellen Betrieb gäbe es Einschränkungen. \subsubsection{Amazon DynamoDB} DynamoDB ist der verwaltete Key-Value- und Dokument-Store von AWS. Die Datenbank skaliert beliebig. Der große Haken ist das Preismodell: DynamoDB läuft nur in der AWS-Cloud und wird pro Anfrage und Speicher abgerechnet. Bei unseren dauerhaften Schreibzugriffen von bis zu 10 Anfragen pro Sekunde würden laufende Kosten entstehen, womit unser Muss-Kriterium \glqq keine Lizenzkosten\grqq{} verletzt ist. Zudem ist die Latenz deutlich höher durch den Netzwerkweg in die Cloud. \subsubsection{etcd} etcd ist ein Key-Value Store, der hauptsächlich zum Speichern von Einstellungen und Konfigurationen benutzt wird, zum Beispiel intern von Kubernetes, ist also nicht dafür gedacht, laufend Spielerdaten zu speichern wie bei uns. Die Lizenz ist Apache~2.0 und damit kostenlos. \subsubsection{Riak KV} Riak KV ist ein verteilter Key-Value Store. Seine Stärke liegt in der Ausfallsicherheit: Daten werden automatisch über mehrere Knoten repliziert, und der Cluster bleibt auch beim Ausfall einzelner Knoten verfügbar. Riak KV steht unter der Apache-2.0-Lizenz. \subsection{Nutzwertanalyse} Wir bewerten alle sechs Datenbanken mit den Auswahlkriterien und Gewichten. Jedes Kriterium wird pro Datenbank mit 0 bis 2 Punkten bewertet und mit dem Gewicht multipliziert. \begin{table}[h] \centering \small \begin{tabular}{l c c c c c c c} \hline \textbf{Kriterium (Gewicht)} & & \textbf{Redis} & \textbf{Memc.} & \textbf{Arango} & \textbf{Dynamo} & \textbf{etcd} & \textbf{Riak} \\ \hline Hohe Performanz & (5) & 2 & 2 & 1 & 1 & 1 & 1 \\ Daten-Streaming & (3) & 2 & 0 & 0 & 2 & 1 & 0 \\ Niedrige Latenz & (3) & 2 & 2 & 1 & 1 & 1 & 1 \\ Skalierbarkeit & (1) & 1 & 1 & 1 & 2 & 0 & 2 \\ Keine Lizenzkosten & (5) & 2 & 2 & 2 & 0 & 2 & 2 \\ Indexing & (2) & 1 & 0 & 1 & 1 & 0 & 1 \\ Vektorrechnungen & (1) & 1 & 0 & 1 & 0 & 0 & 0 \\ Präferenz & (1) & 1 & 0 & 0 & 0 & 0 & 0 \\ \hline \textbf{Gewichtete Summe} & & \textbf{37} & \textbf{27} & \textbf{22} & \textbf{18} & \textbf{21} & \textbf{22} \\ \hline \end{tabular} \caption{Nutzwertanalyse der sechs Key-Value-Datenbanken} \label{tab:nutzwertanalyse} \end{table} Redis liegtklar vorne, weil es als einziger Kandidat sowohl bei Performanz und Latenz als auch beim Daten-Streaming die volle Punktzahl erreicht. Memcached kommt bei der reinen Geschwindigkeit zwar mit, scheitert aber am Muss-Kriterium Daten-Streaming. DynamoDB fällt aber wegen der laufenden Kosten am Muss-Kriterium \glqq keine Lizenzkosten\grqq{} durch. ArangoDB ist als multimodale Datenbank flexibel, aber nicht auf unser schreiblastiges Live-Szenario zugeschnitten, etcd ist für Konfigurationsdaten statt Anwendungsdaten gebaut, und bei Riak KV kommt zur fehlenden Streaming-Funktion die kaum noch aktive Entwicklung hinzu. \subsection{Datenbankauswahl} Aus den sechs betrachteten Datenbanken wählen wir drei aus, die wir umsetzen und miteinander vergleichen, jeweils eine pro Gruppenmitglied: \begin{itemize} \item \textbf{Redis} - der Sieger unserer Nutzwertanalyse und unsere Wahl aus der Zwischenpräsentation, bisher aber noch nicht umgesetzt. Redis dient im Vergleich als Referenz, an der sich die beiden anderen Datenbanken messen müssen. \item \textbf{Memcached} - der direkteste Konkurrent, da ebenfalls In-Memory und ähnlich schnell. Der Vergleich zeigt, welche Redis-Funktionen wir tatsächlich brauchen und was uns bei einem reinen Cache fehlen würde. \item \textbf{ArangoDB} - die multimodale Datenbank im Feld. Der Vergleich zeigt, was uns eine einzige Datenbank für alle drei Modellierungen aus Kapitel~2 gebracht hätte und was sie an Performanz kostet. \end{itemize} \end{document}