Steigerung der Skalierbarkeit und Performance von

Werbung
Steigerung der Skalierbarkeit und Performance
von Webanwendungen durch den Einsatz einer
Redis Datenbank
Abschlussarbeit zur Erlangung des akademischen Grades
Bachelor of Science (B.Sc.)
an der
Hochschule für Technik und Wirtschaft Berlin
Fachbereich Wirtschaftswissenschaften II
Studiengang Angewandte Informatik
1. Prüfer: Prof. Dr. Christin Schmidt
2. Prüfer: Dipl.-Kfm. Andreas Richter
Eingereicht von
Fabian Kirstein
Berlin, 13. August 2012
Kontakt: [email protected], www.fabiankirstein.de
Zusammenfassung
Eine der größten Herausforderung im Zeitalter des Web 2.0 ist es, mit immer größeren Datenmengen und Nutzerzahlen umzugehen. Betreiber von Webanwendungen müssen für diese Herausforderung Lösungen finden und diese in kürzester Zeit umsetzen.
Diese Bachelorarbeit evaluiert, ob und in welchem Maße die Performance und Skalierbarkeit
einer Webanwendung unter Einsatz einer Redis Datenbank gesteigert werden kann. Grundlage
stellt eine bestehende Webanwendung dar, welche eine MySQL Datenbank einsetzt. Die Anwendung wurde hinsichtlich ihrer Qualität bezüglich Performance und Skalierbarkeit bewertet.
Im Anschluss wurde die Anwendung um eine Datenhaltungsschicht auf Basis der Key-ValueDatenbank Redis erweitert, welche als generische Cache-Ebene parallel zur MySQL Datenbank
agiert. Die Schnittstellen der Datenhaltungsschicht blieben dabei unverändert. Die Performance
und Skalierbarkeit der erweiterten Fassung der Anwendung wurde dann ebenfalls bewertet und
mit dem Ausgangszustand verglichen.
Sowohl Performance, als auch Skalierbarkeit konnten durch den Einsatz der Redis Datenbank
gesteigert werden. In der Testumgebung hat sich der Durchsatz um ein Viertel erhöht und die
Anwendung war besser in der Lage mit einer steigenden Anzahl gleichzeitiger Nutzer umzugehen.
Zusätzlich zur Steigerung dieser Werte, wurde durch die Redis Datenbank auch die Grundlage
gelegt, die Performance und Skalierbarkeit mit wenig Aufwand weiter zu steigern. Durch die
einfache Struktur und das simple Key-Value Prinzip der Redis Datenbank, fällt eine horizontale Skalierung besonders leicht. Schlüssel können mit Hilfe von Hashwerten einfach auf mehrere
Server verteilt werden. Eine horizontale Skalierung einer MySQL Datenbank durch Replikation
oder Sharding ist dagegen für die überschaubare Beispielanwendung aufwendiger umzusetzen.
Die Performance und Skalierbarkeit einer Webanwendung kann unter Einsatz einer Redis Datenbank in jedem Fall gesteigert werden, wenn die Datenstrukturen der Anwendung überschaubar
sind und eine unbedingte Konsistenz der Daten nicht notwendig ist.
I
Inhaltsverzeichnis
1 Einleitung
1
1.1
Betriebliches Umfeld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
1.2
Projekt Understandr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
1.3
Motivation
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
1.4
Aufgabenbeschreibung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
1.5
Inhalt und Aufbau der Arbeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
2 Grundlagen
6
2.1
Web 2.0 und Soziale Netzwerke . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
2.2
Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
2.3
Skalierbarkeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
2.4
Relationale Datenbanken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
2.4.1
Performance von MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
2.4.2
Skalierbarkeit von MySQL . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
NoSQL Datenbanken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
2.5.1
Definition und Kategorien . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
2.5.2
Redis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
2.6
Consistent Hashing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
2.7
Objekt-relationales Mapping
14
2.5
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3 Analyse und Vorgehen
16
3.1
Abgrenzung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
3.2
Vorgehen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
16
3.3
Technisches Umfeld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
3.4
Anforderungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
II
INHALTSVERZEICHNIS
3.5
3.6
3.7
3.4.1
Funktionale Anforderungen . . . . . . . . . . . . . . . . . . . . . . . . . .
19
3.4.2
Nicht-funktionale Anforderungen . . . . . . . . . . . . . . . . . . . . . . .
19
3.4.3
Technische Anforderungen . . . . . . . . . . . . . . . . . . . . . . . . . . .
19
Testdesign und Kapazitätsplanung . . . . . . . . . . . . . . . . . . . . . . . . . .
20
3.5.1
Use Cases und Verteilung . . . . . . . . . . . . . . . . . . . . . . . . . . .
21
3.5.2
Entwurf der Testdaten . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22
3.5.3
Page Views und Nutzerzahlen . . . . . . . . . . . . . . . . . . . . . . . . .
24
3.5.4
Testdesign im Überblick . . . . . . . . . . . . . . . . . . . . . . . . . . . .
25
Testumgebung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
3.6.1
Software für die Messung . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
3.6.2
Datenbank befüllen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
3.6.3
Testaufbau, Qualität und Messgrößen . . . . . . . . . . . . . . . . . . . .
28
3.6.4
Test der Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
29
3.6.5
Test der Skalierbarkeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
29
3.6.6
Profiling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
29
Integrations- und Unittests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
30
4 Analyse und Test des Ist-Zustandes
31
4.1
Profiling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
31
4.2
Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
32
4.3
Skalierbarkeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
32
4.4
Testfälle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
34
4.5
Beurteilung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
34
5 Entwurf
35
5.1
Das PlistaModel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
5.2
Datenhaltung und Berechnungen . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
5.3
Verwendung von Redis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
39
5.4
Generische Cache-Ebene . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40
5.5
Redis-Datenmodell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
41
5.6
Denormalisierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
5.7
Sonderfall Suche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
III
INHALTSVERZEICHNIS
6 Implementierung
45
6.1
Cache-Ebene verwenden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
45
6.2
Datenverarbeitung im Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
46
6.3
Die Models im Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
47
6.4
Transparenz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
47
6.5
Probleme und Schwierigkeiten . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
47
6.6
Weitere Implementierungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
48
7 Analyse und Test der neuen Version
50
7.1
Profiling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
7.2
Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
7.3
Skalierbarkeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
51
7.4
Testfälle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
7.5
Beurteilung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
53
8 Zusammenfassung und Ergebnis
54
8.1
Zusammenfassung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
8.2
Allgemeingültigkeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
8.3
Ausblick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
56
A Stack Overflow SQL Abfragen
61
B Beispielhafter Aufbau einer XML-Konfigurationsdatei
63
C Übersicht und Ergebnisse der Tests
64
C.1 PHPUnit Tests der Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
64
C.2 Selenium Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
66
C.3 PHPUnit Tests der Erweiterung . . . . . . . . . . . . . . . . . . . . . . . . . . . .
66
D Inhalt der CD-ROM
67
IV
Abkürzungen
CPU Central Processing Unit
CSS Cascading Style Sheets
DOM Document Object Model
HTML Hypertext Markup Language
HTW Hochschule für Technik und Wirtschaft
I/O Input/Output
MVC Model View Controller
RDBMS Relationale Datenbankmanagementsysteme
SQL Structured Query Language
V
Abbildungsverzeichnis
1.1
Ausschnitt der Understandr Oberfläche
. . . . . . . . . . . . . . . . . . . . . . .
3
2.1
Hinzufügen und Entfernen von Servern aus Edlich et al. 2010, S. 37 . . . . . . . .
14
3.1
Deployment-Diagramm des technischen Umfelds . . . . . . . . . . . . . . . . . .
18
3.2
Use Cases der Anwendung Understandr . . . . . . . . . . . . . . . . . . . . . . .
21
3.3
Traffic für 2 Tage des DE-CIX Internetknoten (de-cix.net, 03.07.2012) . . . . . .
25
3.4
Testdaten Übersicht . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
26
3.5
Testanfragen Übersicht . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
26
3.6
Screenshot JMeter mit Testplan . . . . . . . . . . . . . . . . . . . . . . . . . . . .
27
4.1
Anwortzeit gegenüber Anzahl gleichzeitiger Nutzer im Ist-Zustand . . . . . . . .
33
4.2
Durchsatz gegenüber Anzahl gleichzeitiger Nutzer im Ist-Zustand . . . . . . . . .
33
5.1
Grundsätzlicher Aufbau einer MVC-Anwendung (CakePHP 2012)
35
5.2
Klassendiagramm der Plista Klassenbibliothek für Objekt-relationales Mapping
. . . . . . . .
mit den wichtigsten Klassen und Methoden . . . . . . . . . . . . . . . . . . . . .
36
5.3
Entity-Relationship-Modell des bestehenden MySQL-Implementierung . . . . . .
38
5.4
Klassendesign der Redis Cache Ebene . . . . . . . . . . . . . . . . . . . . . . . .
44
7.1
Anwortzeit gegenüber Anzahl gleichzeitiger Nutzer im Vergleich zwischen alter
und neuer Version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.2
52
Durchsatz gegenüber Anzahl gleichzeitiger Nutzer im Vergleich zwischen alter und
neuer Version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
VI
52
Tabellenverzeichnis
2.1
Beispieltabelle Personen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
2.2
Auszug aus der Beispieltabelle Personen nach der Manipulation . . . . . . . . . .
15
3.1
Verteilung der sieben Performance-Test Aktivitäten über die Kapitel dieser Arbeit 17
3.2
Übersicht der nicht-funktionalen Anforderungen . . . . . . . . . . . . . . . . . . .
19
3.3
Verteilung der Anzahl an Antworten auf Stack Overflow . . . . . . . . . . . . . .
23
3.4
Verteilung der Stimmanzahl auf Stack Overflow . . . . . . . . . . . . . . . . . . .
24
4.1
Ergebnis des Profiling des Ist-Zustandes . . . . . . . . . . . . . . . . . . . . . . .
31
4.2
Ergebnisse des Performance-Tests des Ist-Zustandes . . . . . . . . . . . . . . . .
32
6.1
Elemente einer XML-Konfigurationsdatei der Redis DataSource . . . . . . . . . .
45
7.1
Ergebnis des Profiling mit Redis-Cache . . . . . . . . . . . . . . . . . . . . . . . .
50
7.2
Ergebnisse des Performance-Tests mit Redis-Cache . . . . . . . . . . . . . . . . .
51
VII
Kapitel 1
Einleitung
Die nachfolgende Bachelorarbeit beschäftigt sich mit der Möglichkeit und der Durchführung, die
Skalierbarkeit und Performance einer Webanwendung durch den Einsatz der nicht-relationalen
Datenbank Redis zu steigern. Dafür wird eine bereits bestehende Webanwendung, welche die
relationale Datenbank MySQL zur Datenhaltung einsetzt, als Grundlage verwendet. Diese Anwendung wird hinsichtlich ihrer Qualität in Performance und Skalierbarkeit untersucht. Im
nächsten Schritt wird eine Erweiterung der Anwendung auf Basis einer Redis Datenbank modelliert und funktionsfähig umgesetzt. Abschließend wird die neue Version der Anwendung mit der
ursprünglichen Fassung verglichen und eine Bewertung der Anforderungen durchgeführt. Insbesondere wird das Ergebnis hinsichtlich traditionelleren Verfahren zur Erhöhung der Performance
und Skalierbarkeit einer Webanwendung auf Basis einer MySQL Datenbank bewertet.
Das in dieser Arbeit beschriebene Vorgehen soll dabei nicht nur Gültigkeit für die Beispielanwendung haben, sondern auch als Ideenanstoß für die Verbesserung der Performance und Skalierbarkeit von Webanwendungen durch die Verwendung einer Redis Datenbank, aber auch ähnlicher,
nicht-relationaler Datenbanken, dienen.
1.1
Betriebliches Umfeld
Die Anfertigung dieser Abschlussarbeit wurde bei der plista GmbH in Berlin durchgeführt. Das
Unternehmen ist Betreiber eines online Werbenetzwerkes im deutschen Raum mit über 40 Millionen Besuchern auf tausenden Webseiten.1 Die plista GmbH wurde im Jahr 2008 gegründet
und hat 70 Mitarbeiter in den Bereichen IT, Marketing, Personalwesen und Management.1 Die
Schlüsseltechnologie Cross-Domain Collaborative Filtering2 ermöglicht eine leistungsfähige Auslieferung von Werbekampagnen. (plista GmbH 2012) Der Gegenstand dieser Arbeit steht nicht
unmittelbar mit dieser Kerntätigkeit in Verbindung, sondern hat vielmehr ein gänzlich neues
Projekt des Unternehmens als Grundlage.
1 Stand:
April 2012
2 Werbeanzeigen
und Empfehlungen werden über Domaingrenzen hinweg ausgeliefert und die individuellen
Themen der Anzeigen werden aus den Interessen aller Benutzer gefiltert.
1
KAPITEL 1. EINLEITUNG
1.2
Projekt Understandr
Die plista GmbH plant als Nebenprojekt die Veröffentlichung einer interaktiven und kollaborativen Internetplattform. Ziel des Projektes ist es, die Meinungsbildung und den Meinungsaustausch der Menschen zu fördern. Das Projekt verfolgt dabei keine wirtschaftlichen Interessen und
soll zukünftig als eigenständiges Open-Source Projekt publiziert werden. Die Anwendung heißt
Understandr und stellt im Wesentlichen eine Transformation der klassischen Idee einer Pro- und
Contraliste in eine soziale Anwendung dar. Nutzer können eine kurze Aussage bzw. ein Statement1 erstellen, welches durch alle Nutzer mit Argumenten und Gegenargumenten unterstützt
bzw. abgelehnt wird. Den Argumenten kann einzeln von jedem Nutzer zugestimmt werden, wodurch den Argumenten mehr Gewicht verliehen wird. Aus diesen Stimmen wird die Meinung der
Nutzer zu einer Aussage ermittelt. Jedem Nutzer wird zusätzlich seine persönliche Meinung zu
einer Aussage präsentiert, welche sich aus der Anzahl seiner Stimmen zusammensetzt. Die Meinung wird dabei in Prozent für jeweils pro und contra angegeben. Um den Nutzer direkt in seiner
Meinungsbildung zu unterstützen, werden zusätzlich verschiedene Statistiken präsentiert. Dazu
zählen zunächst generelle Analysen, wie Auflistungen von kontroversen oder viel diskutierten
Aussagen, aber auch persönliche Empfehlungen. Dem Nutzer werden aufgrund seines Lese- und
Stimmverhaltens relevante Diskussionen empfohlen, um ihn dadurch zu weiteren Aktivitäten auf
der Plattform zu animieren.
Es existiert bereits ein lauffähiger Prototyp (siehe Abbildung 1.1), welcher Gegenstand und
Grundlage dieser Arbeit darstellt. Dieser Prototyp wurde vom Autor dieser Arbeit im Rahmen
eines dreimonatigen Praktikums implementiert. Die beschriebenen Grundfunktionalitäten sind
bereits vollständig integriert. Darüber hinaus verfügt der Prototyp über weitere Merkmale. Dazu
zählt insbesondere ein Schlagwortsystem2 , mit dessen Hilfe die Aussagen kategorisiert und sortiert werden und der Nutzer einen schnellen Zugriff auf bestimmte Themengebiete erhält. Eine
Suchfunktion vervollständigt die Möglichkeiten Aussagen zu entdecken und den Nutzer zu aktivieren. Weiterführende Informationen befinden sich insbesondere in den Kapiteln 3.5.1 und 3.3.
1.3
Motivation
Die plista GmbH verfolgt bei der Entwicklung von Understandr mehrere Ziele. Zum einen soll
eine übersichtliche Möglichkeit geschaffen werden, die Meinung zu einer konkreten Fragestellung zu erfahren. Dem Konzept stehen dabei klassische Umsetzungen, wie zum Beispie OnlineDiskussionsforen gegenüber. Bei einem Forum ist es in der Regel notwendig, sich mehrere Beiträge
zu einer Fragestellung durchzulesen, um eine passende oder korrekte Antwort zu finden. Dagegen
ermöglicht das Pro-Contra-Konzept besonders schnell die Meinung der beteiligten Nutzer abzulesen. Konkrete Aussagen, in Form der Argumente, können dann zusätzlich studiert werden. Ein
weiteres Ziel ist es, die Nutzer aktiv bei Ihrer persönlichen Meinungsbildung zu unterstützen.
1 Im Laufe dieser Ausarbeitung werden die Begriffe Statement und Aussage im Zusammenhang mit der Beispielanwendung gleichbedeutend verwendet
2 Der
Begriff Schlagwort wird im folgenden gleichbedeutend mit dem Begriff Tag verwendet.
2
KAPITEL 1. EINLEITUNG
Abbildung 1.1: Ausschnitt der Understandr Oberfläche
Dafür sollen in erster Linie die Empfehlungen und Verlinkungen auf andere Aussagen verantwortlich sein, welche unter anderem durch kollaboratives Filtern ermittelt werden. Der Nutzer
wird dadurch auf neue Problemstellungen aufmerksam und erfährt zusätzlich welche Argumente
und Gegenargumente es bereits gibt.
Die gesamte Plattform ist demzufolge hoch interaktiv und lebt ausschließlich von Inhalten, die die
Nutzer selbst generieren. Dieser Aspekt des Projektes ist charakteristisch für eine Web 2.0 Anwendung (Shuen 2008, S. 1) und führt zu weiteren Schlussfolgerungen bezüglich der zukünftigen
Nutzung von Understandr. Die Art der Plattform hat das Potential, einen positiven, direkten
Netzwerkeffekt zu generieren. Der Mehrwert einer Web 2.0 Plattform erhöht sich umso mehr
Nutzer die Plattform verwenden, was wiederum die Attraktivität für neue Nutzer erhöht. (Shuen
2008, S. 32) Die plista GmbH rechnet daher mit der Möglichkeit eines schnellen Anstiegs der
Nutzerzahlen und damit einhergehend einer hohe Anzahl an gleichzeitigen Zugriffen auf den
Dienst. Daher soll bereits vor der Veröffentlichung die Qualität der Anwendung im Umgang mit
solchen Szenarien ermittelt werden.
Im betrieblichen Umfeld werden bereits erfolgreich Redis Datenbanken bei der Auslieferung von
Werbeanzeigen verwendet. Daher soll geprüft werden, ob die geforderte Qualität durch den Einsatz einer solchen Datenbank erreicht werden kann und inwieweit die Nutzung praktikabel und
sinnvoll ist.
3
KAPITEL 1. EINLEITUNG
1.4
Aufgabenbeschreibung
Die Aufgabe der Bachelorarbeit leitet sich unmittelbar von den Anforderungen der plista GmbH
an die neue Webplattform ab. Die bestehende prototypische Implementierung soll bezüglich Performance und Skalierbarkeit evaluiert werden, um den konkreten Bedarf und Umfang einer Umgestaltung zu ermitteln. Eine Steigerung der Performance und Skalierbarkeit soll dann durch
den Einsatz einer Redis Datenbank erfolgen, welche parallel zur bereits bestehenden Datenbank
MySQL verwendet werden soll. Das Unternehmen geht davon aus, dass die geforderte Qualität
dadurch erreicht werden kann. Ein zentraler Aspekt der Aufgabe ist dabei, dass die Implementierung der Erweiterung transparent1 zu erfolgen hat. Nur relevante Teile sollen umgestaltet
werden und sämtliche Schnittstellen sollen nach Möglichkeit erhalten bleiben und können somit
weiterhin identisch verwendet werden.
1.5
Inhalt und Aufbau der Arbeit
Diese Bachelorarbeit teilt sich in sieben Abschnitte. Im ersten Abschnitt der Arbeit werden
die notwendigen theoretischen Grundlagen für das Verständnis und die Analyse der Aufgabenstellung gelegt. Im Mittelpunkt steht dabei die klare Definition der Begriffe Performance und
Skalierbarkeit, sowie die gegenseitige Abgrenzung. Es werden problembezogene Informationen
zum Thema MySQL vermittelt und eine Einführung in das Gebiet der nicht-relationalen Datenbanken mit Schwerpunkt auf Redis Datenbanken gegeben. Auch auf speziellere Themen wie
Consistent Hashing und Objekt-relationale Mapper wird eingegangen, da sie ebenfalls Grundlagen für die nachfolgenden Kapitel darstellen. Darüber hinaus werden die allgemeinen und technischen Herausforderungen von Web 2.0 Anwendungen und sozialen Netzwerken betrachtet, um
eine Verständnis für die Motivation dieser Arbeit zu schaffen.
Im nächsten Abschnitt wird die Aufgabe analysiert. Dazu gehört das technische Umfeld und
die funktionalen und nicht-funktionalen Anforderungen festzuhalten. Der Schwerpunkt dieses
Abschnittes liegt bei der Ausarbeitung eines hinreichenden Analyseverfahrens, um die Ausgangsbedingungen quantitativ messen zu können. Dafür enthält der Abschnitt eine detaillierte
Kapazitätsplanung, Beschreibung von Testaufbau und Testverfahren und ein Konzept zur Qualitätssicherung.
Der dritte Abschnitt greift das erarbeitete Testverfahren auf und führt es an der bestehenden
Version durch. Die Performance und Skalierbarkeit von Understandr wird in Zahlen gefasst und
damit der Ist-Zustand für einen späteren Vergleich festgehalten.
Der nächste Abschnitt beschäftigt sich mit dem Entwurf der Erweiterung. Dabei wird die bestehende Implementierung analysiert und verschiedene Ansätze, das existierende System mit einer
Redis Datenbank zu erweitern, diskutiert. Schwerpunkt dabei ist, die Erweiterung möglichst
transparent zu gestalten und eine Steigerung der Performance und Skalierbarkeit auch durch
ein geeignetes Datenmodell zu unterstützen. Eine konkrete Lösung wird anschließend entworfen,
bewertet und in ein Klassendesign umgesetzt.
1 Der Begriff Transparenz wird in dieser Arbeit in seiner informationstechnischen Bedeutung verwendet. Er
beschreibt, dass der interne Aufbau eines Systems von außen nicht sichtbar ist.
4
KAPITEL 1. EINLEITUNG
Der vierte Abschnitt beschreibt die tatsächliche Implementierung des vorangegangenen Entwurfs.
Dabei wird aufgezeigt, inwieweit der Entwurf praktikabel ist und an welchen Stellen sich Probleme ergeben haben.
Im nächsten Abschnitt wird eine Analyse der erweiterten Version der Anwendung durchgeführt
und ihre Leistung bezüglich Performance und Skalierbarkeit in Zahlen gefasst. Darüber hinaus
wird auf die funktionale Qualität der neuen Version eingegangen.
Im letzten Abschnitt werden die Ergebnisse zusammengefasst und bewertet. Darüber hinaus wird
geprüft, ob das beschriebene Verfahren allgemeingültig anwendbar ist.
5
Kapitel 2
Grundlagen
2.1
Web 2.0 und Soziale Netzwerke
Für den Begriff des Web 2.0 existiert keine einheitliche und einfache Definition. (Governor et al.
2009, S. 1) Im September 2005 veröffentlichte Tim O’Reilly1 ein Paper, um den Begriff Web 2.0
genauer zu definieren. Bis heute ist es die am weitesten verbreitete Erklärung des Begriffes. Dabei
gibt O’Reilly keine feste Definition vor, sondern erläutert den Begriff anhand von Beispielen von
existierenden Webseiten und Technologien. (Governor et al. 2009, S. 2) Daraus abgeleitet sind
Web 2.0-Entwurfsmuster entstanden, welche wesentliche Merkmale einer Web 2.0 Anwendung
beschreiben. Für diese Ausarbeitung besonders relevant sind dabei Users Add Value (engl. für
Nutzer erhöhen Mehrwert) und Data is the Next Intel Inside (engl. für Daten sind das nächste
Intel Inside). Aus den Titeln dieser Muster lässt sich bereits erkennen, dass Daten einen zentralen
Aspekt einer Web 2.0 Anwendung darstellen. (O’Reilly 2005) Bekannten Web 2.0 Vertretern wie
Flickr, YouTube oder Facebook haben alle gemeinsam, dass sie große Datenmengen verarbeiten
und diese einer sehr großen Menge an Nutzern gleichzeitig zur Verfügung stellen. Einige Zahlen
der populären Web 2.0 Anwendung Facebook veranschaulichen die enormen Datenmengen und
Nutzerzahlen. Im Juni 2010 hatte Facebook 400 Millionen aktive Nutzer, welche jede Woche
5 Milliarden Inhalte (Status Updates, Kommentare, Uploads, Nachrichten und weiteres) teilen
und 3 Milliarden Fotos im Monat hochladen. Tausende Cache-Server mit jeweils mehreren Terabyte Speicher ermöglichen diese hohen Kapazitäten. (highscalability.com 2012) Diese Zahlen
zeigen, dass bei populären Webseiten mit vom Nutzer generierten Inhalten und einem positiven
Netzwerkeffekt die Datenverarbeitung eine ganz neue Herausforderung darstellt. Die betroffenen
Unternehmen müssen teilweise gänzlich neue Wege für die Entwicklung ihrer technischen Infrastruktur finden. So entwickelte Facebook 2008 das verteilte und skalierbare Datenbanksytem
Cassandra oder den PHP-Compiler HipHop, um die Ausführungsgeschwindigkeit ihrer Software
zu erhöhen. Etablierte technische Lösungen schienen, den neuen und erhöhten Anforderungen
nicht gerecht zu werden. Entwickler einer neuen Web 2.0 Plattform sollten sich also diesen neuen
Herausforderungen bewusst sein und ihre Web 2.0 Anwendungen für die Verarbeitung großer
Nutzerzahlen und Datenmengen zu optimieren. Darüber hinaus muss aufgrund eines möglichen
1 Softwareentwickler
und Gründer des O’Reilly Verlages
6
KAPITEL 2. GRUNDLAGEN
Netzwerkeffektes immer von einem schnellen Anstieg der Werte ausgegangen werden. Auch darauf sollte eine moderne Web 2.0 Anwendung in jedem Fall vorbereitet sein.
2.2
Performance
Der Begriff Performance ist in der Informationstechnik gleichzusetzen mit Leistungsfähigkeit. Es
ist möglich, Performance zu messen und zu vergleichen. Die Kriterien zur Bewertung von Performance ergeben sich aus dem zu bewertenden System. (ITWissen 2012) Verschiedene Kennzahlen
können bei der Bewertung verwendet werden. Diese Ausarbeitung beschäftigt sich mit der Performance einer Webanwendung. Dabei sind besonders die Kennzahlen Antwortzeit, Durchsatz
und Ressourcenauslastung relevant. (Meier 2007, S. 24)
Antwortzeit Die Zeit, die ein System benötigt um auf eine Anfrage zu reagieren wird als Antwortzeit bezeichnet. Sie wird häufig in Sekunden angegeben. Ein gängiges Beispiel ist der
Aufruf einer beliebigen Webseite. Die Zeit, die vergeht bis die Seite im Browser erscheint,
ist in diesem Fall die Antwortzeit. Die Angabe dieser Zeit kann in mehrere Komponenten
zerlegt werden. Im Fall einer Webseite wäre das die Antwortzeit des Browsers, die Netzwerkzeit und die Zeit, die der Server zum Bearbeiten der Anfrage benötigt. (Menascé et
al. 2004, S. 13) Die Antwort wird häufig als wichtiges Qualitätskriterium für eine Webanwendung gesehen, da Nutzer bei langen Antwortzeiten die Anfrage abbrechen.
Durchsatz Die Anzahl an Arbeitseinheiten, die in einer bestimmen Zeiteinheit von einem System verarbeitet werden kann, wird als Durchsatz bezeichnet. Beispiele sind Anfragen pro
Sekunde, Aufrufe am Tag oder Hits pro Sekunde.(Meier 2007, S. 26) Die verwendete Angabe ergibt sich aus dem Kontext. Im Fall von Webanwendungen wird häufig von Anfragen
auf die Webseite pro Sekunde oder Minute gesprochen. (Menascé et al. 2004, S. 14)
Ressourcenauslastung Welche Ressourcen eines Systems in welchem Maße bei einer Anfrage
verwendet werden wird als Ressourcenauslastung bezeichnet. Die wichtigsten Ressourcen
dabei sind Prozessor, Arbeitsspeicher, Festplatten Input/Output (I/O) und Netzwerk I/O.
(Meier 2007, S. 25)
2.3
Skalierbarkeit
Ein System wird als skalierbar bezeichnet, wenn es in der Lage ist, mit einer erhöhten Auslastung umzugehen, ohne dass die Performance negativ beeinflusst wird. (Meier 2007, S. 26) Cal
Henderson (2006, S. 246) beschreibt eine skalierbares System genau mit drei Charakteristiken:
• Ein System kann sich an eine erhöhte Nutzung anpassen
• Ein System kann sich an einen erhöhten Datenbestand anpassen
• Ein System ist wartbar
7
KAPITEL 2. GRUNDLAGEN
Der Begriff der Skalierbarkeit muss ganz klar vom Begriff Performance getrennt werden. Ein System mit sehr guter Performance muss nicht zwangsläufig auch gut skalierbar sein. Beispielsweise
ist eine Webanwendung mit einer sehr guten Antwortzeit mit 1000 Nutzern und 1 GB an Daten
nur dann skalierbar, wenn sie die Antwortzeit bei der zehnfachen Anzahl an Nutzern halten kann.
(Henderson 2006, S. 246)
Vertikale Skalierung Durch das Hinzufügen von Ressourcen zu einem System, kann die Skalierbarkeit dieses erhöht werden. Dieses Verfahren wird als vertikale Skalierung bezeichnet.
Gängige Ressourcen sind Arbeitsspeicher oder Prozessor. Zum Beispiel kann ein Webserver,
dessen Kapazitäten an die Grenzen gestoßen sind, durch einen leistungsfähigeren Server ersetzt werden. Sollten die Kapazitäten des neuen Servers ebenfalls nicht mehr ausreichen,
würde dieser wieder ersetzt werden. Der offensichtliche Nachteil dieses Verfahrens ist, dass
der Skalierung eine Obergrenze gesetzt ist, wenn keine bessere Hardware auf dem Markt
verfügbar ist. Darüber hinaus sind die Kosten für Hardware nicht linear, sondern exponentiell. Etwas leistungsfähigere Hardware kann oft ein Vielfaches an Mehrkosten verursachen.
Die Stärke der vertikalen Skalierung liegt beim einfachen Softwaredesign. Die Software
kann einfach auf die neue Hardware portiert werden, ohne die Implementierung anzupassen. (Henderson 2006, S. 248-250)
Horizontale Skalierung Das zweite Konzept, ein System zu skalieren, basiert ebenfalls auf
dem Hinzufügen von Hardware. Im Gegensatz zur vertikalen Skalierung wird bestehende
Hardware nicht modifiziert, sondern einfach um weitere Hardware ergänzt. Im Fall eines
einzelnen Webservers, würde im Zuge eines Wachstums, ein zweiter Server dem System
hinzugefügt werden. Der Vorteil dieser Methode ist, dass es möglich ist, reguläre Hardware
für das System zu verwenden. Man ist nicht auf leistungsfähige Serverhardware angewiesen.
Dadurch ist es theoretisch möglich die Hardwarekosten zu senken. Dem gegenüber steht
allerdings der erhöhte Administrationsaufwand für die Wartung und Installation mehrerer
Rechner. Allerdings ist der Aufwand nicht linear, da man davon ausgehen kann, dass alle
Rechner mit der gleichen Basissoftware ausgestattet sind. Nachteil und Herausforderung der
horizontalen Skalierung ist die Software, welche in der Lage sein muss, mit einem System,
bestehend aus vielen Rechnern, umzugehen. Die Software muss in der Lage sein, mit der
Hardware zu skalieren. (Henderson 2006, S. 248-250)
2.4
Relationale Datenbanken
Das relationale Datenbankmodell wurde 1970 von Edgar Codd entwickelt und hat sich bis heute als das Wichtigste, noch im Einsatz befindliche, Datenbankmodell etabliert. Grundlage ist
die Darstellung von Daten in Tabellen und die Beziehung der Tabellen zueinander. Durch diese
Relationen lassen sich echte Gegebenheiten in der Datenbank nachbilden. Als Relationale Datenbankmanagementsysteme (RDBMS) werden alle Datenbanken bezeichnet, die diese Systematik
verwenden. Für dem Zugriff auf die Daten wird häufig die Structured Query Language (SQL)
eingesetzt. (Pröll et al. 2011, S. 26-27) In dieser Arbeit steht das seit 1995 entwickelte, freie
Datenbanksystem MySQL im Mittelpunkt, welches zu den RDBMS zählt und SQL verwendet.
Der nächste Abschnitt beschäftigt sich mit Performance und Skalierbarkeit von MySQL und
theoretischen Möglichkeiten, diese zu steigern.
8
KAPITEL 2. GRUNDLAGEN
2.4.1
Performance von MySQL
Wie performant eine MySQL-Installation sein kann wird von verschiedensten Faktoren beeinflusst. Einer der wichtigsten Faktoren ist, ob die angefragten Daten von der Festplatte geladen
werden müssen oder sie sich schon in einem Puffer befinden. MySQL verfügt über ein QueryCache, in dem die Ergebnisse bereits ausgeführter Abfragen zwischengespeichert werden und
bei erneuter Anfrage das Ergebnis sofort zurückgegeben wird. (Pröll et al. 2011, S. 318-319)
Der Query-Cache liegt im Arbeitsspeicher und ist daher sehr schnell. Allerdings unterliegt die
Nutzung des Caches einigen Einschränkungen bezüglich zulässiger Select-Anweisungen, welche
zwischengespeichert werden können. So können keine Abfragen, die Teil anderer Abfragen sind,
oder Abfragen mit Variablen verwendet werden. Die zwischengespeicherten Daten werden jedes
Mal gelöscht, wenn eine Änderung auf eine betreffende Tabelle durchgeführt wird. (Pröll et al.
2011, S. 167-168)
Daneben wird die Performance immer beeinflusst, wenn die Datenbank auf Ressourcen, wie
Prozessor, Arbeitsspeicher oder Festplatte, wartet. Aber auch andere Tabellen stellen Ressourcen dar, welche eventuell durch weitere Anfragen blockiert sind. Auch das Design der Abfragen
und der Tabellen hat maßgebliche Auswirkungen auf die Leistungsfähigkeit der Datenbank. Die
genaue Performance kann im Einzelfall durch entsprechende Messungen und Analysen erfolgen. MySQL bietet für diesen Zweck eigene Benchmark- und Profilingbefehle, um individuelle
Schwachstellen zu finden. (Pröll et al. 2011, S. 318-321) Zusätzlich existieren verschiedene Methoden zur Abfrageoptimierung, unter anderem das Slow-Query-Log, mit dessen Hilfe sich langsame
Abfragen schnell ermitteln und optimieren lassen. Das Anlegen von Indizes, um häufig abzufragende Werte in separaten Index-Tabellen effektiv zu verwalten und schnell zugänglich zu machen,
gehört ebenfalls dazu. (Pröll et al. 2011, S. 359-363) Zusammengefasst lässt sich festhalten, dass
die Bewertung der Performance von MySQL individuell betrachtet werden muss und eine pauschale Aussage nicht zu treffen ist. Optimal konfiguriert, kann eine auf MySQL Datenbank eine
sehr gute Performance aufweisen. Auf der anderen Seite kann in speziellen Anwendungsfällen die
Performance von MySQL nicht ausreichend sein und es ist notwendig auf alternative Systeme
zurückzugreifen. Siehe dazu Kapitel 2.5.
2.4.2
Skalierbarkeit von MySQL
Bei der Betrachtung der Skalierbarkeit von MySQL soll an dieser Stelle nur auf horizontale
Skalierung eingegangen werden. Diese Art der Skalierung stellt eine Herausforderung da, für die
sich verschiedene Lösungsansätze entwickelt haben. Einige der wichtigsten Konzepte werden in
diesem Kapitel näher betrachtet. Eine vertikale Skalierung ist problemlos möglich, unterliegt aber
den in Kapitel 2.3 diskutierten Einschränkungen.
Replikation Webanwendungen weisen häufig weit mehr lesende als schreibende Operationen
auf, oftmals in einem Verhältnis von 10 zu 1. Von diesem Umstand profitiert das Konzept
der Replikation, welches von MySQL nativ unterstützt wird. Es ist dem Begriff zu entnehmen, dass dabei Daten auf ein oder mehr Rechner repliziert werden, um dadurch eine
höhere Lesekapazität zu erhalten. Dabei wird zwischen Master und Slave unterschieden.
Eine MySQL-Installation kann ein Slave von genau einem Master sein. Umgekehrt kann
eine Installation ein Master von keinem oder vielen Slaves sein. Sämtliche Schreibopera9
KAPITEL 2. GRUNDLAGEN
tionen werden nur an einen Master-Server gesendet, der alle Operationen wie gewöhnlich
ausführt und zusätzlich in einer Logdatei alle Operationen protokolliert. Ein verbundener
Slave-Server liest diese Datei und führt die Operationen aus. Auf diesem Weg wird er in
exakt den gleichen Zustand versetzt. Ein Master mit einem Slave hätte dann die doppelte Lesekapazität usw. Die Schreibkapazität bleibt bei einem Master allerdings konstant.
(Henderson 2006, S. 277-279)
Clustering Um sowohl die Lesekapazitäten, als auch Schreibkapazitäten zu skalieren kann eine MySQL Datenbank in sogenannte Cluster aufgeteilt werden. In der einfachsten Form
werden beim Clustering die verschiedenen Tabellen einer Datenbank auf mehrere Server
verteilt. Dabei müssen sich Tabellen, auf denen Joins angewendet werden sollen auf einem Server befinden. Joins über Rechnergrenzen hinweg sind nicht ohne Weiteres möglich.
Durch diese Einschränkung ist Clustering im möglichen Leistungsgewinn limitiert. (Henderson 2006, S. 287-289)
Sharding Um diese Limitierung zu überwinden, ist es notwendig, die eigentlichen Tabellen
ebenfalls aufzuteilen. Dieses Verfahren wird als Sharding oder auch Federation bezeichnet.
Dabei werden Tabellen anhand ihrer Zeilen aufgeteilt und auf verschiedene Server verteilt.
Die Implementierung dieser Methode ist außerordentlich kompliziert. Um Operationen auf
den Tabellen auszuführen, müssen die Teile über mehrere Server hinweg zusammengeführt
werden und Joins werden unpraktikabel aufwendig. Für die Bewältigung diese Art der Verteilung, wäre in jedem Fall die Nutzung einer Middleware notwendig. (Henderson 2006, S.
287-289) Die Software MySQL Cluster1 bietet mittlerweile diese Funktionalität. Unter der
Bezeichnung Auto-Sharding ist es möglich Tabellen auf beliebig vielen Server zu verteilen
und dabei bleibt der Zugriff absolut transparent. Realisiert wird die Funktion durch eine
Hash-Funktion auf den Primärschlüssel (siehe dazu auch 2.6). Auch Joins sind weiterhin
wie gewohnt einsetzbar. Ziel ist es, den Nachteil der Replikation auszugleichen und auch
Schreiboperationen zu skalieren. (Oracle 2012, S. 5-6)
Die verschiedenen Verfahren zeigen, dass es möglich ist MySQL zu skalieren. Unter Nutzung
des MySQL Clusters sind sogar beachtliche Werte möglich. Der Hersteller gibt über eine Milliarde Schreiboperationen pro Minute bei 30 Servern an. (Oracle 2012, S. 9) Für den konkreten
Anwendungsfall sollte die zweckmäßigste Methode gewählt werden und eventuelle Limitationen
ermittelt werden.
2.5
NoSQL Datenbanken
Der Begriff NoSQL vereint eine ganze Reihe von Datenbanksystemen, welche sich alle das Ziel
gesetzt haben, die existierenden Nachteile der etablierten, relationalen Datenbanksysteme, auszugleichen. (Gull 2011, S. 18) Obwohl der Begriff und die neuen Datenbanksysteme erst in
den letzten Jahren massiv an Popularität gewonnen haben, geht die Geschichte der NoSQLDatenbanksysteme bis in das Jahr 1979 zurück. In diesem Jahr entwickelte Ken Thompson2
1 Der
Begriff ist an dieser Stelle verwirrend, da wesentlich mehr als einfaches Clustering zur Verfügung steht.
2 Mitentwickler
des UNIX-Betriebssystems und der Programmiersprache C
10
KAPITEL 2. GRUNDLAGEN
bereits eine Key-Hash-Datenbank namens DBM. Es folgten in den 80er Jahren verschiedene
NoSQL-Systeme, wie Lotus Notes, BerkeleyDB und GT.M. (Edlich et al. 2010, S. 1) Im Jahr
1998 wurde dann zum ersten Mal den Begriff NoSQL, im Zusammenhang mit einer Open-SourceDatenbank von Carlo Strozzi, verwendet. (Gull 2011, S. 188) Obwohl dieses System immer noch
auf einem relationalen Datenbankmodell basierte, stand keine SQL-API mehr zur Verfügung. Erst
seit der Jahrtausendwende, durch die Entstehung des Web 2.0 und der Tendenz immer größere
Datenmengen zu generieren, begann die NoSQL Bewegung. Seit 2006 werden die heute üblichen
NoSQL-Systeme, wie HBase/Hypertable, CouchDB, Cassandra, Voldemort, Dynamo/Dynomite,
MongoDB, Redis und viele mehr1 entwickelt. (Edlich et al. 2010, S. 1) Der eigentliche Begriff
NoSQL tauchte aber erst Anfang 2009 bei einem Treffen zum Thema strukturierte, verteilte Datenspeicher auf. Johan Oskarsson bereichnete damit Datenbanken, die nicht relational sind, auf
verteilten Systemen liegen und meistens auf ACID-Eigenschaften2 verzichten. (Gull 2011, S. 188)
2.5.1
Definition und Kategorien
Eine offizielle Definition des Begriffes NoSQL existiert nicht. Das NoSQL-Archiv (nosql-databases.org
2012) gibt an, dass ein Datenbanksystem, welches einige der folgenden Eigenschaften aufweist,
als NoSQL Datenbank gilt:
• nicht relational, verteilt und horizontal skalierbar
• Open-Source
• schemafrei
• einfache Replikationsunterstützung
• einfache API
• Konsistenzmodell BASE3
• Unterstützung für sehr große Datenmengen
Das NoSQL-Archiv listet derzeit mehr als 120 NoSQL-Kernsysteme4 , welche sich in vier wichtige
Kategorien gliedern und von Edlich et al. (2010, S. 7) wie folgt beschrieben werden.
Key-Value-Systeme Diese Kategorie stellt ein einfaches Schema, bestehend aus Schlüssel und
Wert zur Verfügung. Oft können die Schlüssel in Namensräumen sortiert werden und Werte
1 http://nosql-databases.org
2 Atomicity,
Consistency, Isolation, Durability (engl. für Atomarität, Konsistenz, Isolation, Beständigkeit)
3 Basically
Available, Soft state, Eventual consistency - NoSQL Datenbanken achten nicht streng auf Konsistenz
der Daten, da Performance und Verfügbarkeit dadurch sinken. Die Datenkonsistenz wird zum Beispiel, von einer
nachfolgenden Operation wieder hergestellt. Ein konsistenter und inkonsistenter Zustand wechseln sich somit
ständig ab. (Gull 2011, S. 18)
4 Es
wird zwischen Kernsystemen und nachgelagerten Systemen unterschieden, wobei die erst genannten direkt
aus den Bedürfnissen des Web 2.0 entstanden sind und Letztere erst später entstanden sind.
11
KAPITEL 2. GRUNDLAGEN
bestimmten Datentypen zugeordnet sein, wie Hashes oder Listen. Durch dieses einfache
Schema ist eine schnelle und effiziente Datenverarbeitung möglich. Als Nachteile gelten die
nur einfachen Abfragemöglichkeiten.
Als größter Vorteil der Key-Value-Systeme gilt die einfache Skalierbarkeit. In traditionellen
Datenbanken sind die Daten relational miteinander verbunden, wodurch eine Skalierung oft
erschwert wird. Eben diesen Nachteil haben die Key-Value-Systeme nicht. Jedes SchlüsselWert Paar steht zunächst nur für sich und lässt sich deshalb viel unproblematischer auf
verschiedene Rechner verteilen. (Edlich et al. 2010, S. 131)
Bekannte Vertreter: Redis, Voldemort, Scalaris, MemcacheDB, Riak
Column-Family-Systeme Diese Systeme ähneln klassischen Tabellen, wobei ein Schlüssel auf
eine unterschiedliche Anzahl an Key-Value Daten zeigt. Einer solchen Spalte können jederzeit weitere Datenpaare hinzugefügt werden.
Bekannte Vertreter: HBase, Cassandra, Hypertable
Document Stores Diese Datenbanken speichern strukturierte Daten in verschiedenen Formaten und verweisen über eine ID auf diese. Häufig verwendete Formate sind JSON, YAML
oder RDF.
Bekannte Vertreter: CouchDB, MongoDB
Graphendatenbanken Die letzte Kategorie speichert Daten in Graph- oder Baumstrukturen
und stellt dadurch die Beziehung von Daten untereinander dar. Die Einsatzmöglichkeiten
von Graphendatenbanken sind vielfältig und in den letzten Jahren hat ihre Bedeutung
stark zugenommen. Durch das Verbinden von Informationen im Internet mit Geodaten,
Pfadsuche oder Molekülmodellierung. Jede Graphendatenbank verwendet unterschiedliche
Arten von Graphen. Die Wichtigsten sind derzeit die Property-Graphen.
Bekannte Vertreter: Neo4j, SonesDB, FlockDB
2.5.2
Redis
Redis ordnet sich in die Kategorie der Key-Value-Systeme ein und wurde Anfang 2009 von Salvatore Sanfillippo als Open-Source Projekt gestartet. Der Begriff Redis leitet sich vom Wort
Redistribute (engl. für umverteilen) und von Remote Dictionary Service (engl. for entfernter
Wörterbuchdienst) ab. Redis gilt als Nachfolger von Memcached1 . Alle Daten werden im Arbeitsspeicher gespeichert und gleichen sich nach und nach auf die Festplatte ab. Mit leichten
Geschwindigkeitseinbußen können die Daten auch unmittelbar auf die Festplatte geschrieben
werden. Es gilt demzufolge, dass alle Daten einer Redis Datenbank in den Arbeitsspeicher passen müssen. (Edlich et al. 2010, S. 132) Die Unterstützung für virtuellen Speicher gilt als überholt.
(Seguin 2012, S. 7) Die Datenbank ist sehr schnell. Um die 100.000 Zugriffe pro Sekunde sind
gängige Werte. Schreiboperationen sind in der Regel schneller als Leseoperationen. (Offizielle
Redis Webseite 2012)
Redis stellt fünf verschiedene Datenstrukturen zur Verfügung. Jeder Wert in der Datenbank kann
aus einer dieser Strukturen bestehen.
1 Cache-Server
zum Ablegen von Daten in den Arbeitsspeicher
12
KAPITEL 2. GRUNDLAGEN
String Mit dem einfachsten Datentyp String lassen sich beliebige Werte speichern. Der Begriff String ist dabei etwas verwirrend, da natürlich nicht nur Zeichenketten, sondern auch
Zahlen abgelegt werden können. Neben den Befehlen zum Speichern und Auslesen des
Datentyps bietet Redis zusätzliche Befehle für die Manipulation der Werte. Zum Beispiel
ist eine Verkettung von Zeichenketten oder das gezielte Auslesen eines Bereiches der Zeichenkette möglich. Handelt es sich um einen Zahlenwert kann dieser mit entsprechenden
Operatoren erhöht oder verkleinert werden. Demzufolge ist der String Datentyp für Zähler
oder für die Speicherung von serialisierten Objekten geeignet.
List Dieser Datentyp bietet eine einfache Listenfunktionalität und stellt ein Feld von Strings dar,
auf welches verschiedenste Operationen angewendet werden können. Neue Elemente lassen
sich an das Ende oder an den Anfang einfügen. Die Elemente behalten stets ihre Reihenfolge und es ist möglich über den Index auf bestimmte Werte zuzugreifen. Darüber hinaus
können Werte mehrfach vorkommen. Passende Einsatzmöglichkeiten dieses Datentyps sind
das Speichern von Logs oder Referenzen auf andere Schlüssel.
Set Mit Sets lassen sich eindeutige Werte in einem unsortierten Feld abspeichern. Im Prinzip
lassen sich nur Werte hinzufügen und löschen. Aber auch das Zusammenführen von mehreren Sets ist möglich. Ein Anwendungsfall für Sets ist eine Liste von Freunden auf einer
sozialen Plattform.
Sorted Set Dieser Datentyp bietet zunächst die gleiche Funktionalität wie die Sets. Wird jedoch
um eine Gewichtung ergänzt. Jedes Element besitzt zusätzlich einen Score, der allerdings
vom Nutzer angegeben werden muss. Der Wert kann erhöht oder verringert werden. Anhand
des Scores können die Elemente des Sets sortiert und ausgegeben werden. Verwendung kann
dieser Datentyp bei Ranglisten jeder Art finden.
Hash Der letzte Datentyp bietet die Möglichkeit, den Wert eines Schlüssels besser zu qualifizieren. Der Wert besteht aus einer einfachen Hashtabelle. Die einzelnen Felder können
separat befüllt und ausgelesen werden. Ebenfalls sind einfache Rechenoperationen, wie bei
den reinen Strings, möglich. Der Wert eines einzelnes Feldes kann zum Beispiel erhöht oder
verkleinert werden. Hashes eignen sich zum Speichern von strukturierten Daten.
(Seguin 2012, S. 9-13)
Redis ist nicht in der Lage nativ zu skalieren. Erst in zukünftigen Versionen soll die dynamische
Verteilung der Daten auf mehrere Server unterstützt werden. Dennoch existieren zwei einfache
Möglichkeiten, Redis zu skalieren
Client-Sharding Das Verteilen bzw. Sharding der Daten auf mehrere Rechner lässt sich leicht
auf Applikationsebene durchführen. Mit Hilfe einer Hash-Funktion (siehe Kapitel 2.6) lassen
sich die Schlüssel analysieren und auf verschiedene Server verteilen, wodurch die Last auf
einen Server verringert wird. (Edlich et al. 2011, S. 166)
Replikation Analog zu MySQL unterstützt Redis auch Replikation. Dabei kann ein Master
seine Daten auf mehrere Slaves verteilen. Wie bei MySQL wird auf diesem Weg die Lesekapazität erhöht. (Edlich et al. 2011, S. 166)
13
KAPITEL 2. GRUNDLAGEN
2.6
Consistent Hashing
Die einfache Skalierbarkeit von Key-Value-Datenbanken, wie Redis, basiert unter anderem auf
dem Prinzip des Consistent Hashing. Im Allgemeinen bedeutet Hashing, dass nach einem festgelegten Algorithmus ein Wert aus einer großen Menge auf einen Wert aus einer viel kleineren Menge
abgebildet wird. Das wohl einfachste Beispiel eines solchen Algorithmus ist die Modulo-Funktion.
Hash-Funktionen haben verschiedenste Einsatzmöglichkeiten. Unter anderem werden sie in verteilten Systemen verwendet. Zum Beispiel kann im Rahmen einer Client-Server-Anwendung,
einem einzelnen Client aus einer großen Menge schnell ein passender Server zugeordnet werden.
Sollte sich die Anzahl der Server nie ändern, würde die Modulo-Funktion für ein solches Szenario
völlig ausreichen. Allerdings unterliegen solche Systeme in der Realität ständigen Veränderungen.
Die tatsächliche Anzahl an Servern ist oft nicht vorhersehbar oder die Anforderungen an die
Anwendung wachsen und weitere Server müssen hinzugefügt werden. Bei einer normalen Hashfunktion würden sich durch das Hinzufügen eines Servers fast alle Zuordnungen ändern und die
betroffenen Daten müssten verschoben werden. Im Falle von großen Datenmengen ist das zweifellos nicht erwünscht. Consistent Hashing bietet eine Möglichkeit dieses Problem zu lösen. Dabei
wird der mögliche Adressraum als Ring angenommen, auf dem zunächst die Server anhand ihres
Hashwertes verteilt werden. Im nächsten Schritt werden die Hashwerte der Clients ermittelt. Der
jeweils verantwortliche Server ist der im Uhrzeigersinn am nächsten gelegene auf dem Ring. Sollte
ein Server aus dem Ring entfernt werden, muss nun nur ein Teil der Daten verschoben werden.
Der nachfolgende Server würde die Daten des entfernten Servers übernehmen. Wird ein weiterer
Server hinzugefügt, werden ihm alle Clients zwischen ihm und seinem Vorgänger zugewiesen.
(Edlich et al. 2010, S. 36-39)
Abbildung 2.1: Hinzufügen und Entfernen von Servern aus Edlich et al. 2010, S. 37
2.7
Objekt-relationales Mapping
Auf eine relationale Datenbank wird häufig mit SQL zugegriffen, was dem Konzept der objektorientierten Programmierung, möglichst immer mit Objekten zu arbeiten, widerstrebt. Daher wird
eine zusätzliche Schicht verwendet, welche den Zugriff auf die Datenbank abstrahiert und die
14
KAPITEL 2. GRUNDLAGEN
relationalen Daten als Objekt darstellt. Dieses Verfahren wird als Objekt-relationales Mapping
bezeichnet. Der Zugriff auf die Datenbank kann dann ausschließlich über Objekte erfolgen und
es ist nicht länger notwendig direkt SQL zu verwenden.
ID
1
2
3
Vorname
Bruce
Peter
Tony
Nachname
Wayne
Parker
Stark
Tabelle 2.1: Beispieltabelle Personen
Zum Beispiel ist in Tabelle 2.1 eine einfache Form einer SQL-Tabelle dargestellt. Nun könnte es
eine Klasse Person geben, welche diese Tabelle repräsentieren würde. Durch den Aufruf einer
Methode zum Abrufen von Daten erhält man ein Objekt der Klasse.
$person = Person :: findById (2);
Dieses Objekt würde eine Zeile bzw. einen Datensatz der Tabelle repräsentieren. Über die Eigenschaften des Objektes könnten dann die einzelnen Informationen des Datensatzes abgerufen
und manipuliert werden.
$person - > Vorname = " Clark " ;
$person - > Nachname = " Kent " ;
Nach einer Manipulation des Objektes würden durch den Aufruf einer weiteren Methode die
Daten zurück in die Datenbank geschrieben werden.
$person - > save ();
ID
2
Vorname
Clark
Nachname
Kent
Tabelle 2.2: Auszug aus der Beispieltabelle Personen nach der Manipulation
(Möhrke 2012, S. 327-329)
15
Kapitel 3
Analyse und Vorgehen
3.1
Abgrenzung
An dieser Stelle muss die zentrale Aufgabe dieser Arbeit von anderen Verfahren und Techniken
um die Performance oder Skalierbarkeit einer Webanwendung zu erhöhen, abgegrenzt werden.
Grundsätzlich ist festzuhalten, dass eine Webanwendung ein verteiltes System ist, dessen Qualität von verschiedensten Faktoren abhängig ist. Im einfachsten Fall ist mindestens ein Client,
ein Server und ein Netzwerk beteiligt. Alle Teile des Systems bestimmen das Verhalten. Eine
umfassende Optimierung müsste sich also mit allen Aspekten auseinandersetzen. Der Fokus dieser Arbeit liegt aber auf der Optimierung der Datenhaltung. Es besteht die Möglichkeit, dass die
geforderten Anforderungen mit Optimierungen an anderen Stellen der Anwendung ebenfalls zu
erreichen sind und außerhalb des Rahmens dieser Arbeit sollten diese zusätzlich geprüft werden.
3.2
Vorgehen
Um allen Anforderungen in vollem Umfang gerecht zu werden, wird neben dem Entwurf und der
Umsetzung, der Fokus besonders auf die Analyse gelegt. Die gesamte Umsetzung des Projektes unterliegt dafür einem genau festgelegten Vorgehen, welches zunächst hauptsächlich in drei
Schritte gegliedert ist:
Analyse des Ist-Zustandes
Im ersten Schritt wird der Ist-Zustand hinsichtlich Performance
und Skalierbarkeit analysiert. Um den Erfolg durch die Weiterentwicklung im Nachhinein zu bewerten ist es notwendig, den bestehenden Zustand hinreichend zu analysieren und die aktuelle
Performance und Skalierbarkeit in Zahlen zu fassen. Mit dem Ziel diese Bewertung mit einer hohen Qualität durchzuführen, wird sich das Vorgehen an den sieben Performance-Test Aktivitäten
aus dem Buch Performance Testing Guidance for Web Applications (Meier 2007, S. 45) orientieren. Die sieben Aktivitäten sind über mehrere Kapitel dieser Arbeit verteilt und die Zuordnung
ist in Tabelle 3.1 dargestellt.
16
KAPITEL 3. ANALYSE UND VORGEHEN
Aktivität
Kapitel
Testumgebung identifizieren
Kapitel 3.3
Performance Kriterien identifizieren
Nicht-funktionale Anforderungen in Kapitel
3.4.2
Planung und Design von Tests
Kapitel 3.5
Testumgebung konfigurieren
Kapitel 3.6
Implementierung des Testdesign
Kapitel 3.6
Tests ausführen
Kapitel 4
Analyse und Zusammenfassung
Kapitel 4
Tabelle 3.1: Verteilung der sieben Performance-Test Aktivitäten über die Kapitel dieser Arbeit
Neben diesen sieben Aktivitäten wird der bestehende Zustand in geeigneten Testverfahren festgehalten werden. Damit wird die Möglichkeit geschaffen, die neue Version auf Fehler und abweichendes Verhalten zu prüfen. Durch dieses Vorgehen ist es hinterher möglich, den neuen Zustand
mit dem Ausgangszustand zu vergleichen, indem die gleichen Tests wiederholt werden. Siehe
dazu Kapitel 3.7.
Entwurf und Implementierung der Erweiterung Nach Abschluss der Analyse des bestehendes Zustandes wird mit dem Entwurf und der anschließenden Implementierung der Erweiterung begonnen.
Analyse der erweiterten Version
Im letzten Schritt wird die Analyse des Ist-Zustandes
ebenfalls an der neuen Version der Anwendung durchgeführt. Dadurch lässt sich die Kapazität
und die Funktionsweise der Weiterentwicklung mit dem ursprünglichen Zustand direkt vergleichen und eine hinreichende Qualität kann gewährleistet werden.
3.3
Technisches Umfeld
Understandr basiert auf einer typischen Zusammenstellung verschiedener Server- und Webtechnologien. Grundlage bildet der LAMP-Stack, bestehend aus der Linux-Distribution Debian1 , dem
Webserver Apache, dem Datenbanksystem MySQL und der Skriptsprache PHP.
Demzufolge kommt PHP für die eigentliche Anwendungsentwicklung zum Einsatz. Dabei wird
auf das quelloffene PHP-Framework CakePHP gesetzt. CakePHP basiert auf der Model View
Controller (MVC) Architektur und bietet somit eine strikte Trennung zwischen den Schichten
Darstellung (View), Steuerung (Controller) und Datenhaltung (Model). Für die Darstellungsschicht werden die gängigen Technologien Hypertext Markup Language (HTML), Cascading Style
Sheets (CSS) und JavaScript verwendet. Darüber hinaus findet die freie JavaScript-Bibliothek
jQuery Anwendung, welche die Nutzung von JavaScript, insbesondere die Manipulation des Document Object Model (DOM) und die Animation von Elementen, stark vereinfacht.
1 Alternativ
kann und wird auch Ubuntu, eine wiederum auf Debian basierende Linux-Distribution, eingesetzt
17
KAPITEL 3. ANALYSE UND VORGEHEN
Für die Analyse und den Test der Anwendung wird eine Testumgebung eingerichtet. Die serverseitige Infrastruktur dafür stellt die Hochschule für Technik und Wirtschaft (HTW) Berlin durch
das Aufsetzen von virtuellen Maschinen auf einem Server mit der Virtualisierungssoftware Xen.
Für die Testumgebung wird ein Webserver und ein Datenbankserver aufgesetzt. Der inhaltliche
Fokus auf die Datenbank spiegelt sich dadurch auch in der Infrastruktur wieder und es wird eine
absolut unabhängige Bearbeitung der Datenbankinfrastruktur ermöglicht. Als Client für Testanfragen wird ein einfacher Desktop-PC fungieren, welcher über das Internet auf die Testserver
zugreift. Abbildung 3.1 zeigt den vollständigen Aufbau in einem Deployment-Diagramm.
Abbildung 3.1: Deployment-Diagramm des technischen Umfelds
18
KAPITEL 3. ANALYSE UND VORGEHEN
3.4
3.4.1
Anforderungen
Funktionale Anforderungen
Es ist gefordert, dass die Anwendung sich nach der Ergänzung um die Redis Datenbank exakt genauso verhält wie im Ausgangszustand. Ein potentieller Benutzer der Weboberfläche darf keinen
Unterschied bei den Funktionalitäten feststellen. Dadurch folgt, dass keine besonderen funktionalen Anforderungen an die Umsetzung gestellt werden. Alle Funktionen müssen entsprechend
dem Ist-Zustand zur Verfügung stehen.
3.4.2
Nicht-funktionale Anforderungen
Durch die Weiterentwicklung sollen verschiedene nicht-funktionale Anforderungen an die Anwendung sichergestellt werden. Dazu zählt zunächst natürlich die Steigerung der Performance.
Langfristiges Ziel ist es, eine durchschnittliche Antwortzeit von 50 Millisekunden zu erreichen.
Ziel dieser Arbeit ist nicht, genau diesen Wert zu erreichen, sondern zunächst eine Steigerung
der Performance überhaupt zu erreichen. Es wird davon ausgegangen, dass ein entsprechend sehr
guter Wert von 50 ms weitere Optimierungen erfordert, welche nicht Gegenstand dieser Arbeit
sind (siehe Kapitel 3.1).
Neben der Performance ist die Skalierbarkeit eine weitere nicht-funktionale Anforderung. Zunächst
ist gefordert, dass die Anwendung auf einem Rechner bzw. auf einem Webserver und einem Datenbankserver besser skaliert als es momentan der Fall ist. Konkret heißt das, dass die Anwendung
bei steigender Nutzerzahl einen konstanten Durchsatz pro Minute halten kann. Für den Fall, dass
die Nutzerzahl auf ein Niveau ansteigt, bei dem der Durchsatz einbricht, soll eine horizontale
Skalierung der Hardware unkompliziert und hinreichend schnell möglich sein. Faktisch heißt das,
dass ein bestehendes System innerhalb kürzester Zeit und mit geringem Aufwand um weiteren
Server erweitert werden kann.
Nicht-funktionale Anforderungen
Relative Steigerung der Performance
Steigerung der Skalierbarkeit
Einfache horizontale Skalierbarkeit ermöglichen
Transparenz der Erweiterung
Tabelle 3.2: Übersicht der nicht-funktionalen Anforderungen
3.4.3
Technische Anforderungen
Die technischen Anforderungen orientieren sich am bestehenden System. Abgesehen von der
Redis Datenbank soll die Anwendung um keine neuen Technologien erweitert werden.
19
KAPITEL 3. ANALYSE UND VORGEHEN
3.5
Testdesign und Kapazitätsplanung
Für die Umsetzung des Tests der Performance und Skalierbarkeit von Understandr ist eine Kapazitätsplanung und ein entsprechendes Testdesign unumgänglich. Die Anzahl an Nutzern, ihr
Verhalten und zu erwartende Datenmengen sind Grundlage des Tests. (Meier 2007, S. 48) Es
existieren verschiedene Methoden, um die Last auf eine Anwendung vorherzusagen. Eine grundlegende Aussage solcher Techniken ist, dass eine Vorhersage direkt mit Daten der Vergangenheit
verbunden ist. (Calzarossa et al. 2002, S. 147) Da die Anwendung noch nicht online ist, muss auf
Daten einer anderen, ähnlichen Plattform zurückgegriffen werden. Neben der Nutzung solcher
historischen Daten ist die Ausarbeitung von Nutzungsszenarien (Use Cases) ausschlaggebend,
um die Last auf eine Anwendung nah am Produktionsbetrieb zu verteilen. (Calzarossa et al.
2002, S. 150)
Beispiel Stack Overflow
Als Quelle der historischen Daten wird die Webseite Stack Over-
flow (www.stackoverflow.com) dienen. Stack Overflow ist eine kostenfreie Plattform, auf der
Nutzer Fragen zum Thema Programmierung stellen können. Andere Nutzer können diese Frage beantworten. Das reine Lesen der Beiträge ist ohne Anmeldung möglich. Das Schreiben von
Fragen, Antworten und Kommentaren erfordert eine Registrierung. (stackoverflow.com 2012a)
Die Webseite ist Teil des Stack Exchange Netzwerkes, welches neben Stack Overflow 841 weitere
Webseiten mit dem gleichen Konzept zu verschiedensten Themengebieten betreibt. Die Fragen
und Antworten können von allen Nutzern auf- und abgewertet werden. (stackexchange.com 2012)
Die Inhalte werden vollständig von den Nutzern erstellt und gepflegt.
Man kann schnell erkennen, dass sich die grundsätzlichen Funktionalitäten von Understandr und
von Stack Overflow stark ähneln. Nutzer können Beitrage erstellen, Antworten geben und abstimmen. Daher ist die Webseite sehr gut geeignet, um als Vorlage für die Kapazitätsanalyse
von Understandr zu fungieren. Darüber hinaus ermöglicht das Open Source Projekt Stack Exchange Data Explorer Zugriff auf die öffentlichen Daten-Dumps des Stack Exchange Netzwerkes.
(data.stackexchange.com 2012) Dadurch können spezifische Daten von Stack Overflow mit Hilfe
von SQL2 Befehlen abgerufen und zusammengefasst werden. Auf diesem Weg werden detaillierte
Verteilungs- und Nutzungsmuster der Daten erstellt.
Stack Overflow existiert seit September 2008 (stackoverflow.com 2009) und die freie Datenbank
umfasst alle Daten bis heute. Als Grundlage für die Kapazitätsplanung von Understandr wird der
Umfang der Daten und die Anzahl an Zugriffen auf Stack Overflow bis September 2009 fungieren. Eine Planung über ein Jahr hinaus ist unpraktikabel und würde den Umfang der möglichen
Testbedingungen sprengen. Zudem ist Stack Overflow eine sehr erfolgreiche Webseite mit sehr
schnellem Wachstum. Eine Orientierung an diesen Werten führt zu einer sehr optimistischen
Prognose mit ausreichend Puffer.
1 Stand:
2 Stack
26. Juni 2012
Exchange verwendet Microsoft SQL Server, daher wird die SQL-Variante T-SQL verwendet
20
KAPITEL 3. ANALYSE UND VORGEHEN
3.5.1
Use Cases und Verteilung
Für die Durchführung aussagekräftiger Lasttests ist es unabdingbar, Anfragen an die Anwendung
zu stellen, welche tatsächlich von echten Nutzern auf diese Art durchgeführt werden. Dafür
müssen Use Cases, also konkrete Fälle, wie eine Anwendung genutzt wird ermittelt werden. Diese
Use Cases können anschließend simuliert werden. An dieser Stelle sollen nur die relevantesten Use
Cases herausgearbeitet und bewertet werden, da es unpraktisch bis unmöglich ist, jedes mögliche
Szenario zu simulieren. (Meier 2007, S. 140) Die Use Cases ergeben sich aus einer Analyse der
bestehenden Anwendung und sind in der Abbildung 3.2 visualisiert.
Abbildung 3.2: Use Cases der Anwendung Understandr
Für den eigentlichen Lasttest der Anwendung wird aus diesen Use Cases wiederum nochmal eine
Auswahl getroffen, um das Testszenario möglichst einfach und überschaubar zu halten. Für den
Zweck dieser Arbeit ist es relevanter, dass sich die Use Cases in der Art der abzurufenden Daten
aus der Datenbank unterscheiden. Dabei kann nicht jeder Anwendungsfall abgedeckt werden.
Diese spezifischen Anwendungsfälle von Understandr werden selbstverständlich nicht gleich verteilt auftauchen. Der Datenbestand von Stack Overflow zeigt eine mögliche Verteilung auf. Ein
Jahr nach dem Start von Stack Overflow wurden an einem Tag etwa 5000 Fragen und Antworten,
5000 Kommentare und 25.000 Stimmen abgegeben bei einer Million Page Views (siehe Anhang
A). Daraus folgt, dass nur 3% der Anwendungsfälle schreibender Natur sind. Dieser Umstand
21
KAPITEL 3. ANALYSE UND VORGEHEN
wird bei den Use Cases von Understandr berücksichtigt. Im Folgenden werden die Use Cases für
den Lasttest erläutert und ihre relative Häufigkeit bestimmt.
Statement ansehen Dieser Use Case repräsentiert die zentrale Funktionalität von Understandr.
Es ist anzunehmen, dass der Großteil der Nutzer den Dienst ausschließlich für diesen Anwendungsfall verwenden wird. Über Suchmaschinen oder Verlinkungen werden die Statements unmittelbar zu finden sein. Darüber hinaus ist dieser Use Case auch aus Sicht der
Performance am signifikantesten, da er die aufwendigste Aggregation von Daten beinhaltet.
Statement-, Argument-, User- und Stimmdaten werden an dieser Stelle zusammengeführt
(siehe Kapitel 5.2). Aus diesem Grund sollen 70% der Anfragen während des Lasttests auf
Statement-Ansichten zugreifen. Dabei wird kein Statement mehrfach abgerufen, um eine
maximale Verteilung zu gewährleisten.
Startseite aufrufen Die Bedeutung der Startseite von dynamischen Diskussionsseiten, wie
Stack Overflow, ist längst nicht so groß, wie die Bedeutung der eigentlichen Inhalte. Dennoch soll der Abruf Teil des Tests werden. 10% der Testanfragen werden auf die Startseite
verwendet.
Suchen Die Suchfunktionalität legt eine größere Last auf die Datenbank, da bei großen Datenmengen ein umfangreicher Index durchsucht werden muss. Es ist anzunehmen, dass
diese Funktion sehr zeitintensiv ist. Darüber hinaus wird sie relativ häufig von Nutzern
verwendet. 10% der Testanfragen werden eine Suche auslösen
Statement erstellen Auch wenn schreibende Aktionen nur einen sehr geringen Anteil der Gesamtnutzung ausmachen, werden sie Teil des Tests sein. Auf diesem Weg wird die Datenbank auch schreibend verwendet. Die Erstellung eines neuen Statements wird mit 2% am
Test beteiligt sein. Insgesamt werden die schreibenden Szenarien 10% ausmachen. Das ist
deutlich mehr als im Fall von Stack Overflow, da durch die nur sehr kurzen Texteingaben
bei Understandr die Schwelle zur aktiven Beteiligung niedriger sein könnte.
Argument erstellen Die Erstellung eines neuen Argumentes wird 3% aller Anfragen ausmachen.
Stimme für Argument abgeben Die Stimmabgabe erfordert nur einen einzigen Klick, daher
wird die Beteiligung am Test 5% betragen.
3.5.2
Entwurf der Testdaten
Um die Anwendung nah realitätsnah zu testen, ist es notwendig, die Datenbank mit Daten zu
füllen. Dabei steht zunächst die reine Menge der Daten im Vordergrund, obwohl die Verteilung
der Daten auch Beachtung finden soll. Es werden nie alle Statements gleich viele Argumente und
nie alle Argumente gleich viele Stimmen haben. Darüber hinaus gibt es auf der einen Seite aktive
und auf der anderen Seite passive Nutzer. Eine Vorstellung über diese Verteilung liefert ebenfalls
die Stack Overflow Datenbank. Die Understandr Datenbank wird mit Testdaten befüllt, die
sich dieser Verteilung annähern. Besonders relevant und kritisch für die Leistung sind natürlich
Statements mit besonders vielen Argumenten, Stimmen und beteiligten Nutzern. In diesem Fall
ist die Last auf die Datenbank am größten und somit als Testgegenstand am relevantesten. Daher
22
KAPITEL 3. ANALYSE UND VORGEHEN
wird der Fokus beim Lasttest der Anwendung auf einen solchen Fall gelegt werden. Statements
mit wenig, bis keinen Argumenten werden der Vollständigkeit halber erstellt, um eine akkurate
Testumgebung zu schaffen. Alle SQL-Abfragen für die Ermittlung der folgenden Daten befinden
sich in Anhang A.
Statements und Nutzer
Inklusive September 2009 wurden auf Stack Overflow fast 300.000
Fragen erstellt und es waren mehr als 65.000 Nutzer registriert. Die Testdaten für Understandr
werden sich daher an diesen Werten orientieren.
Verteilung der Argumente Zunächst ist die minimale und maximale Anzahl an Antworten
eine relevante Größe. Im Fall von Stack Overflow ist das 0 und 416. Nun kann betrachtet werden
wie sich diese Zahlen genau verteilen. Die durchschnittliche Anzahl an Antworten beträgt 2,17.
Insgesamt wurden bisher ca. 3.300.000 Fragen erstellt.
Anzahl Antworten
Vorkommen
Prozent
0
280.000
8
1-5
2.900.000
88
6-10
100.000
3
11-50
14.000
0,5
51-416
140
0,01
Tabelle 3.3: Verteilung der Anzahl an Antworten auf Stack Overflow
In Tabelle 3.3 kann man deutlich erkennen, dass am häufigsten null bis fünf Antworten je Frage
auftreten, wohingegen über 10 Antworten praktisch keine Rolle spielen. Diese Verteilung ist ein
guter Anhaltspunkt, um die Testdaten für Understandr sinnvoll zu verteilen. Im Gegensatz zu
Stack Overflow ist Understandr kein Forum für ein spezifisches Thema, bei dem die Beantwortung
einer Frage im Idealfall Fachwissen verlangt. Es ist davon auszugehen, dass die Nutzer häufiger zu
einem Statement ein Argument erstellen. Eine häufige Anzahl (80%) von 10 Argumenten scheint
dafür eine sinnvolle Wahl zu sein. Des Weiteren wird die Datenbank zu 10% mit Statements ohne
Argumente und zu 10% mit Statements mit 10 bis 50 Argumenten befüllt werden.
Verteilung der Nutzerbeteiligung
Stack Overflow hat ca. 1.225.000 angemeldete Nutzer,
welche nicht alle gleich aktiv auf der Plattform sind. Die Aktivität lässt sich sehr gut an der
so genannten Reputation ablesen. Dieser Wert gibt an, welchen Stellenwert die Meinung eines
Nutzers hat. Der Wert steigt hauptsächlich durch das Erstellen von guten Fragen und Antworten.
Jeder Nutzer startet mit einer Reputation von 1 und fällt auch nie unter diesen Wert. Demzufolge
sind Nutzer mit einer Reputation von 1 absolut passiv oder sehr wenig aktiv (Reputation kann
auch wieder verloren werden). (stackoverflow.com 2012b) Ca. 670.000 User haben eine Reputation
von 1. Also nur die Hälfte aller Nutzer beteiligt sind aktiv an der Erstellung der Inhalte. Das
gleiche Muster soll bei den Testdaten zur Anwendung kommen. Die Hälfte aller Nutzer werden als
Autor von Statements, Argumenten und Stimmen verwendet. Dabei werden alle Nutzer als gleich
aktiv angenommen und nicht zwischen sehr aktiven und wenig aktiven Nutzern unterschieden.
23
KAPITEL 3. ANALYSE UND VORGEHEN
Anzahl Stimmen
0
1
2
3
4
5
6
-1
Anzahl Beiträge
3.970.000
2.560.000
1.300.000
680.000
380.000
230.000
150.000
120.000
Prozent
8
88
3
0,5
<0,01
<0,01
<0,01
<0,01
Tabelle 3.4: Verteilung der Stimmanzahl auf Stack Overflow
Verteilung der Stimmen
Auch bei Stack Overflow ist es möglich für Fragen und Antworten
zu stimmen. Insgesamt existieren fast 9.990.000 Beiträge (Fragen und Antworten) mit einem
durchschnittlichen Score von 1,7. Die Verteilung der Stimmen ist in Tabelle 3.4 ersichtlich. Weit
über 50 Prozent haben demzufolge eine Score zwischen 0 und 2. Die gleiche Verteilung soll für
die Stimmen der Argumente verwendet werden.
Schlagwörter Jedes Statement wird zufällig mit null bis drei Schlagwörtern versehen.
3.5.3
Page Views und Nutzerzahlen
Der Kennwert Page View entspricht dem Abruf einer einzelnen HTML-Datei von einem Server.
Dabei beinhaltet eine Page View, den Abruf aller eingebetteten Dateien einer HTML-Datei, wie
zum Beispiel CSS oder JavaScript Dateien. (Meier 2007, S. 94) Der Begriff ist daher von einer
einzelnen HTTP-Anfrage abzugrenzen. Das Darstellen einer einzelnen HTML-Seite beinhaltet
fast immer mehrere HTTP Anfragen. Als Kennzahl für die Beliebtheit eines Webauftrittes wird
häufig die Angabe der Page Views verwendet. Daneben lässt sich daraus die Last auf den Webserver ablesen, denn jeder Seitenaufruf muss von ihm verarbeitet werden.
Bei der Kapazitätsplanung einer Webanwendung spielt die zu erwartende Page View Zahl eine
zentrale Rolle. Im Idealfall muss eine Webanwendung mit dieser Kennzahl belastet werden. (Meier
2007, S. 94) Gleichzeitig wird die durchschnittliche Antwortzeit ermittelt und mit der geforderten
Antwortzeit verglichen. Diese Zahl kann natürlich nur angenommen werden und durch historische Daten gestützt werden. Stack Overflow soll auch hierfür als Vorbild dienen. Im September
2009 hatte der Dienst erstmals eine Million Page Views an einem Tag (quantcast 2012). Diese
Zahl soll den ungefähren Anhaltspunkt für Understandr darstellen. Eine Million Page Views pro
Tag entsprechen im Schnitt 12 Page Views pro Sekunde. Allerdings muss für einen Lasttest in
jedem Fall die Spitzenlast verwendet werden. Nur wenn eine Webanwendung unter Spitzenlast
eine gute Performance vorweisen kann, ist sie insgesamt als performant zu bezeichnen. (Joines et
al. 2003, S. 141) Im Idealfall ergibt sich der Wert für die Spitzenlast aus Erfahrungswerten. Da
diese nicht zur Verfügung stehen, wird an dieser Stelle auf eine allgemeine Quelle zurückgegriffen:
die Traffic-Statistik des German Commercial Internet Exchange (DE-CIX), einem der größten
Internet-Knoten der Welt. (www.de-cix.net 2012) In Abbildung 3.3 kann man deutlich ablesen,
dass der Spitzenwert (Peak) mehr als 50% über dem Durchschnittswert (Average) liegt. Daher
bietet es sich an, für den Lasttest von den angenommen 12 Page Views auf 20 zu erhöhen, um
damit einen Wert mit genügend Spielraum zu erhalten. Im Rahmen dieses Tests wird eine Pa-
24
KAPITEL 3. ANALYSE UND VORGEHEN
ge View mit einer HTTP-Anfrage gleichgesetzt. Eingebettete Dateien, wie CSS und JavaScript
Dateien werden nicht mit abgefragt, um das Szenario möglichst einfach zu halten. Außerdem
beinhaltet die Anwendung auch eingebettete Dateien von Drittanbietern, deren Antwortzeiten
nicht vorhersehbar ist. Daher entsprechen die geforderten 20 Page Views pro Sekunde auch einem
Durchsatz von 20 Anfragen pro Sekunde.
Eine weitere wichtige Kennzahl ist, wie vielen verschiedenen Nutzern diese Zugriffe generieren.
Stack Overflow hatte im September 2009 ungefähr 300.000 eindeutige Nutzer. Das entspricht
inklusive den 50% Peak-Aufschlag fast 6 Nutzer pro Sekunde. (quantcast 2012).
Abbildung 3.3: Traffic für 2 Tage des DE-CIX Internetknoten (de-cix.net, 03.07.2012)
3.5.4
Testdesign im Überblick
Das Testdesign besteht zunächst aus einer Testdatenbank, die sowohl im Umfang als auch in der
Verteilung einen realistischen Bezug aufweist. Daneben wurden Testanfragen entworfen, welche
der Nutzung der Anwendung in einem späteren produktiven Einsatz möglichst nahe kommen. In
Abbildung 3.4 ist die Verteilung der Daten in der Testdatenbank noch einmal illustriert und in
Abbildung 3.5 sind die Testanfragen dargestellt.
25
KAPITEL 3. ANALYSE UND VORGEHEN
Abbildung 3.4: Testdaten Übersicht
Abbildung 3.5: Testanfragen Übersicht
26
KAPITEL 3. ANALYSE UND VORGEHEN
3.6
3.6.1
Testumgebung
Software für die Messung
Für die Messung der Performance und Skalierbarkeit wird die Software JMeter eingesetzt. Die
Software gehört zum Apache Projekt und ist komplett in Java geschrieben. JMeter wurde entwickelt um Client-Server-Software, wie Webanwendungen, Lasttests zu unterziehen. Es unterstützt
verschiedenste Ressourcen, wie statische Webseiten, Java Applets, CGI-Skripte, Datenbanken,
FTP-Server und viele weitere. JMeter kann Adressen von Ressourcen automatisiert aufrufen und
darüber hinaus eine große Anzahl von gleichzeitigen Nutzern simulieren. Die Performance der
Anwendung kann dann unter dieser Last analysiert werden. (Apache 2012)
Abbildung 3.6: Screenshot JMeter mit Testplan
JMeter ist grundsätzlich in so genannten Thread-Gruppen organisiert. Jede Thread-Gruppe repräsentiert ein Verbund von virtuellen Nutzern, die einen bestimmtem Testfall ausführen. (Apache 2012) Ein Thread entspricht immer einem Nutzer. Einer solchen Gruppe können verschiedene
Steuerelemente hinzugefügt werden. Dazu zählen unter anderem logische Controller, wie Schleifen und Bedingungen, aber auch Zeitgeber, um die Abarbeitung der Nutzeraktionen zu takten.
Wichtigste Elemente sind aber die Sampler, mit deren Hilfe sich Anfragen an einen Server senden lassen. Verschiedenste gängige Protokolle stehen zu Auswahl: HTTP, FTP, SMTP, SOAP
und viele mehr. Zusätzlich lassen sich alle Aspekte einer solchen Anfrage simulieren. Im Falle von HTTP Anfragen zum Beispiel die Übergabe von POST- oder GET-Variablen. Um die
Ergebnisse der Lasttest zu überwachen, existieren verschiedene Listener, die unterschiedliche
Visualisierungsarten zur Verfügung stellen oder die Daten abspeichern.
27
KAPITEL 3. ANALYSE UND VORGEHEN
3.6.2
Datenbank befüllen
Um die Datenbank mit den geforderten Testdaten zu befüllen, existieren verschiedene Lösungsansätze. Es ist möglich die Webanwendung an sich zu verwenden. Ein synthetischer Nutzer kann
automatisch alle notwendigen Klicks durchführen und entsprechend häufig wiederholen, um die
notwendigen Datenmengen in der Datenbank zu erhalten. Daneben ist es möglich, die Datenbank
unmittelbar mit Daten zu füllen. Letztere Methode wird verwendet, um die Understandr Datenbank für den Test vorzubereiten, da die geforderten Datenmengen auf diesem Weg wesentlich
schneller angelegt werden können. Hierzu wurde eine CakePHP Konsolenanwendung entwickelt,
welche die geforderten Daten in die entsprechenden Tabellen schreibt (siehe Kapitel 6.6).
3.6.3
Testaufbau, Qualität und Messgrößen
Für den Lasttest werden die beiden Testserver (Web- und Datenbankserver) verwendet. Die
Anwendung wurde leicht modifiziert. Das Einloggen wurde vereinfacht und ist über das Aufrufen
einer bestimmten URL möglich, da die Nutzung des verwendeten Facebook-Logins aus JMeter
heraus nicht möglich ist. Darüber hinaus werden in der Sidebar nur noch die neuesten Statements
angezeigt, da die Implementierung der Statistikfunktionen noch nicht vollständig abgeschlossen
ist. Die Anwendung wird vor einem Test in einen Ausgangszustand versetzt, welcher folgende
Punkte erfüllt:
• Die Datenbank ist nur mit den Daten befüllt, die in Kapitel 3.5.4 aufgezeigt sind
• Die Server werden einmal neu gestartet
• Netzwerkverbindung und Netzwerkgeschwindigkeit werden durch das Hoch- und Herunterladen einer Referenzdatei überprüft
Performance und Skalierbarkeit werden in unterschiedlichen Testszenarien gemessen, da ansonsten die Anzahl an variablen Größen zu groß wird. An dieser Stelle muss erwähnt werden, dass
es sich bei allen Tests nur um synthetische Szenarien handelt, deren Aussagekraft entsprechend
gewertet werden muss. Hauptsächliches Ziel dieser Arbeit ist es, den relativen Leistungsunterschied zwischen zwei verschiedenen Implementierungen zu ermitteln. Auch wenn die gemessenen
Werte eine gewisse Aussagekraft bezüglich der absoluten Leistung der Anwendung haben, sollte
für eine diesbezügliche Aussage ein entsprechender Test entwickelt werden. Darüber hinaus unterliegt ein solcher Test gewissen Qualitätsschwankungen. Daher muss jeder Testlauf hinreichend
lange durchgeführt werden. Faktoren, die das Testergebnis beeinflussen können, sind in diesem
Fall hauptsächlich Schwankungen in der Netzwerk- und Internetleistung.
Als Messgrößen werden die beiden Kennzahlen Durchsatz und Antwortzeit dienen. Auf eine Messung der Verteilung der Ressourcenauslastung wird verzichtet, da es sich nicht um einen Stresstest
handelt und die Auslastung jeder Ressource nicht das jeweilige Maximum überschreiten soll. Eine
entsprechende Überwachung der Ressourcen während der Tests mit passenden Systemtools ist
angebracht.
28
KAPITEL 3. ANALYSE UND VORGEHEN
3.6.4
Test der Performance
Für den Performance-Test wird jeder in Kapitel 3.5.1 aufgeführte Use Case in JMeter abgebildet.
Dabei entspricht jeder Anwendungsfall einer Thread-Gruppe. Jede Thread-Gruppe wird mit den
notwendigen HTTP-Requests, verschiedenen Listenern und einem Zeitgeber für einen konstanten
Durchsatz versehen. Letzteres dient der Festlegung der Quantität der verschiedenen Use Cases.
Zum Beispiel soll in 70% der Zugriffe ein Statement angesehen werden. Der Durchsatz wird pro
Minute angegeben. Bei geforderten 20 Page Views pro Sekunde entspricht das 840 Zugriffen
pro Minute. Dieser Wert wird angegeben und JMeter versucht den gewünschten Durchsatz zu
erreichen. Zusätzlich lässt sich festlegen, wie viele Nutzer den jeweiligen Use Case gleichzeitig
ausführen. Um die Testszenarien möglichst übersichtlich zu halten, wird jede Thread-Gruppe
nur von einem Nutzer gleichzeitig ausgeführt. Das bedeutet, dass JMeter versucht die geforderte
Anzahl an Anfragen innerhalb einer Gruppe nacheinander auszuführen. Insgesamt handelt es sich
also um 6 Nutzer, da es 6 Use Cases sind. Sollte der geforderte Durchsatz erreicht werden und jede
Anfrage im Schnitt unter einer Sekunde in Anspruch nehmen, entspräche das den geforderten 6
eindeutigen Nutzern pro Sekunde.
Als Ergebnis erhält man dann die erzielte mittlere Antwortzeit für die jeweiligen Use Cases und
für den gesamten Test als aggregierten Wert. Auch wenn man den gewünschten Durchsatz bereits
vorgegeben hat, erhält man zusätzlich den tatsächlich erreichten Durchsatz.
3.6.5
Test der Skalierbarkeit
Für den Test der Skalierbarkeit wird auf die Unterteilung in verschiedene Use Cases verzichtet.
Konzept dieses Tests ist es, dass mehrere Nutzer gleichzeitig versuchen auf die Anwendung zuzugreifen. Die Anzahl der Nutzer wird dabei stetig erhöht, um eine erhöhte Last auf den Server
zu simulieren. Durchsatz und Antwortzeit werden parallel gemessen. Je nachdem in welchem
Maß der Durchsatz sinkt bzw. die Antwortzeit steigt, lässt sich die Skalierbarkeit einordnen. Ein
einzelner Use Case soll an dieser Stelle genügen, hauptsächlich um den JMeter-Client nicht zu
überlasten. Für jeden simulierten Thread wird ein neuer Java-Thread bereitgestellt mit entsprechendem Ressourcenverbrauch. Abgerufen werden die Statements mit den meisten Argumenten
und Stimmen.
3.6.6
Profiling
Als Profiling bezeichnet man das Erfassen von Informationen über die Abarbeitung von Quelltext
zur Laufzeit. Ein Profiler ermittelt an welchen Stellen der Software die meiste Zeit während der
Ausführung verbraucht wurde. Häufig wird angegeben, wie oft Funktionen ausgeführt wurden
und wie lange eine Ausführung dauerte. Auf diesem Weg lässt sich sehr schnell identifizieren,
welche Teile der Anwendung Flaschenhälse sind und optimiert werden sollten. (Henderson 2006,
S. 211-212)
Neben den Lasttests wird bei der Anwendung auch ein Profiling durchgeführt. Zum einen um
einwandfrei auszuschließen, dass es eventuell einen noch größeren Flaschenhals als die Datenbank
gibt. Zum anderen, um zusätzliche, langsame Funktionen zu identifizieren, welche sich gegebenenfalls durch die Erweiterung um eine neue Datenhaltungsebene ebenfalls beschleunigen lassen.
29
KAPITEL 3. ANALYSE UND VORGEHEN
Für die Durchführung des Profiling wird das von Facebook entwickelte Programm XHProf zum
Einsatz kommen. XHProf ist ein Profiler speziell für PHP. Installiert als PHP Extension liefert
er die Ergebnisse über ein webbasiertes Interface.
3.7
Integrations- und Unittests
Für die unproblematische Bewertung der Funktionalitäten und der Transparenz der Weiterentwicklung, soll der bestehende Zustand mit Hilfe von automatisierten Tests festgehalten werden.
Dafür werden zwei verschieden Umgebungen und Arten von Tests verwendet.
Integrationstests mit Selenium
Ein Integrationstest dient dazu, das Zusammenspiel von
verschiedenen Komponenten in einem Softwaresystem zu testen. In diesem Fall wird es sich um
die gesamte Anwendung, also die HTML-Seite als Frontend handeln. Dafür wird die Software
Selenium (www.seleniumhq.org) zum Einsatz kommen. Mit Selenium lässt sich die Nutzung einer
Webanwendung automatisieren und die Ergebnisse mit vorher festgelegten Annahmen vergleichen. Die Use Cases von Understandr sollen auf diesem Weg festgehalten werden. Die Erweiterung wird dann den gleichen Tests unterzogen und damit eine transparente Funktionalität der
Frontend-Seite gewährleisten.
Unittests mit PHPUnit Ein Unittest überprüft die korrekte Funktionsweise einer Einheit
eines Softwaresystems. In den meisten Fällen handelt es sich dabei um eine einzelne Klasse. Dabei
wird diese als isoliert betrachtet und im Idealfall werden Verbindungen zu anderen Einheiten
bzw. Klassen simuliert, um tatsächlich nur die Richtigkeit der einen Klasse zu bewerten. Ein
solcher Test ruft dann Methoden der Klasse auf und überprüft das Ergebnis wiederum mit
vorher festgelegten Annahmen. Die Arbeitsweise der wesentlichen Schnittstellen der bestehenden
Datenhaltungsschicht sollen auf diesem Weg festgehalten werden. Damit ist es später möglich,
die korrekte Arbeitsweise und die geforderte Transparenz sicherzustellen.
30
Kapitel 4
Analyse und Test des
Ist-Zustandes
4.1
Profiling
Für das Profiling wurde ein Statement mit vielen Argumenten (50) vom Server abgerufen, um
zu sehen welche Funktionen den meisten Anteil der Ausführungszeit beanspruchen. Insgesamt
hat die Ausführung ca. 460 Millisekunden in Anspruch genommen. Tabelle 7.1 zeigt die fünf
Funktionen mit dem größten Anteil.
Funktionsname
Anzahl Aufrufe
Zeit in ms
PDO::query
PDOStatement::execute
PlistaModel:: get@1
PlistaModel::getDataField
Understandr\Statement::getUserPosition
231
70
8.699
10.432
60
81
37
36
32
25
Anteil
an
Ausführungszeit in %
17,5
7,9
7,7
7,0
5,5
Tabelle 4.1: Ergebnis des Profiling des Ist-Zustandes
An oberster Stelle befindet sich zwei Funktionsaufrufe der PDO Klasse. Diese Klasse stellt die
Datenbankschnittstelle von PHP dar. Der Zugriff auf die Datenbank nimmt an dieser Stelle
schon über 25% der Gesamtzeit ein. Die nächsten Funktionen gehören zur PlistaModel Klasse
und geben Zugriff auf einzelne Datenfelder (Informationen zum PlistaModel in Kapitel 5.1). Die
letzte Funktion ist Teil der Berechnung der öffentlichen Meinung, welche indirekt ebenfalls in
Zusammenhang mit Datenbankoperationen steht (siehe Kapitel 5.2). Zusammengefasst bedeutet
das, dass die aufwändigsten Funktionsaufrufe mit der Datenhaltung zusammenhängen.
31
KAPITEL 4. ANALYSE UND TEST DES IST-ZUSTANDES
Use Case
Anzahl
Anfragen
1150
Gewünschter
Durchsatz in
Anfragen/s
120
Tatsächlicher
Durchsatz in
Anfragen/s
115
Durch. Antwortzeit
in
ms
258
Startseite aufrufen
Statement aufrufen
Suche
Statement anlegen
Argument angelegen
Stimme abgeben
Insgesamt
1079
840
108
550
860
240
120
24
86
24
644
435
360
36
36
283
597
60
60
310
4286
1200
429
428
Tabelle 4.2: Ergebnisse des Performance-Tests des Ist-Zustandes
4.2
Performance
In Tabelle 4.2 sind die Ergebnisse des Performance-Tests zu sehen. Der Test wurde wie in Kapitel
3.6.4 beschrieben durchgeführt und lief 10 Minuten. Auffällig ist sofort, dass der gewollte Durchsatz von 1200 Anfragen pro Sekunde nicht erreicht wurde. Das ist fast ausschließlich auf den sehr
niedrigen Durchsatz des Use Cases Statement aufrufen zurückzuführen. Dieser Fall konnte nur
ein Achtel des gewünschten Durchsatzes erreichen.
4.3
Skalierbarkeit
Für den Skalierungs-Test wurde die Anzahl an gleichzeitigen Nutzern langsam von 1 auf 40
erhöht. Die Zahl 40 ergab sich aus Testläufen um die Obergrenze an gleichzeitigen Nutzern
bezüglich Ressourcenauslastung zu ermitteln. Abbildung 4.1 zeigt den Verlauf der Antwortzeit
bei steigender Nutzerzahl. Die Kurve verläuft linear, die Antwortzeit steigt also linear zur Anzahl gleichzeitiger Nutzer. Die mittlere Antwortzeit liegt bei ungefähr 3300 ms. Bei mehr als 6
gleichzeitigen Nutzern steigt die Antwortzeit über eine Sekunde. Bei einer Wartezeit von mehr
als einer Sekunde kann man die Anwendung als schwer benutzbar bezeichnen.
Abbildung 4.2 zeigt den Durchsatz in Anfragen pro Sekunde bei steigender Nutzerzahl. Der
mittlere Durchsatz liegt dabei bei etwas über 6 Anfragen. Bei 7 Nutzern bricht der Durchsatz kurz
ein, dabei handelt es sich wahrscheinlich um eine zufällige Abweichung. Davon abgesehen, steigt
der Durchsatz bis 9 gleichzeitige Nutzer. Danach hält sich der Durchsatz auf einem konstanten
Wert.
Insgesamt skaliert die Anwendung fast überhaupt nicht, da die Leistung bei steigender Nutzerzahl
sich verschlechtert und nur bis zu einer kleinen Nutzerzahl im verwendbaren Bereich bleibt.
32
KAPITEL 4. ANALYSE UND TEST DES IST-ZUSTANDES
Abbildung 4.1: Anwortzeit gegenüber Anzahl gleichzeitiger Nutzer im Ist-Zustand
Abbildung 4.2: Durchsatz gegenüber Anzahl gleichzeitiger Nutzer im Ist-Zustand
33
KAPITEL 4. ANALYSE UND TEST DES IST-ZUSTANDES
4.4
Testfälle
In Anhang C.1 sind die erstellten PHPUnit-Testmethoden dargestellt. Es wurden für die wesentliche Datenhaltungsoperationen Tests erstellt, welche die Funktionsweise festhalten. Dabei
wird vor jedem Test eine leere Testdatenbank mit Testdaten befüllt. Die Testmethoden führen
anschließend Testoperationen durch. Zum Beispiel das Anlegen eines neuen Datensatzes und die
anschließende Überprüfung, ob dieser in der Datenbank auch vorhanden ist. Die Auswahl der
Methoden orientiert sich dabei an den Funktionen des PlistaModel, welches in Kapitel 5.1 näher
erläutert wird. Die Testfälle waren alle erfolgreich, was zu erwarten war, da sie an die vorhandenen Gegebenheiten angepasst wurden.
Anhang C.2 zeigt eine Übersicht der erstellten Testfälle für das Frontend. Die gängigsten Anwendungsfälle wurden festgehalten.
4.5
Beurteilung
Insgesamt sind die Werte für Performance und Skalierbarkeit weit unter den Anforderungen. Die
durchschnittliche Antwortzeit ist weit entfernt vom langfristigen Ziel von 50 ms und der geplante
Durchsatz konnte ebenfalls nicht erreicht werden. Darüber hinaus skaliert die Anwendung nur
unwesentlich. Allerdings hat das Profiling gezeigt, dass die Datenhaltung einen wesentlichen Teil
der Ausführungszeit beansprucht. Insofern ist eine Überarbeitung der Datenhaltung zunächst
der richtige Weg um die Werte zu verbessern. Inwieweit weitere Faktoren eine Rolle spielen, wird
sich nach den Tests der erweiterten Version zeigen.
34
Kapitel 5
Entwurf
Im folgenden Abschnitt wird der theoretische Entwurf der geforderten neuen Datenhaltungsebene
auf Basis einer Redis Datenbank diskutiert. Um dieses Ziel zu erreichen, werden die bestehende
Architektur und die zu verarbeitenden Daten analysiert, um einen optimalen Punkt und ein
geeignetes Datenmodell für die Erweiterung zu finden. Abbildung 5.1 zeigt noch einmal den
grundsätzlichen Aufbau einer CakePHP MVC Anwendung mit den drei wesentlichen Bestandteilen und dem CakePHP Dispatcher, der für die Wahl des passenden Controller zuständig ist.
(CakePHP 2012) Der folgende Entwurf konzentriert sich dabei hauptsächlich auf die ModelSchicht, welche für die Datenhaltung verantwortlich ist.
Abbildung 5.1: Grundsätzlicher Aufbau einer MVC-Anwendung (CakePHP 2012)
5.1
Das PlistaModel
Die plista GmbH verwendet für die eigene Softwareentwicklung eine selbst entwickelte Klassenbibliothek für Objekt-relationales Mapping. Die zentrale Klasse dieser Bibliothek heißt PlistaModel,
daher wird dieser Name im Folgenden stellvertretend für die gesamte Klassenbibliothek verwendet. Das PlistaModel wurde hauptsächlich 2009 entwickelt, da zu dieser Zeit gängige Lösungen
von Drittanbietern die gewünschten Anforderungen nicht erfüllen konnten. Das PlistaModel
ist spezialisiert für die Nutzung mit MySQL. Obwohl CakePHP über ein integriertes Objekt-
35
KAPITEL 5. ENTWURF
relationales Mapping verfügt, wird auch für die Entwicklung von Understandr die firmeninterne Komponente verwendet und ersetzt damit vollständig sämtliche Model-Funktionalitäten von
CakePHP. Das bedeutetet, dass alle Datenbankoperationen über das Interface des PlistaModel
durchgeführt werden. Die Erweiterung der Anwendung soll weitgehend transparent erfolgen. Daher bietet es sich zunächst an, die Datenhaltungsschicht genauer zu betrachten und zu bewerten,
inwieweit die gewünschten neuen Funktionalitäten ausschließlich an dieser Stelle eingeführt werden können. In jedem Fall wird für eine Änderung der Datenhaltung diese Schicht der Anwendung
Grundlage und wichtigster Ausgangspunkt sein. Abbildung 5.2 gibt in Form eines Klassendiagramms einen Überblick über die interne Struktur des PlistaModel. Dabei zeigt sie nur die
wichtigsten und für diesen Entwurf relevanten Methoden und Eigenschaften. Im Folgenden wird
die Funktions- und Einsatzweise des PlistaModel genauer erläutert.
Abbildung 5.2: Klassendiagramm der Plista Klassenbibliothek für Objekt-relationales Mapping
mit den wichtigsten Klassen und Methoden
Vererbung Für den Zugriff auf eine Datenbank-Tabelle, wird eine neue Klasse erstellt, welche
von der Klasse PlistaModel ableitet. Über geerbte Eigenschaften lassen sich Tabellenname,
Beziehungen zu anderen Models und Validierungen für die Daten konfigurieren. Anschließend ist die Klasse sofort einsatzbereit und ermöglicht eine direkte Interaktion mit der
entsprechenden Tabelle in der MySQL Datenbank.
Statische Finder Ein PlistaModel verfügt über verschiedene statische Methoden mit deren
Hilfe sich Datensätze aus der Tabelle abrufen lassen. Jede Methode dient einem speziellen
36
KAPITEL 5. ENTWURF
Einsatzzweck. Die find Methode ist dabei die vielfältigste Ausführung. Mit ihr lassen
sich komplexe Abfragen mit Konditionen und Sortierungen durchführen. Dabei sind die
Schlüsselwörter an SQL angelehnt.
PlistaModel :: find ( ’ all ’ , array (
’ order ’ = > ’ createdAt DESC ’ ,
’ conditions ’ = > ’ Id =2 ’ ,
));
Mit den Methoden findById und findBy lassen sich differenziertere Abfragen durchführen.
Die findById Methode fragt einen einzigen Datensatz anhand des Primärschlüssels ab
mit der findBy Methode lässt sich gezielt nach Konditionen abfragen. Alle Finder geben
entweder eine Sammlung von instanziierten Models in Form einer PlistaCollection oder bei
einem einzigen Datensatz eine Instanz eines PlistaModel zurück. Die statischen Methoden
dienen nur dem Zugriff von außen, da intern alle Methoden auf nicht statische Varianten
der Finder abgebildet werden. Die als Parameter übergebenen Konditionen werden von der
PlistaConditions Klasse geparst und in entsprechende MySQL Syntax umgewandelt.
Datensätze zählen Die statische Count Methode lässt sich mit ähnlichen Parametern wie die
Find-Methoden aufrufen. Allerdings liefert sie als Ergebnis die Anzahl der passenden Datensätze als Integer. Auch sie wird intern auf eine nicht statische Variante abgebildet.
Daten auslesen Für den Zugriff auf die einzelnen Datenfelder eines PlistaModel gibt es zwei
Varianten. Zum einen kann durch die Implementierung des ArrayAccess Interfaces über die
Array-Schreibweise (array[index]) zugegriffen werden. Alle Felder stehen aber auch als
Eigenschaften des Objektes zur Verfügung.
Daten speichern Manipulierte oder neu erstellte Daten eines Models existieren zunächst nur
innerhalb des Objektes. Durch den Aufruf der save Methode werden alle Daten in die
Tabelle geschrieben. Ein Aufruf der update Methode ändert nur die Daten des Objektes
und führt kein automatisches Speichern durch.
Assoziationen Die Beziehungen von Models zueinander, respektive die Relationen der Tabellen,
werden durch die Klasse PlistaAssociation abgebildet. Wird auf eine Eigenschaft eines
Models zugegriffen, welche als Beziehung konfiguriert wurde, erhält man als Rückgabewert
eine PlistaAssociation. Diese Klasse verfügt ebenfalls über Find, Count und Save Methoden,
mit deren Hilfe über Relationen definierte Daten gelesen und manipuliert werden können.
Das folgende Beispiel zeigt, wie zu einem Statement alle Argumente abgerufen werden.
In MySQL entspräche das einem Fremdschlüssel in der Argument-Tabelle, welcher auf die
Statement-Tabelle zeigt.
$arguments = $statement - > arguments - > find ( ’ all ’ );
Alle Methoden der PlistaModel Klassen wandeln die Anfragen in MySQL Befehle um, welche
dann mit Hilfe der PlistaQuery Klasse an die Datenbank weitergeleitet werden. Die gesamte
Funktionalität baut auf MySQL auf und die entsprechenden SQL-Befehle sind unmittelbar in
den Klassen verankert. Der Datenbankzugriff ist dementsprechend nicht abstrahiert und Erweiterungen erfordern einen direkten Eingriff in die interne Struktur.
37
KAPITEL 5. ENTWURF
5.2
Datenhaltung und Berechnungen
Neben den technischen Gegebenheiten der bisherigen Datenhaltung, spielen die Struktur der Daten und die Art und Weise ihrer Aufbereitung eine Rolle beim Entwurf einer neuen Datenschicht.
Abbildung 5.3 zeigt die zentralen Tabellen der Anwendung und ihre Beziehungen zueinander.
Nachfolgend werden die sechs Use Cases aus Kapitel 3.5.1 aus Sicht der Datenhaltung genauer
betrachtet.
Die schreibenden Anwendungsfälle, wie Statement und Argument erstellen, oder eine Stimme
abgeben, erzeugen zunächst nur jeweils einen neuen Datensatz in den entsprechenden Tabellen. Bei der Erstellung eines Statements werden optionale Schlagwörter abgespeichert und ihre
Beziehung zu dem Statement in einer Relationstabelle abgelegt. Insgesamt sind die Schreiboperationen relativ einfach und wenig umfangreich. Im Gegensatz dazu müssen bei den Leseoperationen komplexere Abfragen durchgeführt werden. Die hauptsächliche Ursache dafür liegt bei der
Berechnung der öffentlichen und persönlichen Meinung. Für die persönliche Meinung zu einem
Statement werden zunächst alle Argumente des Statements ermittelt für die ein Nutzer gestimmt
hat. In Abhängigkeit zu der Gesamtzahl der Stimmen dieser Argumente werden die Werte berechnet. Dieser Algorithmus erfordert Zugriffe und Verknüpfungen auf die Tabellen Statements,
Arguments, ArgmtVotes und Users. Für die Ermittlung der öffentlichen Meinung eines Statements müssen die Meinungen aller beteiligten Nutzer des Statements einbezogen werden, denn
die öffentliche Meinung ist der Mittelwert aller Nutzermeinungen. Die Verknüpfung der Tabellen
wird also entsprechend der Anzahl an beteiligten Nutzern mehrfach durchgeführt. Entscheidend
ist jetzt, dass diese durchaus aufwendige Berechnung in jedem Fall erfolgt, in dem Statements
aufgelistet werden. Die öffentliche Meinung wird als zentrale Information der Anwendung an allen Stellen mitgeführt. Dazu zählt der Aufruf der Startseite, welche die aktuellste Beiträge zeigt,
das Darstellen der Sidebar mit einer Auswahl an Statements und auch Suchergebnisse. Darüber
hinaus wird die Berechnung bei der Anzeige des Statements durchgeführt, bei der zusätzlich die
zugehörigen Argumente abgefragt werden. Außerdem wird auch bei jeglichen Aktionen, die eine
Änderung der Meinung verursachen, neu berechnet. Dazu zählen ein neues Argument anlegen
und eine Stimme abgeben.
Abbildung 5.3: Entity-Relationship-Modell des bestehenden MySQL-Implementierung
38
KAPITEL 5. ENTWURF
5.3
Verwendung von Redis
Die vorher beschriebenen Gegebenheiten sollen nun Beachtung beim Entwurf der Erweiterung
auf Basis einer Redis Datenbank finden. Dazu muss geklärt werden, welche Daten in welcher Form
gespeichert werden und an welcher Stelle dies innerhalb der bestehenden Architektur umgesetzt
wird.
Art des Einsatzes Die Leistungsfähigkeit einer Webanwendung kann durch den Einsatz eines Caches auf Serverseite erhöht werden. Dieses Konzept ist weit verbreitet und existiert in
vielfältigen Ausprägungen. Die Entwickler von Stack Overflow berichten, dass sie grundsätzlich
versuchen möglichst alle Inhalte zu cachen. (meta.stackoverflow.com 2010) Entsprechende Literatur zu der Thematik beschäftigt sich dabei häufig mit dem so genannten Proxy-Caching. In
Web Caching and its Applications (Nagaraj 2004, S. 3-16) beschreibt der Autor verschiedenste
Unterarten dieser Caching-Methode. Grundsätzlich werden dabei vor den eigentlichen Webserver ein oder mehrere Proxy-Server installiert, welche die HTTP-Anfragen aufzeichnen und ihre
Ergebnisse zwischenspeichern. (Nagaraj 2004, S. 3-12)
Das Ziel dieser Ausarbeitung ist, die bestehende Datenhaltung um eine sehr schnelle Key-Value
Datenbank zu erweitern. Es kann also bei diesem Vorgehen von einer Cache-Ebene gesprochen
werden, die wesentlich näher an der Anwendung selbst angesiedelt ist und gezielt Daten für den
häufigen Zugriff zwischenspeichert. Verschiedene Methoden, dies umzusetzen, sind denkbar.
Eine Möglichkeit wäre das Zwischenspeichern von ganzen HTML-Seiten. Zum Beispiel könnte
beim Aufruf der aufwendigen Statement-Ansicht, die vollständige HTML-Ausgabe in Redis gespeichert werden. Bei einer wiederholten Anfrage, wäre eine Neuerstellung nicht notwendig. Erst
mit einer Schreiboperation jeglicher Art auf die betreffenden Daten müsste der Cache erneuert
werden. Mit der Startseite oder anderen Ansichten könnte analog verfahren werden. Dieses Konzept birgt einige Nachteile. Die gespeicherten Daten wären speziell an eine Ansicht und einen
Zweck angepasst und könnten nicht an anderer Stelle verwendet werden. Dabei ist es durchaus gewollt die Statement-Metadaten überall schnell zur Verfügung zu stellen, zum Beispiel in
Statistiken. Außerdem wäre eine transparente Implementierung schwieriger, da sowohl die ViewSchicht, als auch die Model-Schicht involviert sind.
Eine weitere Möglichkeit ist, nur bestimmte Daten gezielt zwischenzuspeichern, die ansonsten
aufwendig abgerufen werden müssten. Zum Beispiel, welche die neusten Beiträge sind oder welche User für ein Statement abgestimmt haben. Zusätzlich könnten bereits berechnete Meinungen
zwischengespeichert werden und nur bei Datenänderungen neu berechnet werden. Besonders das
Speichern der Meinungen würde viel Arbeit vom Server nehmen. Nachteil dieses Ansatzes ist, dass
der MySQL-Server nur teilweise entlastet wird und die verschiedenen Speicheroperationen individuell den betreffenden Models hinzugefügt werden müssten. Bei einem Wachstum der Anwendung
und Einführung neuer Funktionen müssten eventuell viele Änderungen und Ergänzungen durchgeführt werden.
Eine dritte und hier favorisierte Möglichkeit kombiniert Teile der vorhergehenden Ideen. Die
Redis Cache-Ebene als generische, zusätzliche Datenschicht, die große Teile oder alle Daten automatisch in Redis mitspeichert. Bei einem lesenden Zugriff wird diese Schicht bevorzugt und
MySQL dient nur noch als Fallback-Ebene. Damit hätte man die Daten der Ansichten in der
Cache-Ebene, aber auch atomare Informationen wären verfügbar. Zusätzlich können gezielte,
39
KAPITEL 5. ENTWURF
häufig verwendete Informationen dem Model hinzugefügt werden und werden automatisch in
Redis abgelegt.
Transparente Integration
Die bestehende MVC-Architektur und die Anforderungen diktie-
ren prinzipiell bereits den genauen Ort der Implementierung. Die Implementierung der Datenhaltung gehört in die Model-Schicht und jeder Versuch Teile davon in einer der anderen Schichten zu
platzieren, würde das Prinzip verletzen. Darüber hinaus sollen alle Schnittstellen erhalten bleiben
und die Implementierung möglichst transparent erfolgen. Da der Controller sämtliche Datenoperationen über die Schnittstellen des PlistaModel ausführt, müssen diese bestehen bleiben. Im Falle
einer parallelen Implementierung der neuen Datenhaltung in einem zweiten Model, müssten in
allen Controllern Änderungen durchgeführt werden. Das wäre in keinem Fall zielführend. Auf
welche Art und Weise das Model modifizert wird, erläutert das nächste Kapitel.
5.4
Generische Cache-Ebene
Das PlistaModel ist unmittelbar mit MySQl verzahnt. Interne Methoden generieren teilweise
SQL-Syntax als Rückgabewerte und auch die Finder verarbeiten SQL Syntax. Es gibt keine einheitlichen Schnittstellen zum Speichern und Abrufen von Daten. Eine Erweiterung unterhalb des
Models ist daher nicht möglich. Die eigentliche Klasse soll natürlich auch nicht modifiziert werden. Funktionalitäten sollten immer gekapselt sein. Es bietet sich daher an, eine neue Klasse von
der Klasse PlistaModel abzuleiten und die Schnittstellen zu überschreiben, um auf diesem Weg
neue Funktionalitäten einzubinden. Eine überschriebene Methode kann immer die entsprechende
Methode der Elternklasse aufrufen. Dadurch ist der Fallback-Aspekt sichergestellt.
DataSource
Die enge Beziehung des PlistaModel zu MySQL macht die Klasse unflexibel und
im Idealfall versucht man ein Model unabhängig von der verwendeten Datenbank zu gestalten.
Beispielsweise bietet das Objekt-relationale Mapping von CakePHP die Möglichkeit, verschiedene
Datenbanken einzusetzen. Dazu wird eine Abstraktionsebene eingesetzt, die ausschließlich für den
Datenzugriff zuständig ist. Die gleiche Vorgehensweise wird bei der Cache-Ebene zum Einsatz
kommen. Die neuen Datenhaltungsfunktionen werden daher nicht unmittelbar in die abgeleitete Klasse implementiert, sondern in eine, nur für den Datenzugriff auf Redis verantwortliche
Klasse, ausgelagert. Andernfalls würde sich das Model noch mehr spezialisieren und unflexibel gegenüber späteren Anpassungen werden. Diese sogenannte DataSource wird ein CRUD-Interface1
implementieren und von der neuen Klasse über dieses Interface verwendet werden. Damit ist
die neue Datenhaltungsebene unabhängig vom eigentliche Mechanismus der Datenhaltung und
kann jederzeit ausgetauscht werden. Eine DataSource implementiert dann den konkreten Datenzugriff auf eine bestimmte Datenbank, was in diesem Fall Redis ist. Das UML-Diagramm
der DataSource-Klasse in Abbildung 5.4 zeigt diese Pflichtmethoden einer DataSource. Darüber
hinaus ist eine DataSource unabhängig von der Art des verwendeten Models. Sie darf Daten nur
in Form von reinen Arrays annehmen und gibt ebenfalls nur reine Arrays zurück. Dadurch ist
eine hohe Wiederverwendbarkeit gewährleistet.
1 CRUD
beschreibt grundlegende Datenbankoperationen: Create, Read, Update und Delete
40
KAPITEL 5. ENTWURF
PHPRedis und PlistaRedis
Der konkrete Datenbankzugriff der Redis-DataSource wird mit
1
der PHP-Erweiterung PHPRedis erfolgen. Diese Erweiterung bietet sämtliche Redis Kommandos über eine PHP Klasse an und gibt die Ergebnisse als Werte oder Array zurück. Die Software
ist im Umfeld des Unternehmens bereits im Einsatz und wird unmittelbar in der Klasse PlistaRedis verwendet. Diese Klasse erweitert die Funktionalität von PHPRedis unter anderem um
die Möglichkeit des Consistent Hashing. An der Klasse können mehrere Server angemeldet werden und die Klasse übernimmt die komplette Zuteilung von Schlüsseln auf den Hashing-Ring.
Durch den Einsatz der PlistaRedis Klasse ist die sofortige Nutzung von Consistent Hashing somit
sichergestellt.
Die neue Model-Klasse Die neue, vom PlistaModel abgeleitete Klasse, dient nur noch als Adapter2 zwischen den ursprünglichen Methoden der Elternklasse und den neuen CRUD-Methoden
der Redis-DataSource. Ihre Aufgabe ist, übergebene Parameter zu interpretieren und in das
von der DataSource unterstützte Format zu konvertieren. Dann wird die entsprechende CRUDMethode aufgerufen. Eine DataSource kann eine Exception werfen, wenn sie die Anfrage nicht
bearbeiten kann oder bestimmte Optionen nicht unterstützt werden. Die Modelklasse kann diese
fangen und dann die Anfrage an die Elternklasse weiterleiten. Zusätzlich definiert die Klasse
einige zusätzliche Callback-Methoden, die dem Nutzer die Möglichkeit geben, Datenhaltungsoperationen gezielt zu manipulieren. Beispielsweise eine Methode, die vor dem Speichern in die
DataSource aufgerufen wird. Siehe dazu Klassendiagramm der Modelklasse in Abbildung 5.4.
Assoziationen
In Abbildung 5.4 wird zusätzlich eine neue Association-Klasse definiert. Das
ist notwendig, da die Methoden der PlistaAssociation-Klasse ebenfalls an die neue DataSource
angepasst werden müssen. Die Implementierung verhält sich analog zu der Implementierung der
Modelklasse. Die neue Redis DataSource wird N-N-Beziehungen nicht generisch unterstützen.
Dafür gibt es zwei Gründe. Zum einen, taucht bei der Beispielanwendung, eine solche Beziehung nur einmal auf und das auch bei einer weniger kritischen Funktion, der Speicherung von
Schlagwörtern. Zum anderen, soll nicht versucht werden, alle Funktionen eines relationalen Datenbanksystems in Redis abzubilden, da dadurch die Einfachheit verloren und die Key-ValueDatenbank nicht im eigentlichen Sinne verwendet wird. Im konkreten Anwendungsfall kann die
Funktionalität natürlich durch den Einsatz der Callback-Methoden erreicht werden.
5.5
Redis-Datenmodell
Nach dem die strukturellen Rahmenbedingungen für die neue Datenquelle festgesetzt wurden,
wird nun festgelegt in welcher Form die Daten in Redis abgelegt werden. Lässt man die Relationen, in denen die Daten zueinander stehen zunächst einmal außer Betracht, bietet Redis für das
Ablegen von tabellarischen Daten gute Möglichkeiten. Eine Zeile kann ohne weiteres in einem
Hash abgelegt werden und ist damit in der Redis Datenbank vollständig abgebildet. Die Schlüssel
1 https://github.com/nicolasff/phpredis/
2 Unter Adapter versteht man ein Entwurfsmuster, bei dem die Schnittstelle einer Klasse in die Schnittstelle
einer anderen Klasse konvertiert wird. (Freeman et al. 2004, S. 243)
41
KAPITEL 5. ENTWURF
des Hashes sind die ehemaligen Spaltennamen und die Werte die Zellenwerte. Der Schlüssel des
Hash enthält dann noch den Primärschlüssel und jeder Datensatz ist sofort auffindbar.
statement :[ id ] = hash (
statement = ’ hallo ’ ,
createdAt = ’ 2012 -08 -01 14:14 ’
...... )
Prinzipiell würden man mit dieser Methode sämtliche Daten in Redis ablegen können, denn eine
Datenbank besteht lediglich aus Zeilen in Tabellen. Allerdings existieren noch gravierende Nachteile. Die Datensätze können nur anhand des Primärschlüssels abgerufen werden. Eine Abfrage
über Konditionen auf andere Werte des Datensatzes ist nicht möglich. Redis kann nur Abfragen
über die Schlüssel durchführen. Außerdem lassen sich die Datensätze bisher nicht nach dem Wert
einer Spalte darstellen.
Datensätze sortieren
Um die Datensätze sortiert ausgeben zu können bietet Redis den Befehl
SORT. Mit diesem Befehl lässt sich ein Set, ein Sorted Set oder eine Liste sortieren. Allerdings ist
es auch möglich nach einem externen Schlüssel über ein Schlüsselmuster zu sortieren. Hat man
nun ein Set mit allen Primärschlüsseln (ID) und die zugehörigen Daten in Hashes mit Schlüssel
die diese ID enthalten, lässt sich das Set anhand eines Wertes des Hashfeldes sortieren. Konkret
bedeutet das, es ist notwendig neben der Speicherung der Zeilen, die Primärschlüssel in einem
zusätzlichen Set mitzuführen.
statements : index = set (1 ,2 ,34 ,45 ,67 , ...)
Zusätzlich bietet die Funktion auch die Möglichkeit das Set zu limitieren und einen Startwert
anzugeben analog zu den MySQL Attributen LIMIT und OFFSET.
Konditionen
Wie bereits erwähnt ist eine Abfrage in Redis nur nach Schlüsseln möglich.
Möchte man Abfragen nach Konditionen durchführen, muss man diese Information in einer
passenden Form in Schlüsseln ablegen. Der Autor ist der Meinung, dass das der bedeutendste
Unterschied in der Handhabung zwischen Key-Value-Datenbank und relationaler Datenbank ist.
Bei der Verwendung von Redis ist man in jedem Fall gezwungen vor dem Schreiben der Daten festzulegen, nach welchen Informationen man später sucht. Im Gegensatz dazu, können bei
einer relationalen Datenbank alle Daten im Nachhinein beliebig aggregiert werden. Praktisch
bedeutet das, dass Sets von Primärschlüsseln gepflegt werden müssen, deren Schlüsselnamen die
Konditionen enthalten.
statements : BY : user :[ id ] = set (4 ,7 ,8 ,12 ,34 ...)
Für jede Kondition muss es ein eigenes Set geben. Über die Werte des Sets lassen sich dann die
einzelnen Datensätze abrufen. Darüber hinaus kann die SORT Funktion verwendet werden, um
die Ausgabe zu sortieren.
Konfiguration
Folglich ist festzuhalten, dass die Nutzung einer Key-Value-Datenbank nach
mehr Konfiguration der zu speichernden Daten verlangt. Daher soll die bisherige Konfiguration
42
KAPITEL 5. ENTWURF
über Klasseneigenschaften überdacht werden. Diese Art der Festlegung von Konfigurationen
wird bei größeren Mengen von Daten schnell unübersichtlich, da entweder mit vielen Variablen
oder mit mehrdimensionalen Arrays gearbeitet werden muss. Aus diesem Grund wird bei der
Konfiguration der Cache-Ebene eine zentrale XML-Datei zum Einsatz kommen. In dieser werden
Schlüsselname, Indizes, Konditionen und mehr festgelegt. Über den in PHP verfügbaren XMLLeser SimpleXMLElement lassen sich die Informationen unkompliziert auslesen. Zusätzlich bietet
ein XML-Dokument die Möglichkeit, Konfigurationen mit einem XML-Schema auf Richtigkeit
zu prüfen.
5.6
Denormalisierung
Das Profiling aus Kapitel 4.1 und die Analyse der Datenhaltung in Kapitel 5.2 haben gezeigt, dass viele Datenzugriffe von unmittelbaren Berechnungen verursacht werden. Dazu zählt
hauptsächlich die Berechnung der öffentlichen Meinung, aber auch die Ermittlung der Anzahl
von Pro- und Contra-Argumenten oder Stimmen für ein Argument. Daher bietet es sich an, bei
der Einführung einer zusätzlichen Datenhaltungsebene, an dieser Stelle zusätzliche denormalisierte Daten vorzuhalten. So wird die öffentliche Meinung eines Statement als reiner Wert dem
Redis-Model hinzugefügt. Sollte eine Aktion den Wert ändern, wird eine Neuberechnung durchgeführt. Analog dazu wird die Anzahl der Stimmen für ein Argument in dem Fall erhöht, wenn
eine neue Stimme abgeben wird. Eine weitere Möglichkeit ist, die Speicherung des Nutzernamens
als Klartext, anstatt eines Verweis auf diesen über die Nutzer-ID.
Die Anwendung wird nicht nur durch die schnellere Datenbank, sondern auch durch diese Methode beschleunigt werden. Natürlich besteht bei einer Denormalisierung immer die Gefahr, dass
die Daten inkonsistent werden. Auch Änderungen werden aufwendiger, da dieselben Informationen an verschieden Stellen abgelegt sind. Im Fall einer einfachen Webanwendung ohne kritische
Daten und größerer Relevanz ist dieser Punkt allerdings zu vernachlässigen. Sollte ein Zähler
zu einem Zeitpunkt inkorrekt sein, ist das ohne Weiteres hinzunehmen. Außerdem bietet die
normalisierte MySQL-Ebene die Möglichkeit, ihre Daten mit der Cache-Ebene abzugleichen und
eventuelle Inkonsistenzen zu beseitigen.
5.7
Sonderfall Suche
Eine Sonderstellung in Bezug auf Redis nimmt die Suchfunktion ein. Bekanntlich ist es bei Redis
nicht möglich nach Werten abzufragen. Zur Realisierung einer Suche, müssten alle Begriffe nach
denen gesucht wird, in den Schlüsseln stehen. Zum Beispiel müsste eine Statement in seine
einzelnen Wörter zerlegt werden. Für jedes Wort wird dann hinterlegt, bei welchem Statement
es vorkam. Mit dieser Methode würde man Rechenzeit und viele tausende Schlüssel verbrauchen.
Man kann daher festhalten, dass Redis nicht geeignet ist, eine Suchfunktion bereitzustellen. Daher
wird diese Funktionalität weiterhin von MySQL übernommen.
43
KAPITEL 5. ENTWURF
Abbildung 5.4: Klassendesign der Redis Cache Ebene
44
Kapitel 6
Implementierung
Abbildung 5.4 zeigt das Klassendiagramm der Redis Cache-Ebene. Diese Klassen wurde vollständig implementiert. Die folgenden Abschnitte dokumentieren die konkrete Nutzung und Funktionsweise. Zusätzlich werden Probleme, die sich bei der Implementierung ergeben haben, aufgezeigt.
6.1
Cache-Ebene verwenden
Wie geplant, lässt sich die neue Cache-Ebene einsetzen, indem die konkreten Models statt vom
PlistaModel vom neuen Model ableiten. Zusätzlich sind zwei weitere Schritte notwendig. Zum
einen muss der Redis DataSource einmalig eine PHPRedis Instanz übergeben werden. Das geschieht über den Aufruf einer statischen Methode der DataSource. Es ist möglich sowohl eine
reine PHPRedis oder eine PlistaRedis Instanz zu übergeben. Zum anderen muss ebenfalls über
eine statische Methode der Pfad zur Konfigurationsdatei im XML-Format übergeben werden.
Alle Models werden in einer Datei konfiguriert. Anhang B zeigt eine solche XML-Datei. Tabelle
6.1 zeigt die notwendigen Elemente.
Element
key
primarykey
Bedeutung
Legt den Prefix aller Schlüssel des Models fest
Legt fest, welches Feld des Daten-Arrays den
Primärschlüssel darstellt
Wenn true, wird der Index aller Einträge mitgeführt
Wenn true, werden die Daten eines Models
abgespeichert
Legt alle Konditionen fest, welche mitgespeichert werden
index
entity
conditions
Tabelle 6.1: Elemente einer XML-Konfigurationsdatei der Redis DataSource
Zusätzliche Funktionalitäten müssen manuell in den Callback-Methoden definiert werden.
45
KAPITEL 6. IMPLEMENTIERUNG
6.2
Datenverarbeitung im Detail
Hat man eine Model für die Nutzung der Cache-Ebene konfiguriert, läuft das Lesen und Schreiben
von Daten wie im folgenden beschrieben ab.
Schreiben von Daten Einen neuen Eintrag erhält man wie bisher durch das Erstellen einer
neuen Instanz und der Übergabe eines Arrays mit den Daten. Danach muss nur doch die
Save-Methode aufgerufen werden. Diese Methode ruft dann zunächst die Save-Methode
der Elternklasse auf, dadurch werden die Daten in MySQL gespeichert. Zusätzlich werden
eventuell konfigurierte Validierungen von der Elternklasse durchgeführt. Ist das Speichern
erfolgreich, wird die Create-Methode der DataSource aufgerufen. In diesem Fall wurde beim
Model eine Instanz der Redis DataSource instanziiert. Die DataSource stellt anhand der
Konfigurationsdatei fest, welche Daten gespeichert werden sollen und führt die entsprechenden Operationen durch. Soll ein Index mitgeführt werden, wird das entsprechende Set um
den Wert ergänzt und soll die Entität abgespeichert werden, wird ein entsprechender Hash
in Redis abgelegt. Eventuelle Konditionen werden ebenfalls ausgelesen und abgespeichert.
Die Schlüssel werden dabei über Methoden der Utilities-Klasse (siehe Abbildung 5.4) gebildet, damit deren Strukturen austauschbar sind. Entsprechende Callback-Methoden werden
im Zuge des Speicherns ebenfalls aufgerufen.
Lesen von Daten Für das Lesen von Daten wird ein passender Finder am Model aufgerufen. Das neue Model ruft dann zunächst eine Methode auf, welche die Parameter des
PlistaModel in ein, für eine DataSource kompatibles Format umwandelt. Danach wird die
Read-Methode der DataSource mit den kompatiblen Parametern aufgerufen. Folgender
Find-Aufruf zeigt alle bisher möglichen Parameter:
Statement :: find ( ’ all ’ , array (
’ order ’ = > ’ createdAt ’
’ limit ’ = > 5 ,
’ offset ’ = > 20 ,
’ index ’ = > ’ statements : mostrecent ’ ,
’ conditions ’ = > array (
’ userId ’ = > 4 ,
),
));
Die Redis DataSource unterstützt genau diese Parameter in dieser Form. Optionen können
weggelassen werden. Anders als beim PlistaModel müssen Konditionen als Array übergeben
werden. Im nächsten Schritt überprüft die DataSource, ob Abfragen mit den übergebenen
Optionen von Redis beantwortet werden können. Zum Beispiel ist eine Abfrage mit Konditionen, die nicht konfiguriert wurden, nicht möglich. Sind die Optionen nicht verfügbar
wird eine Exception geworfen und das Model gibt die Abfrage an die Elternklasse weiter.
Passen die Optionen werden die Daten aus Redis geholt und als Array zurückgegeben. Das
Model muss das reine Array dann abschließend in eine PlistaCollection umwandeln.
Ändern, Löschen und Zählen von Daten Alle weiteren Operationen verlaufen analog zum
Lesen von Daten. Beim Zählen wird ein passender Index ermittelt und dann mit ei46
KAPITEL 6. IMPLEMENTIERUNG
ner entsprechenden Redis Methode die Anzahl von Elementen im Index bestimmt und
zurückgegeben. Beim Ändern von Daten werden die alten Daten in Redis einfach durch
die neuen ersetzt und eventuell veraltete Konditionen entfernt. Das Löschen von Daten
ist exakt die umgekehrte Operation zum Schreiben von Daten. Es wird sowohl in MySQL
gelöscht, als auch in Redis. Dabei werden alle Einträge in Indizes mit entfernt.
6.3
Die Models im Detail
Die Models, z.b. das Statement-Model, nutzen hauptsächlich die generisch angebotenen Funktionen der Erweiterung. Einige zusätzliche Funktionen wurden mit Hilfe der Callback-Methoden
ergänzt. Hauptsächlich handelt es sich dabei um die zusätzlichen Daten, die durch die Denormalisierung entstanden sind. Zum Beispiel wird bei einem Argument vor dem Speichern eine
zusätzliches Feld countVotes angelegt, welche die Anzahl an Stimmen erhöht. Wird nun eine
neue Stimme über das ArgmtVotes-Model abgeben, wird dort ebenfalls in einer Callback-Methode
das entsprechende Feld des zugehörigen Arguments erhöht. Auch das Schlagwortsystem wurde manuell ergänzt. Die Schlagwörter werden denormalisiert, unmittelbar im JSON-Format im
Statement-Hash abgelegt und können somit in der Statement-Ansicht unmittelbar ausgegeben
werden. Weitere Daten werden auf diese Weise gepflegt.
6.4
Transparenz
Eine Anforderung war, dass die Erweiterung transparent sein soll und beim Datenzugriff keine
großen Änderungen erfolgen. Es wurden fast alle Schnittstellen des ursprünglichen Models umgesetzt und für die Nutzung der Redis Erweiterung nutzbar gemacht. Einige wenige Ausnahmen
existieren. Zum Beispiel wurde der Finder findBy noch nicht implementiert, da seine Funktionalität auch durch ein find erreicht werden kann. Außerdem sind die möglichen Übergabeparameter
der Finder etwas eingeschränkter. Die bisherige Möglichkeit unmittelbar SQL Syntax zu verwenden, entfällt bei Nutzung von Redis, um dadurch ein allgemeingültiges Format zu erreichen.
Dieses Vorgehen wird vom Autor als einen Schritt angesehen, die vorliegende Software robuster
und besser wartbar zu gestalten. Folglich mussten dadurch einige bestehende Finder-Aufrufe angepasst werden. Um die Performance der ursprünglichen Fassung zu erhöhen, wurden teilweise
unmittelbar SQL-Abfragen verwendet und das PlistaModel an dieser Stelle umgangen. Durch die
schnelle Redis Datenbank ist das an vielen Stellen überflüssig und die Abfragen konnten durch
reine Model-Methoden ersetzt werden. Im Prinzip wurde dadurch ein Teil der Transparenz sogar
wiederhergestellt. Insgesamt kann festgehalten werden, dass die geforderte Transparenz erreicht
wurde. Der Lauf der Unit- und Integrationstests wird endgültige Ergebnisse liefern.
6.5
Probleme und Schwierigkeiten
Im Großen und Ganzen gab es bei der Implementierung keine schwerwiegenden Probleme. Eine
große Schwierigkeit lag bei der Analyse der bestehenden Funktionalität. Das PlistaModel verwendet häufig keine festen Parameterlisten bei der Definition von Methoden, sondern macht sich
47
KAPITEL 6. IMPLEMENTIERUNG
die Möglichkeit von PHP zu Nutze, die Anzahl und den Typ von Übergabeparametern komplett
dynamisch zu gestalten. Daher war es notwendig, den gesamten Quelltext zu analysieren, um sich
über alle Möglichkeiten klar zu werden. Mögliche Rückgabewerte waren oftmals ebenso schwer
zu erkennen, da auch an dieser Stelle PHP sehr dynamisch gehalten ist.
Ein Problem tauchte auf, als bei ersten Performance Tests festgestellt wurde, dass die Nutzung
der Redis SORT Funktion bei sehr großen Indizes unzumutbar langsam wurde. Die Startseite zeigt
beispielsweise die aktuellsten Statements an, wofür der komplette Index verwendet wurde. Als
Reaktion darauf wurde zum einen die Nutzung des Index ebenfalls optional und die Übergabe
eines eigenen Index an die Find-Methode eingeführt. Dadurch ist es möglich eigene Indizes in
Form von Sets oder Lists mit Hilfe der Callback-Methoden zu pflegen. Die aktuellsten Statements
werden nun in einer FIFO-Liste geführt.
6.6
Weitere Implementierungen
Neben der eigentlichen Erweiterung wurde im Rahmen dieser Arbeit noch weitere Software entwickelt und auch administrative Aufgaben durchgeführt.
Unittests Die Entwicklung der Unittests zum Zweck die bestehende Funktionalität festzuhalten
und das spätere Ergebnis zu testen gehört ebenfalls zu den Aufgaben der Implementierung.
Die Schnittstellen und ihre Parameter müssen identifiziert werden und in geeigneter Art
getestet werden. Dazu zählt im Idealfall eine zusätzliche, leere Datenbank als Ausgangsvoraussetzung und das Einbinden der Bibliotheken der Anwendung in die Testumgebung.
Innerhalb einer Testmethode werden dann zunächst die Ausgangsvoraussetzungen hergestellt. Beim Test eines Datenmodels beinhaltet das fast immer das Erstellen von Testdaten
in der Datenbank. Erst danach kann die eigentliche Methode ausgeführt und das Ergebnis
ausgewertet werden. Abschließend müssen die Testdaten wieder gelöscht werden um die
gleichen Ausgangsvoraussetzungen wieder herzustellen.
Zusätzlich zu den Unittests für die bereits existierenden Model-Klassen, wurden für ausgewählte Klassen und Methoden der Erweiterung Unittests entwickelt. Insbesondere die
Methoden der Redis DataSource wurden auf ihre korrekte Arbeitsweise getestet. Anhang
C.3 zeigt eine Übersicht der Tests.
Testdaten-Script Um die Datenbank mit Testdaten zu befüllen wurde mit Hilfe des CakePHP
Framework eine Konsolenanwendung entwickelt. Die Anwendung ist Teil des Understandr
Quelltextes und somit auf allen Testservern verfügbar. Der Nutzer kann die gewünschte Anzahl an Statements, Nutzern und Schlagwörtern angeben. Die Anzahl der Argumente und
Stimmen ergibt sich dann entsprechend der in der Analysephase bestimmten Verhältnisse.
Die Anwendung benutzt für das Schreiben der Daten die Models der Anwendung. Auf diesem Weg war die Anwendung nach der Implementierung der Erweiterung in der Lage, die
Daten auch in die Redis Datenbank zu schreiben. Neben dem Erstellen der Testdaten ist es
möglich, zu ermitteln, welche die Statements mit den meisten Argumenten sind, um diese
für die Lasttests zu verwenden.
Server aufsetzen Neben der Entwicklung gehörte auch das Aufsetzen und Pflegen der nötigen
Software auf den Testservern zu den Aufgaben dieser Ausarbeitung. Auf dem Webserver
48
KAPITEL 6. IMPLEMENTIERUNG
musste die Anwendung installiert und das System entsprechend konfiguriert werden. Über
die Versionsverwaltungssoftware Git und den Hostingdienst Github wurde immer die aktuellste Version der Software auf dem Server veröffentlicht. Auch der Datenbankserver mit
MySQL und Redis musste installiert werden und die Schnappschüsse der Datenbank gesichert und vor den Lasttests wiederhergestellt werden. Zusätzlich war es während allen
Lasttests notwendig, die Server zu überwachen, um eine Überlastung der Systemressourcen
zu vermeiden.
49
Kapitel 7
Analyse und Test der neuen
Version
Die folgenden Abschnitte zeigen die Ergebnisse der Analyse der erweiterten Version der Anwendung. Die Analyse verläuft analog zu der des Ist-Zustandes.
7.1
Profiling
Es wurde wiederum ein Statement mit 50 Argumenten abgerufen. Die gesamte Ausführungszeit
beträgt nur noch ca. 140 Millisekunden und beträgt dabei nur ein Viertel der alten Variante.
Tabelle 7.1 zeigt die genauen Ergebnisse. Die aufwändigsten fünf Funktionsaufrufe haben sich
vollständig geändert. Immer noch am aufwändigsten ist trotzdem der Datenbankzugriff, bei dem
die absolute Zeit aber deutlich gefallen ist. Die weiteren Funktionen sind nicht weiter einzuordnen.
Es handelt sich um interne Funktionen des CakePHP Frameworks.
Funktionsname
Anzahl Aufrufe
Zeit in ms
Anteil
an
Ausführungszeit
in %
Redis::hGetAll
56
15
11,0
I18n::translate
705
11
8,2
ObjectCollection::trigger
125
11
7,9
CakeRoute::match
236
5
3,9
call user func array
1.366
4
3,0
Tabelle 7.1: Ergebnis des Profiling mit Redis-Cache
7.2
Performance
Tabelle 7.2 zeigt die neuen Ergebnisse des Performance-Tests. Der Durchsatz ist insgesamt leicht
gestiegen und die durchschnittliche Antwortzeit ist leicht gesunken. Dabei haben sich im Detail
50
KAPITEL 7. ANALYSE UND TEST DER NEUEN VERSION
Use Case
Anzahl
Anfragen
1150
Gewünschter
Durchsatz in
Anfragen/s
120
Tatsächlicher
Durchsatz in
Anfragen/s
120
Durch. Antwortzeit
in
ms
182
Startseite aufrufen
Statement aufrufen
Suche
Statement anlegen
Argument angelegen
Stimme abgeben
Insgesamt
1079
840
233
252
860
240
120
24
44
24
1321
271
360
36
36
277
597
60
60
284
4286
1200
516
332
Tabelle 7.2: Ergebnisse des Performance-Tests mit Redis-Cache
nur zwei Use Case verändert. Die Performance vom Aufruf der Statements hat sich stark gesteigert. Der Durchsatz hat sich mehr als verdoppelt womit sich die mittlere Antwortzeit mehr als
halbiert. Kurioserweise ist der Durchsatz der Suche in der neuen Version gesunken. Insgesamt
kann festgehalten werden, dass die Performance nur leicht gestiegen ist.
7.3
Skalierbarkeit
Abbildung 7.1 zeigt den Verlauf der Antwortzeit sowohl für die neue Version als auch für die
alte Fassung. Prinzipiell sehen sich die Kurven sehr ähnlich. Es ist wieder ein linearer Anstieg
festzustellen. Allerdings ist der Anstieg deutlich geringer. Die mittlere Antwortzeit liegt bei 1700
ms und hat sich damit halbiert. Der geringere Anstieg zeigt, dass die Leistung bei höherer
Nutzerzahl weniger einbricht. Das System skaliert dementsprechend etwas mehr als vorher. Auch
der Vergleich des Durchsatzes in Abbildung 7.2 zeigt ähnliche Kurven. Allerdings ist der mittlere
Durchsatz doppelt so hoch. Auch hält die Phase, in welcher der Durchsatz steigt, etwas länger
an. Das System kann mit steigender Nutzerzahl etwas besser umgehen.
51
KAPITEL 7. ANALYSE UND TEST DER NEUEN VERSION
Abbildung 7.1: Anwortzeit gegenüber Anzahl gleichzeitiger Nutzer im Vergleich zwischen alter
und neuer Version
Abbildung 7.2: Durchsatz gegenüber Anzahl gleichzeitiger Nutzer im Vergleich zwischen alter
und neuer Version
52
KAPITEL 7. ANALYSE UND TEST DER NEUEN VERSION
7.4
Testfälle
Die in Anhang C.1 aufgeführten Tests wurden mit der neuen Fassung durchgeführt. Das Ergebnis war insgesamt sehr erfolgreich. Einige verwendete Optionen der Finder werden in der neuen
Fassung nicht mehr unterstützt, daher mussten diese Testfälle minimal angepasst werden.
Die Selenenium-Tests (siehe Anhang C.2) wurden ebenfalls mir der erweiterten Fassung durchgeführt. Dabei traten einige Fehler auf. Dadurch konnten kleinere Bugs in der Implementierung
entdeckt und beseitigt werden. Anschließend lief der Test ohne Fehler ab.
7.5
Beurteilung
Die reinen Zahlen der Tests zeigen zwar eine relative Steigerung der Kennzahlen, allerdings
erfüllen die Ergebnisse in diesem Testszenario die Anforderungen noch nicht. Die Performance
ist mit einer mittleren Antwortzeit von ca. 330 ms noch nicht zufriedenstellend, angesichts des
langfristigen Ziels von 50 ms. Auch ist der Anstieg der Kurve in Abbildung 7.2 noch zu steil,
obwohl die Verbesserung zur alten Version sehr deutlich ist. Es ist an dieser Stelle aber festzuhalten, dass die Testumgebung aus relativ schwachen Servern bestand. Beide Server verfügen
nur über einen Prozessorkern und der Webserver hat mit 1 GB sehr wenig Arbeitsspeicher. Mit
zeitgemäßen Rechnern würde die Leistung der Anwendung mit Sicherheit deutlich steigen.
Allerdings ist durch die neue Infrastruktur nun ein horizontales Skalieren unkompliziert möglich.
Die Anzahl an Webservern kann ohne Eingriffe in die Software erhöht werden und die RedisDatenbank lässt sich mit Hashing oder Consistent Hashing nun ebenfalls skalieren. Dadurch
kann die Hardware auf eine Weise angepasst werden, dass es möglich ist die Anforderungen an
Performance und Skalierbarkeit zu erfüllen. Die anfängliche gestellten Anforderungen wurden damit erfüllt (siehe Tabelle 3.2). Performance und Skalierbarkeit wurden gesteigert, eine horizontale
Skalierung ist einfach umzusetzen und die Erweiterung ist weitgehend transparent erfolgt.
Selbstverständlich ist es notwendig die tatsächlichen Leistungsziele in einer weiteren Testumgebung zu evaluieren. Siehe dazu Kapitel 8.3. Zusätzlich muss genauer untersucht werden, warum
der Durchsatz der Suche gesunken ist, um eventuelle Fehler in der Implementierung auszuschließen.
53
Kapitel 8
Zusammenfassung und Ergebnis
8.1
Zusammenfassung
Aufgabe dieser Arbeit war es evaluieren, ob und in welchem Maße die Performance und Skalierbarkeit einer Webanwendung unter Einsatz einer Redis Datenbank gesteigert werden kann. Für
diesen Zweck wurde eine bestehende, im Vorfeld vom Autor entwickelte Web 2.0-Anwendung,
hinsichtlich dieser beiden Größen bewertet und ihr diesbezüglicher Zustand festgehalten. Im Anschluss wurde die, auf einer MySQL Datenbank basierende, Anwendung um eine zusätzliche Datenhaltungsschicht auf Basis der Key-Value-Datenbank Redis erweitert. Die zusätzliche Schicht
wurde dabei transparent der ursprünglichen Datenhaltungsschicht hinzugefügt. Die Schnittstellen
der Datenhaltungsschicht blieben dementsprechend nahezu unverändert. Es handelt sich dabei
um generische Erweiterung, die nach einfacher Konfiguration, parallel zur MySQL Datenbank
agiert. Die Daten werden weiterhin in beide Datenbanken geschrieben, wobei für den lesenden
Zugriff die sehr schnelle Redis Datenbank favorisiert wird und damit die ursprüngliche Datenbank stark entlastet wird. Die neue Ebene lässt sich über die generischen Funktionen hinweg
individuell anpassen. Dadurch war es möglich zusätzlich Daten der bestehenden Anwendung zu
denormalisieren und dadurch aufwendige Abfragen und Berechnungen einzusparen. Die Performance und Skalierbarkeit der erweiterten Fassung der Anwendung wurde dann ebenfalls gemessen
und festgehalten um den Ausgangszustand mit dem neuen Zustand zu vergleichen. Die Messung
der Größen wurde dabei immer mit realistischen Testdaten durchgeführt, deren Umfang und
Verteilung an eine reale Anwendung angelehnt sind. Im Rahmen der Qualitätssicherung wurden
darüber hinaus für die ursprüngliche Fassung der Anwendung Integrations- und Unittests entwickelt. Auf diesem Weg war es möglich die Transparenz und Qualität der erweiterten Anwendung
mit eben diesen Tests sicherzustellen.
Sowohl Performance, als auch Skalierbarkeit konnten durch den Einsatz der Redis Datenbank
gesteigert werden. Beim Test der Performance ist der Durchsatz um 25% gestiegen und die
mittlere Antwortzeit ist um 25% gesunken. Der Test bestand aus dem gleichzeitigen Ausführen
verschiedener Use Cases der Anwendung. Bei dem Test der Skalierung, welcher aus Anfragen an
die Anwendung bei steigender Anzahl gleichzeitiger Nutzer bestand, konnte die durchschnittliche Antwortzeit halbiert werden. Neben der Steigerung dieser absoluten Zahlen, wurde durch
die Redis Datenbank auch die Grundlage gelegt, die Performance und Skalierbarkeit mit wenig
54
KAPITEL 8. ZUSAMMENFASSUNG UND ERGEBNIS
Aufwand weiter zu steigern. Die Anwendung ist damit, für die sich verändernden und steigenden
Anforderungen an Anwendungen im Umfeld des Web 2.0 gerüstet. Durch die einfache Struktur
und das simple Key-Value Prinzip der Redis Datenbank fällt eine horizontale Skalierung besonders leicht. Schlüssel können mit Hilfe von Hashwerten einfach auf mehrere Server verteilt
werden. Spezielle Hash-Verfahren wie Consistent Hashing ermöglichen sogar ein Hinzufügen von
Servern mit minimalen Aufwand hinsichtlich der Neusortierung von Daten. Dadurch lässt sich
Performance und Skalierbarkeit beliebig steigern. Dem gegenüber steht die MySQL Datenbank,
für welche ebenfalls Verfahren zur Leistungssteigerung und Skalierung existieren. Dazu gehören
unter anderem, die einfach zu implementierende Replikation um Leseoperationen zu beschleunigen oder das aufwändige Sharding, bei dem Tabellen verteilt werden um sowohl Lese-, als auch
Schreibleistung zu steigern. Beide Verfahren eigenen sich ebenfalls zur Skalierung. Diese Verfahren haben allerdings gemeinsam, dass sie aufwendiger umzusetzen sind. Das gilt insbesondere
für die hier vorgestellte Webanwendung, welche mit vergleichsweise einfachen Datenstrukturen
auskommt und deren Migration von einem relationalen Datenbankmodell in ein nicht-relationales
Modell relative unkompliziert war.
Zusammengefasst kann festgehalten werden, dass die Performance und Skalierbarkeit einer Webanwendung mit Hilfe einer Redis Datenbank in jedem Fall gesteigert werden kann. Dabei steigert
sich sowohl die Performance und Skalierbarkeit an sich, als auch die Voraussetzungen beide Werte
durch sehr einfaches horizontales Skalieren zu erhöhen, was hauptsächlich durch die Möglichkeit
des Consistent Hashing gegeben ist.
8.2
Allgemeingültigkeit
Die Ergänzung um eine Redis Datenbank war für die Bespielanwendung von Vorteil. Performance
und Skalierbarkeit wurden erhöht und horizontales Skalieren ist nun einfach umzusetzen. Jetzt
gilt es noch zu klären, inwieweit das Verfahren für Webanwendungen im Allgemeinen anwendbar
ist.
Grundsätzlich gilt, dass für jede Webanwendung individuell geklärt werden muss, welches Vorgehen für eine Steigerung der Performance und Skalierbarkeit am geeignetsten ist. Insbesondere
muss dabei die Art der Anwendung und der Umfang der Nutzerzahlen berücksichtigt werden.
Für den Einsatz einer generischen Redis-Cache-Ebene sind Annwendungen geeignet, die folgende
Voraussetzungen erfüllen:
• Überschaubares Datenmodell mit wenigen und einfachen Relationen
• Absolute Konsistenz nicht notwendig
• Hohe Zugriffszahlen und schnelles Wachstum
Der erste Punkt ergibt sich aus der Natur der Redis Datenbank. Relationen können nativ nicht
abgebildet werden und müssen in der Applikationsebene verwaltet werden. Für die Speicherung
komplexer Beziehungen eignen sich relationale Datenbanksysteme immer noch am besten. Der
zweite Punkt begründet sich ebenfalls in der Art und Weise wie Redis Daten speichert. Informationen sind oft nicht atomar und Teil verschiedener Schlüssel. Daher können zeitweise und
vorübergehend immer Inkonsistenzen auftreten. Im Falle einer einfachen sozialen Webanwendung
55
KAPITEL 8. ZUSAMMENFASSUNG UND ERGEBNIS
ist das unproblematisch. Für ernsthafte Datenverarbeitung, wie beispielsweise Online-Banking,
ist das selbstverständlich nicht zu verantworten. Der letzte Punkt sollte auf jeden Fall immer
bedacht werden. Nur bei wirklich hohen Zugriffszahlen lohnt sich der Einsatz einer sehr schnellen
Redis Datenbank und der Aufwand diese zu integrieren. Für normale Szenarien ist eine traditionelle, relationale Datenbank ausreichend. Auch für Anwendungen mit hohen Zugriffszahlen,
aber wenig oder sehr gut absehbaren Wachstum, kann eine relationale Datenbank ausreichend
sein. Konkrete Vorgehensweisen müssten im Einzelfall bewertet werden.
Sind diese Voraussetzungen jedoch gegeben, ist eine Redis Datenbank aufgrund ihrer Einfachheit
und Geschwindigkeit in jedem Fall eine Überlegung wert. Eine einmal implementierte, generische Cache-Ebene ist sehr flexibel und kann auch steigenden Anforderungen und sich ändernden
Datenstrukturen schnell angepasst werden.
8.3
Ausblick
Die hier vorgestellte Implementierung stellt zunächst nur eine einfache Umsetzung einer RedisCache Ebene dar. Eine Fortführung der Entwicklung ist denkbar um weitere Funktionalitäten
generisch abzubilden und den Einsatz von Redis damit noch einfacher zu gestalten. Sofort denkbar wäre eine automatische Pflege der aktuellsten Einträge eines Models - eine sicherlich häufig
benötigte Funktion. Weitere solcher eingebauten Funktionen sind denkbar.
Das Profiling der neuen Version hat gezeigt, dass immer noch der größte Teil der Ausführung
auf die Datenhaltung verwendet wird. Es sollten Überlegungen angestellt werden, wie diese absolute Zahl der Zugriffe weiter gesenkt werden kann. Eine Möglichkeit wäre, zusätzlich größere
Datenansichten in Redis zu speichern, wie zum Beispiel die bereits diskutierten vollständigen
HTML-Ansichten der Statements. In diesem Fall aber als zusätzliche Daten, neben den atomaren Informationen. Dadurch könnte in bestimmten Ansichten die Anzahl an Datenbankanfragen
weiter verringert werden.
Es sollte auch evaluiert werden, inwieweit vollständig auf MySQL verzichtet werden kann und
damit eine Mehrbelastung durch zwei Datenbanksysteme zu vermeiden. Dazu muss in jedem
Fall ein Konzept erarbeitet werden, wie Inkonsistenzen vermieden werden können, die durch die
Verteilung eines Model auf viele Schlüssel entstehen können.
Abschließend wäre ist ebenfalls wünschenswert den Nutzen der Redis Datenbank in Bezug auf
Performance und Skalierbarkeit in einem realen Nutzungsszenario mit echten Nutzern und Produktionsservern zu bewerten. Dadurch könnte eine wesentlich differenzierte Empfehlung bezüglich
des Mehrwertes erfolgen.
56
Literatur
Allspaw, J. (2008). The Art of Capacity Planning: Scaling Web Resources. O’Reilly Series.
O’Reilly Media. isbn: 9780596518578.
Calzarossa, M.C., S. Tucci und IFIP Working Group 7.3 on Computer System Modelling (2002).
Performance Evaluation of Complex Systems: Techniques and Tools : Performance 2002 Tutorial Lectures. Lecture Notes in Computer Science. Springer. isbn: 9783540442523.
Edlich, S., A. Friedland, J. Hampe und B. Brauer (2010). NoSQL: Einstieg in die Welt nichtrelationaler Web 2.0 Datenbanken. Hanser. isbn: 9783446427532.
Edlich, S., A. Friedland, J. Hampe, B. Brauer und M. Brückner (2011). NoSQL: Einstieg in die
Welt nichtrelationaler Web 2.0 Datenbanken. Hanser. isbn: 9783446427532.
Freeman, E.T., E. Robson, B. Bates und K. Sierra (2004). Head First Design Patterns. Head
First. O’Reilly Media. isbn: 9780596007126.
Governor, J., D. Nickull und D. Hinchcliffe (2009). Web 2.0 Architectures. Oreilly Series. O’Reilly
Media, Incorporated. isbn: 9780596514433.
Gull, Clemens (2011). Web-Applikationen entwickeln mit NoSQL. Franzis. isbn: 9783645601047.
Henderson, C. (2006). Building Scalable Web Sites. O’Reilly Series. O’Reilly. isbn: 9780596102357.
Joines, S., R. Willenborg und K. Hygh (2003). Performance Analysis for Java Web Sites. Addison
Wesley. isbn: 9780201844542.
Kecher, Christoph (2011). UML 2: Das umfassende Handbuch. Galileo Design. Galileo Press
GmbH. isbn: 9783836214193.
Meier, J. (2007). Performance Testing Guidance for Web Applications: Patterns & Practices.
O’Reilly Media, Inc. isbn: 9780735646001.
Menascé, D.A., V.A.F. Almeida, L.W. Dowdy und L. Dowdy (2004). Performance by Design:
Computer Capacity Planning by Example. Prentice Hall PTR. isbn: 9780130906731.
Möhrke, C. (2012). Besser PHP programmieren. Galileo computing. Galileo Press. isbn: 9783898423816.
Nagaraj, S.V. (2004). Web Caching and Its Applications. Kluwer international series in engineering and computer science. Kluwer Academic Publishers. isbn: 9781402080494.
57
LITERATUR
Oracle (2012). Guide to Scaling Web Databases with MySQL Cluster. Techn. Ber.
Pröll, S., E. Zangerle und W. Gassler (2011). MySQL: Das Handbuch für Administratoren. Galileo
Press GmbH. isbn: 9783836217156.
Seguin, K (2012). The Little Redis Book. http://openmymind.net.
Shuen, A. (2008). Die Web 2.0 Strategie. O’Reilly. isbn: 9783897218666.
Souders, S. (2009). Even Faster Web Sites. O’Reilly Series. O’Reilly. isbn: 9780596522308.
Whittaker, J.A., J. Arbon und J. Carollo (2012). How Google Tests Software. Addison Wesley
Professional. isbn: 9780321803023.
58
Online Quellen
Apache (2012). Apache JMeter. url: http://jmeter.apache.org/usermanual/intro.html
(besucht am 11. 07. 2012).
CakePHP (2012). Understanding Model-View-Controller. url: http://book.cakephp.org/2.
0 / en / cakephp - overview / understanding - model - view - controller . html (besucht am
06. 08. 2012).
data.stackexchange.com (2012). Stack Exchange Data Explorer. (Besucht am 26. 06. 2012).
highscalability.com (2012). The Four Meta Secrets of Scaling at Facebook. url: http://highscalability.
com/blog/2010/6/10/the-four-meta-secrets-of-scaling-at-facebook.html (besucht
am 23. 07. 2012).
ITWissen (2012). Performance. url: http : / / www . itwissen . info / definition / lexikon /
Performance-performance.html (besucht am 23. 07. 2012).
meta.stackoverflow.com (2010). Does Stack Overflow use caching and if so, how? url: http:
//meta.stackoverflow.com/questions/69164/does- stack- overflow- use- cachingand-if-so-how (besucht am 02. 08. 2012).
nosql-databases.org (2012). List Of NoSQL Databases. url: http://nosql-databases.org/.
Offizielle Redis Webseite (2012). How fast is Redis? url: http://redis.io/topics/benchmarks
(besucht am 19. 07. 2012).
O’Reilly, Tim (2005). What Is Web 2.0? url: http://www.oreilly.de/artikel/web20.html
(besucht am 18. 06. 2012).
pch.net (2012). Internet Exchange Directory. url: https://prefix.pch.net/applications/
ixpdir/ (besucht am 03. 07. 2012).
plista GmbH (2012). Offizielle Webpräsenz. url: http://www.plista.com/infos/company
(besucht am 18. 06. 2012).
quantcast (2012). Statistiken von Stack Overflow. url: http://www.quantcast.com/stackoverflow.
com (besucht am 07. 08. 2012).
59
ONLINE QUELLEN
stackexchange.com (2012). About Stack Exchange. url: http : / / stackexchange . com / about
(besucht am 26. 06. 2012).
stackoverflow.com (2009). Stack Overflow Blog. url: http://blog.stackoverflow.com/2009/
09/one-million-pageviews/ (besucht am 26. 06. 2012).
— (2012a). About Stack Overflow. url: http : / / stackoverflow . com / about (besucht am
26. 06. 2012).
— (2012b). Stack Overflow FAQ. url: http://stackoverflow.com/faq (besucht am 09. 08. 2012).
www.de-cix.net (2012). DE-CIX. url: https://www.de-cix.net/about/statistics/ (besucht
am 03. 07. 2012).
60
Anhang A
Stack Overflow SQL Abfragen
Listing A.1: Minimale und Maxmimal Anzahl an Antworten
SELECT
min ( Posts . AnswerCount ) as [ Minimum # of Answers ] ,
avg ( cast ( Posts . AnswerCount as decimal )) as [ Average # of Answers ] ,
max ( Posts . AnswerCount ) as [ Maximum # of Answers ]
FROM Posts
WHERE Posts . PostTypeId =1
Listing A.2: Gesamtzahl an Fragen
SELECT count ( Id ) FROM posts WHERE Posts . PostTypeId =1
Listing A.3: Fragen ohne Antworten
SELECT count ( Id ) FROM posts WHERE Posts . PostTypeId =1
AND AnswerCount is null OR AnswerCount = 0
Listing A.4: Fragen mit bestimmter Anzahl an Anworten
SELECT count ( Id ) FROM posts WHERE Posts . PostTypeId =1
AND AnswerCount between 1 and 50
Listing A.5: Anzahl Nutzer
SELECT count ( Id ) FROM users
Listing A.6: Maximale Reputation
SELECT max ( Reputation ) FROM users
Listing A.7: Maximaler Score
SELECT max ( score ) FROM posts
Listing A.8: Anzahl an Beiträgen insgesamt
SELECT count ( id ) FROM posts
61
ANHANG A. STACK OVERFLOW SQL ABFRAGEN
Listing A.9: Score sortiert nach Häufigkeit
SELECT score , count ( score ) as c FROM posts
GROUP BY score ORDER BY c DESC
Listing A.10: Anzahl Fragen vor einem bestimmten Datum
SELECT count ( id ) FROM posts
WHERE posttypeid = 1 AND creationdate < ’ 2009 -09 -30 ’
Listing A.11: Anzahl Nutzer vor einem bestimmten Datum
SELECT count ( id ) FROM users creationdate < ’ 2009 -09 -30 ’
Listing A.12: Anzahl Stimmen in bestimmten Zeitraum
SELECT count ( id ) FROM votes WHERE CreationDate
BETWEEN ’ 2009 -09 -30 ’ and ’ 2009 -10 -01 ’
62
Anhang B
Beispielhafter Aufbau einer
XML-Konfigurationsdatei
<? xml version = " 1.0 " encoding = " UTF -8 " ? >
< redisstorage >
< arguments >
< key > argument </ key >
< primarykey > argumentId </ primarykey >
< index > true </ index >
< entity > true </ entity >
< conditions >
< condition >
< field name = " statementId "
< field name = " polarity " / >
</ condition >
< condition >
< field name = " userId "
</ condition >
</ conditions >
</ arguments >
</ redisstorage >
63
/>
/>
Anhang C
Übersicht und Ergebnisse der
Tests
C.1
PHPUnit Tests der Model
Ergebnis und Bemerkung
Test
Anzahl
Assertions
Beschreibung
IstZustand
Redis-Version
testFindById
4
Abruf eines Datensatzes
Primärschlüssel
nach
OK
OK
testFindWithCondition
5
Abruf von Datensätzen mit Konditionen
OK
Anpassung Option ohne
rungsangabe
testCount
1
Abruf der Anzahl an Datensätzen
OK
OK
testSave
3
Erstellen eines neuen Datensätzen
OK
OK
testDelete
1
Löschen eines Datensatzes
OK
OK
testUpdate
1
Änderung und anschließende Speicherung eines Datensatzes
OK
OK
testUserAssociation
4
Abruf des Datensatzes des assoziierten Nutzers
OK
OK
testArgumentsAssociation
3
Abruf der Datensätze der assoziierten Argumente
OK
OK
testTagsAssociation
2
Abruf der Datensätze der assoziierten Tags
OK
OK
testFindById
5
Abruf eines Datensatzes
Primärschlüssel
nach
OK
OK
testFindWithCondition
5
Abruf von Datensätzen mit Konditionen
OK
Anpassung Option ohne
rungsangabe
testCount
1
Abruf der Anzahl an Datenssätzen
OK
OK
testSave
3
Erstellen eines neuen Datensatzes
OK
OK
testDelete
1
Löschen eines Datensatzes
OK
OK
Statement Model
OrderSortie-
Argument Model
64
OrderSortie-
ANHANG C. ÜBERSICHT UND ERGEBNISSE DER TESTS
testUpdate
1
Änderung und anschließende Speicherung eines Datensatzes
OK
OK
testUserAssociation
4
Abruf des Datensatzes des assoziierten Nutzers
OK
OK
testStatementAssociation
2
Abruf des Datensatzes des assoziierten Statements
OK
OK
testVotesAssociation
3
Abruf der Datensätze der assoziierten Votes
OK
OK
testFindById
5
Abruf eines Datensatzes
Primärschlüssel
nach
OK
OK
testFindWithCondition
3
Abruf von Datensätzen mit Konditionen
OK
OK
testCount
1
Abruf der Anzahl an Datensätzen
OK
OK
testSave
3
Erstellen eines neuen Datensatzes
OK
OK
testDelete
1
Löschen eines Datensatzes
OK
OK
testUpdate
1
Änderung und anschließende Speicherung eines Datensatzes
OK
OK
testStatementsAssociation
3
Abruf der Datensätze der assoziierten Statements
OK
Anpassung Option ohne
rungsangabe
OrderSortie-
testArgumentsAssociation
3
Abruf der Datensätze der assoziierten Argumente
OK
Anpassung Option ohne
rungsangabe
OrderSortie-
testVotesAssociation
3
Abruf der Datensätze der assoziierten Votes
OK
Anpassung Option ohne
rungsangabe
OrderSortie-
testFindById
2
Abruf eines Datensatzes
Primärschlüssel
nach
OK
OK
testFindWithCondition
3
Abruf von Datensätzen mit Konditionen
OK
Anpassung Option ohne
rungsangabe
testCount
1
Abruf der Anzahl an Datensätzen
OK
OK
testSave
2
Erstellen eines neuen Datensatzes
OK
OK
testDelete
1
Löschen eines Datensatzes
OK
OK
testUpdate
1
Änderung und anschließende Speicherung eines Datensatzes
OK
OK
testStatementsAssociation
3
Abruf der Datensätze der assoziierten Statements
OK
OK
testFindById
3
Abruf eines Datensatzes
Primärschlüssel
nach
OK
OK
testFindWithCondition
3
Abruf von Datensätzen mit Konditionen
OK
Anpassung Option ohne
rungsangabe
testCount
1
Abruf der Anzahl an Datensätzen
OK
OK
testSave
1
Erstellen eines neuen Datensatzes
OK
OK
testDelete
1
Löschen eines Datensatzes
OK
OK
testUpdate
1
Änderung und anschließende Speicherung eines Datensatzes
OK
Anpassung - ArgumentId muss existieren
User Model
Tag Model
OrderSortie-
ArgmtVote Model
65
OrderSortie-
ANHANG C. ÜBERSICHT UND ERGEBNISSE DER TESTS
C.2
Selenium Tests
Test
Beschreibung
login
Einloggen eines Testnutzers
createstatement
Erstellen eines Statements mit Schlagwörtern. Überprüfung, ob
Statement vorhanden ist und mit Schlagwort versehen wurde.
createargument
Ein Argument zum dem Statement anlegen. Überprüfung,
ob Argument vorhanden ist und sich die öffentliche Meinung
verändert hat.
voteargument
Die Stimme des Arguments entfernen. Überprüfung, ob sich die
öffentliche Meinung entsprechend ändert.
deleteargument
Das Argument löschen.
deletestatement
Das Statement löschen.
search
Eine Suche ausführen
logout
Testnutzer ausloggen
C.3
PHPUnit Tests der Erweiterung
Test
Beschreibung
testCreate
Anlegen eines neuen Datensatzes
testCreateWithMissingCondition
Anlegen eines neuen Datensatzes, ohne eine konfigurierte Kondition mitzugeben
testReadAll
Alle Datensätze lesen
testReadWithCondition
Datensätze mit Kondition lesen
testReadWithConditionWithoutEntity
Datensätze mit Kondition lesen, ohne dass die Entität mitgespeichert wurde
testReadWithWrongCondition
Datensätze mit flaschen Konditionen lesen
testReadById
Einen einzelen Datensatz lesen
testUpdateWithIndex
Datensatz mit Index ändern
testUpdateWithoutIndex
Datensatz ohne Index ändern
testDelete
Datensatz löschen
testCountAll
Alle Datensätze zählen
testCountWithCondition
Datensätze nach Kondition zählen
testProcessOptionsWrongOption
Eine falsche Option übergeben
testProcessOptionsWrongOrder
Falsche Order-Option übergeben
testProcessOptionsWrongConditions
Falsches Condition-Format übergeben
testProcessOptionsRightConditions
Richtiges Condition-Format übergeben
testProcessOptionsLimitAndOffset
Optionen beinhalten Limit und Offset
Redis-DataSource
Utilities
66
Anhang D
Inhalt der CD-ROM
• JMeter Testdateien
• JMeter Messergebnisse
• Understandr Quelltext in der neuen Version
• PHPUnit Tests
• Selenium Test
• Quelltext der Redis Erweiterung
• Diese Arbeit im PDF-Format
67
Eigenständigkeitserklärung
Hiermit versichere ich, dass ich die vorliegende Bachelorarbeit selbstständig und nur unter Verwendung der angegebenen Quellen und Hilfsmittel verfasst habe. Die Arbeit wurde bisher in
gleicher oder ähnlicher Form keiner anderen Prüfungsbehörde vorgelegt.
——————————————
Fabian Kirstein
Berlin, 13.08.2012
Herunterladen