Hadoop 2.7.2 auf dem Raspberry PI 2 Cluster

Um etwas mehr in die Tiefe von Hadoop einzutauchen, habe ich nun einen Hadoop 2.7.2 Cluster auf dem 6-Node Raspberry PI 2 Cluster aufgesetzt.

Hadoop 2.7.2 auf Raspberry PI 2 Cluster
Word Count mit 5 Slaves und einem Master Node

Leider lief nicht alles auf Anhieb einwandfrei. So musste ich die native-Libraries für die ARM-Prozessorplattform des Raspberry PI selbst kompilieren. Auch die Netzwerkkonfiguration benötigte einige Erfahrung bezüglich SSH und Linux-Konfigurationsfiles. Auch vor den typischen Cloud-Problemen mit Billighardware blieb ich nicht gefeit. Etwa nach der Hälfte der Arbeit hängte sich ein Node auf und musste komplett neu aufgesetzt werden.

Betrachtet man all diese Aufwände, welche nötig sind um einen Cluster nur mal zum Laufen zu bringen, geschweige denn im produktiven Betrieb zu halten, zeigen sich folgende Punkte klar und deutlich:

  • Man muss von Anfang an eine DevOp-Lösung zur Konfigurationsverwaltung verwenden. Andernfalls verliert man den Überblick und verschwendet unnötig Zeit für Fehlersuche.
  • Die Verwendung einer Public-Cloud-Infrastruktur wie Amazon AWS oder Microsoft Azure rechnen sich schnell, betrachtet man die Zeit, die für Wartung und Betrieb nötig sind.
  • Um die Möglichkeiten und Einschränkungen einer solchen Lösung wirklich zu verstehen, macht es jedoch schon Sinn, selbst mal eine solche Infrastruktur aufzusetzen. So lernt man doch am meisten.

So damit wäre die Grundlage für den Batch-Layer der Lambda-Architektur gelegt.

Mein eigener Cluster mit 6 Raspberry PI 2 Nodes

Wozu ein eigener Cluster?

Verteilte Systeme haben mich schon immer fasziniert. Die Entwicklung solcher Systeme erfordert aber einiges an Administrationsaufwand um eine entsprechende Entwicklungs- und Testinfrastruktur aufzusetzen.

Grundsätzlich gibt es zwei Möglichkeiten:

  • Virtualisierung und Simulation eines Netzwerks. (Ein Tool um das zu vereinfachen habe ich bereits 2004 im Rahmen meiner Diplomarbeit entwickelt.)
  • Simulation mittels Hardware. Dies war bis jüngst die teuerste Alternative. Mit günstigen Einplatinenrechner wie z.B. dem Raspberry PI ist das nun aber problemlos möglich.

Der Cluster

Mein Cluster besteht aus 6 Raspberry PI 2 mit je 16GB microSD Speicher. Untereinander sind die Knoten über einen 100MBit Ethernet Switch verbunden, der wiederum über einen alten WLAN-Router im Bridge-Modus ins WLAN eingebunden ist, um so den Zugriff von anderen Rechnern aus und aufs Internet zu ermöglichen.

Cluster mit 6 Raspberry PI 2 Nodes
Erster Stand des 6 Node Raspberry Pi 2 Clusters

Cluster-Verwaltung

So ein Cluster mit 6 Nodes mittels SSH zu verwalten wäre eine ziemliche Fleissarbeit. Zum Glück gibt es bereits passende Tools, welche einem viel Arbeit abnehmen können. Die wohl bekanntesten Tools zur DevOp-Automatisierung sind Puppet, Chef und Ansible. Ich habe mich als erstes für Ansible entschieden, da es keine Installation auf den Nodes erfordert. Einzige Voraussetzung ist, dass auf die Nodes Zugriff via SSH ermöglichen, was sowieso schon der Fall war. Einzig auf dem Rechner, von dem man aus das Cluster verwalten will benötigt die Installation von Ansibel, die über PIP ein Einzeiler ist:

Ist Ansible erst mal heruntergeladen und installiert, muss man ein Host-File erstellen, das sogenannte Inventory-File. Da ich unter Mac OS X dafür nicht /etc/ansible/hosts verwenden wollte, habe ich in einem Unterordner ein eigenes hosts-File erstellt.

Um nun alle Nodes im Cluster zu pingen, kann folgender Befehl verwendet werden, unter der Voraussetzung, dass man sich auf dem Terminal im Verzeichnis des hosts-File befindet (Option -i . für Inventory-Verzeichnis = .):

Ping des Clusters via Ansible

Ansible funktioniert via SSH. Daher ist ein ping hier durch das Ansible ping-Modul (-m ping) realisiert, das einfach ein SSH-Login auf jedem Node durchführt und so die Verbindung prüft.

Eben so hilfreich ist es das Cluster mit einem solchen Befehl herunterzufahren:

Shutdown des Clusters via Ansible

Ausblick

Da mein Cluster nun funktioniert, plane ich in näherer Zukunft einige Test mit verteilten Applikationen:

  • Lambda-Architektur mit
    • Hadoop Cluster für Batch Layer
    • Spark Cluster für Speed Layer
  • MicroServices Simulation mit Akka
  • Tests unterschiedlicher Verteilter Stores/DBs wie CouchDB, Redis, Cassandra, etc.

Offene / freie Datenquellen (Open Data)

Schon erstaunlich, welche Informationen einem als Open Data zur Verfügung stehen. Leider kommt man oft gar nicht auf die Idee, dass gewisse Infos bereits frei zur Verfügung stehen, wenn man vor einer Aufgabe steht. Deshalb möchte ich hier  einige interessante Datenquellen sammeln und vorstellen… So als Inspiration für spätere Datenanalyse-Spielereien.

Transport und Verkehr

Energie

Regional (Länder/ Kantone /Städte / Gemeinde)

Medizin

Wetter

Wissenschaft

Wirtschaft

Die Liste wird von Zeit zu Zeit erweitert und aufgeräumt.

Modulare Architektur für WebApp mit Ionic / Angular

In diesem Beitrag möchte ich eine modulare Architektur für hybride mobile Apps mit dem Ionic-Framework vorstellen.

Leider bieten die Starter-Templates keine wirklich gute Ausgangslage für eine modulare Architektur. Die Möglichkeiten von Modulen in Angular werden nicht ausgeschöpft, so dass aller Code für sämtliche Screens in den beiden Dateien app.js und controller.js im Verzeichnis www/js/ landet.

Wie man diese Beispiel App nun in eine modulare Architektur überführt (refactoring) zeigt dieser Artikel. Den Source-Code zum Artikel gibt es auf liegt auf meinem GitHub Repository die Commits zeigen die entsprechenden Schritte des Refactorings

Analyse

Analysieren wir mal die Ionic Starter App  mit dem Sidemenu welche durch folgendes Kommando erstellt:

Damit erhält man eine App, welche ein Sidemenu enthält, das die Navigation zu den Screens (Views) bietet:

  • Login
  • Search
  • Browse
  • Playlists
    • Playlist item

Die wesentliche Verzeichnisstruktur der App sieht wie folgt aus:

Verzeichnisstruktur der ionic sample app für sidemenu
Verzeichnisstruktur der Ionic sample App für sidemenu

Die folgenden Dateien sind für uns von Interesse:

  • index.html bildet den Rahmen für die App indem es Styles und Scripts einbindet und den Platzhalter für Views   <ion-nav-view></ion-nav-view> enthält.
  • app.js enthält den Code zur Initialisierung und Konfiguration der App
  • controllers.js enthält sämtliche Controller von sämtlichen Views.
  • templates/* beinhaltet die Views für einzelne Screens.

Die aktuelle Struktur mag ja für einfache Beispiele wie dieses Starter Demo App genügen, führt jedoch sehr schnell zu Problemen, da keine klare Trennung der Module und damit der Verantwortlichkeiten vorhanden ist. Sowohl app.js wie auch controller.js enthalten Code für unterschiedliche Features (Views). Werden noch weitere Views hinzugefügt, kann das sehr schnell sehr unübersichtlich werden.

Betrachten wir die vorhandenen JavaScript Dateien app.js und controller.js im Detail:

In app.js wird die Applikation initialisiert und der State-Provider für sämtliche States aus controller.js konfiguriert.

In controller.js werden dann die Controller zu den States implementiert. Damit ist eine direkte Koppelung zwischen den beiden Dateien vorhanden.

Wenn man eine neue Funktion hinzufügen will, muss man in app.js einen neuen State eintragen und in controller.js den entsprechenden Controller. Zusätzlich sind dann im Templates Ordner auch noch eine oder mehrere neue Views zu erstellen.

Refactoring / Modularisierung:

Nachdem wir nun in der Analyse gesehen haben, was nicht so optimal ist, scheint es nun klar, dass wir Module erstellen sollten, welche einzelne Features darstellen.

Typischerweise enthält so eine App mehrere Features, welche durch einzelne (Angular-)Module bestehend aus dem JavaScript-Code für Konfiguration und Logik und den entsprechenden HTML-Files für Views bestehen.

Solch ein modularer Aufbau hat einige Vorteile:

  • Module können in anderen Apps ohne oder mit geringen Anpassungen wiederverwendet werden.
    Stichwort: Wiederverwendbarkeit
  • Die Zusammenarbeit im Team ist einfacher, da unterschiedliche Entwickler an unterschiedlichen Modulen arbeiten können und der Code in unterschiedliche Dateien  liegt.
    Stichwort: Geringe Koppelung.
  • Die Verständlichkeit eines Modules ist viel besser, wenn alles zusammen ist, als wenn die Teile vermischt mit anderen Modulen in unterschiedlichen Dateien und Verzeichnissen liegt. Dies verringert die Einarbeitungszeit, die Zeit für Entwicklung und Fehlersuche und erhöht die Testbarkeit.
    Stichwort: Hohe Kohäsion.

Um diese Ziel-Architektur zu erreichen, bauen wir die Applikation nun in folgenden Schritten um:

  1. Das Verzeichnis „js“ wird in „app“ umbenannt, da wir nun hier Module bestehend aus HTML und JavaScript ablegen werden.
  2. Im Verzeichnis „app“ erstellen wir ein Unterverzeichnis „modules“, welches die Module enthalten wird
  3. Im Verzeichnis „modules“ erstellen wir Unterverzeichnisse für die Module: „browse“, „search“, „playlist“ und „menu“
  4. Die entsprechenden HTML-Dateien aus dem Verzeichnis „templates“ werden nun in die jeweiligen Modul-Verzeichnisse verschoben.
  5. In jedem Modul-Verzeichnis wird ein JavaScript-File mit entsprechendem Namen angelegt, welches die Konfiguration der States und die Controller zum Modul enthält. Siehe GitHub
  6. Die JavaScript-Files der Module werden im index.html File eingebunden:
  7. Das „templates“ Verzeichnis und das controller.js File können nun gelöscht werden.

Die neue Verzeichnis/Datei-Struktur sieht nun wie folgt aus:

Verzeichnistruktur für modulare Ionic-App

Die Datei app.js ist nun nur noch für die Initialisierung der App zuständig:

Zu beachten hier ist, dass in der ersten Zeile das starter-Modul definiert wird, welches nun aber die neu erstellten Module einbindet.

Die Implementation der einzelnen Module sind auf meinem GitHub-Repository zu finden.

Stellvertretend für ein einfaches Modul, soll hier das Modul „browse“ betrachtet werden. Die View absiert auf den Ionic-Tags und zeigt eine View mit dem Text „Browse“ an:

In browse.js wird das „browse.module“ definiert, welches den State-Provider konfiguriert und den Controller „BrowseCtrl“ implementiert.

Etwas komplexer ist das Modul „playlist“, welches aus der Master-View (Liste) „playlists.html“ und der Detail-View „playlist.html“ besteht. Die Datei „playlists.js“ definiert die States und die Controller für beide Views.

In playlists.html wird für jedes Element aus Variablen „playlists“ aus dem Angular-Playlists-Controller-Scope ein List Item erstellt, dass ein Link mit der Playlist ID in der URL und dem Playlist Titel als Text enthält:

Wählt der Benutzer solch ein List-Item, wird zur Detail-View playlist.html navigiert, welche mit dem Controller „PlaylistItemCtrl“ verbunden ist. Diesem werden bei der Initialisierung in $stateParams die Parameter aus der URL übergeben. Hier also die Playlist ID. Über diese ID, wird das Playlist-Element gesucht und via Scope-Vaiable $scope.playlist  der View zur Verfügung gestellt. Die View verwendet dann den Titel:

Fazit:

Mit einigen einfachen Schritten kann mittels Angular eine sehr modulare Applikation erstellt werden. Die gezeigte Lösung gibt einen ersten Eindruck, wie eine modulare Architektur aussehen kann.

Für die aktuelle Lösung müssen aber immer noch 3 Dateien angepasst werden, wenn man ein Modul hinzufügen oder löschen will:

  • index.html: Hier werden die JavaScript-Dateien eingebunden.
  • menu.html im Module „menu“: Hier wird das Menü angezeigt.
  • app.js: Hier werden die Module vom starter-Modul referenziert.

Wie man auch noch diese Unschönheiten beheben kann, behalte ich mir für einen späteren Artikel vor.

Mein anderer Blog

Leider komme ich momentan nicht so oft dazu meinen privaten Blog zu aktualisieren. Einige interessante Projekte findet man aber auf meinem Noser-Blog (vom 1. Februar 2009 bis 31. Dezember 2016, ab 1. Januar 2017 arbeite ich nicht mehr bei Noser Engineering AG)