Und zack! Tot.

Privat interessiere ich mich nicht nur für die Programmierung, sondern auch für klassische Mechanik in Form von PKW.

Audi 80 Typ89 mit 1.8L JN KE-Jetronic

Meine Autofahrer"karriere" begann mit einem Audi 80 EZ 1990. Der hatte ABS, Scheibenbremsen vorne und hinten, ein Fahrwerk für Doofe, Velours-"Sportsitze" (serie), elektrisch verstellbare Spiegel, Schiebedach und Heckscheibenheizung.

Dafür hatte der Audi 80 Typ89 keine Servolenkung.

Das ABS konnte man nach jedem Motorstart deaktivieren; es gab dafür einen Knopf (Taster!). Der Audi war natürlich frontgetrieben und es war quasi unmöglich ihn aus der Spur zu bringen. Wenn man zu schnell in eine Kurve gefahren ist, schob das Auto lediglich über die Vorderräder und man konnte nicht mehr lenken. Das konnte man aber regulieren, in dem man vom Gas ging; dann konnte man auch wieder lenken.

Ich kaufte den Audi 80 mit 199.000km. Da war das Auto quasi schon verbraucht. Das Fahrwerk e.g. war hinüber. Erst, als ich beim Bremsen auf unebenen Straßen merkte, dass das Auto quasi "abhebt" und gar nicht mehr richtig bremst, beschloss ich ein komplett neues Fahrwerk einzubauen. Ich verbaute H&R Federn mit Bilstein Dämpfern. Natürlich etwas tiefer. Das Auto war danach ein anderes. Es war vergleichsweise hart, lag dafür aber extrem gut auf der Straße. Man konnte auch bei hohen Geschwindigkeiten über Unebenheiten brettern (Autobahn e.g.). Das Fahrwerk war so gut, dass man manchen schnelleren Brot-und-Butter Autos davon fuhr, weil selbst bei Neuwagen in der Brot-und-Butter Klasse die Serienfahrwerke ab höheren Geschwindigkeiten zum "Schaukeln" neigen, was dann in Kurven auf Autobahnen ein unsicheres Gefühl vermittelt (auch, wenn in der Regel nichts passiert). Besonders den kleinen SUV konnte man recht einfach davon fahren, weil die eh nicht besonders schnell fahren und auch sonst ganz gut hoppeln.

Ich war aber jung und lernte noch Fahrpraxis. Da war das ABS sehr willkommen, weil es erlaubt bei einer Vollbremsung noch zu bremsen. Im Schnee kann man es deaktivieren, wenn man meint fahren zu können.

Mit dem Audi 80 hatte ich meine grundlegende Fahrpraxis sammeln können.

Lincoln Continental Mark IV 1972 7.5L V8

Mein Audi 80 war mir aber irgendwie zu langweilig, also wollte ich als Hobby mal etwas Ausgefallenes. Für "Amis" interessierte ich mich sowieso und dann wurde es ein Lincoln Continental Mark IV aus 1972 mit 7.5L V8.

Das war im Grunde das Gegenteil des Audi; super bequem, dicker Motor, aber der Lincoln, so alt er auch war, war seiner Zeit irgendwie voraus; zumindest für US-amerikanische Verhältnisse. Er hatte rundum Scheibenbremsen und eine Art ABS mit dem Namen "Suretrack". Der Lincoln wiegt ca. 2.3t und ich musste tatsächlich mal vollbremsen und da merkte ich dann auch das "ABS"; es funktionierte zwar nich annährend so genau wie das vom Audi 80, aber es "verzögerte" :).

Mercedes W124 300CE 1992

Der Lincoln war nur mein Hobbyauto, aber ich wollte nun auch soetwas ähnliches für den Alltag, also kaufte ich mir den 300CE; Fehler :P. Lahme Kiste. Behebig, Opa-Automatik und ein Lenkrad so groß wie im Segelschiff...egal...war nicht meins...also weg damit. Ich würde nie wieder einen Motor mit 4-Gang Lahmomat kaufen. Im Lincoln war der 3-Gang Automat in Ordnung, aber auch nur, weil der Automat so gut wie nie schaltete. Die 7.5L benötigten das einfach nicht; der hatte untenrum bärenkräfte.

BMW 3er E90 LCI 318d 12/2011

Ich hatte den Mercedes mit Verlust verkauft; nachdem ich ihm einen neuen Motor aus einem 4Matic spendiert hatte. Mir hat es dann ein 318d angetan. Schwarz...finde ich noch heute gut und fahre ich gerne im Alltag.

BMW 3er 316 1979

Der Lincoln hatte es mir nach einiger Zeit als Hobby aber nicht mehr angetan. Die Kiste fiel auf und mir war die "Couch auf Rädern" irgendwann zu langweilig. Der Lincoln ist innen sehr leise und man muss quasi nicht dabei sein; man steigt ein, legt die Fahrstufe ein und lässt sich vom Auto fahren :). Ich hatte mir also einen alpinweißen E21 angelacht. Mit stolzen 90PS, kein ABS, keine Servo, keine Hydrostößel(!Ventilspiel einstellen!).

Der E21 hat aktuell 113tkm auf dem Tacho, wurde von einem Rentner gefahren usw...alles nachvollziehbar. Sehr schön, aber wie jedes alte Auto, das ich kaufe, war auch hier der Hauptbremszylinder defekt.

Ich hatte schon bei meinem Lincoln einen defekten Hauptbremszylinder; den Defekt bemerkte ich auf der Autobahnabfahrt als ich bremsen wollte ;). Ein sehr unwohles Gefühl, wenn man bremst und das Pedal bis zum Teppich geht.

Beim E21 bemerkte ich es ähnlich. Ich war auf einer Landstraße unterwegs, als ich an einer Kreuzung mit Ampel bremsen musste, weil es auf gelb wechselte und trotz 70km/h die Gelbphase kurz war. Ich bremste also etwas stärker und bemerkte, dass das Pedal zum Teppich sackt und ich keine Bremsleistung habe...innerhalb von MS war mir klar, dass ich die Kreuzung auch ohne zu bremsen überleben kann, aber ich wusste ja, dass Pumpen hilft; tat es auch hier...phew :).

Ich besorgte mir also einen neuen HBZ und der E21 bremste wieder wie er sollte.

ABER wie es der Teufel so will, nimmt mir heute eine Twingofahrerin die Vorfahrt, ich musste vollbremsen, die Räder blockierten (kein ABS) und ich konnte nicht mehr rechtzeitig bremsen, also wollte ich "vorbei lenken", ging aber nicht, weil die Räder blockierten. Also kurz runter von der Bremse, Route ändern und wieder vollbremsen...

Das alles passierte in einem Bruchteil einer Sekunde.

Und auch, wenn ich es erstaunlich finde, wie schnell das Gehirn "schalten" kann, so war mir auch bewusst, dass das auch ein schlechteres Ende haben könnte. Kein Airbag e.g.; ein altes Karosseriekonstrukt usw...aber die Frau hätte bei Kontakt nur hoffen können, dass ich nicht mehr aussteigen kann.

Die Frau bemerkte das Ganze nicht mal :(. Sie fuhr einfach ohne jegliche Reaktion weiter.

Fazit: gut, dass mein HBZ neu war :)!

Verfasst am 14.04.2014 (Permalink).

Android Entwicklung mit Android Studio

Ich kann es nicht sein lassen am Wochenende zu programmieren. Da ich mich mal wieder mit Android beschaeftigen wollte, kam es mir sehr gelegen, dass Google mittlerweile erkannt hat, dass Eclipse nichts ist, was erstrebenswert waere.

Sie haben also den Quellcode von Intellij Community Edition genommen und daraus "Android Studio" gemacht: Android Studio

Android Studio ist eine sehr nette Java IDE extra fuer Android. Man braucht nichts einrichten; einfach runterladen, neues Projekt anlegen und auf den "gruenen Pfeil" klicken :P. Ok, man muss bei seinem Android Smartphone USB Debugging aktivieren oder den Emulator konfigurieren, aber das ist alles recht einfach.

Android Studio hat sogar einen UI-Designer!

Meine "App"

Meine Test-App, die tatsaechlich einen Zweck erfuellen soll, nennt sich "SmokeCounter" und zaehlt die Zigaretten, die man so am Tag raucht. Ich habe ein Grid verwendet, um auch die vorigen Tage anzuzeigen, um eventuell einen Trend zu erkennen.

Die "App" funktioniert mit Android 2.3 aber auch mit dem aktuellsten Android 4.4 Kitkat.

Screenshot

Hier ein Screenshot:

image

Projekturl: https://bitbucket.org/schipplock/smokecounter/

Wie gesagt: nur ein Experiment, aber ich nutze diese App tatsaechlich :P.

Verfasst am 13.04.2014 (Permalink).

PHP Micro Frameworks

Im Bereich der Softwareentwicklung gibt es immer Menschen, die es sich zur Aufgabe gemacht haben Funktionalitäten bestehender Frameworks zu kopieren, um das dann als eigene Kreation zu verkaufen. In der Regel behaupte ich dann, dass soetwas unsinnig ist, weil das Framework erprobt ist, aber es gibt Ausnahmen, wie e.g. nur einen bestimmten Teil für einen ganz bestimmten Zweck zu kopieren.

Ich persönlich finde Symfony für PHP am besten, weil es eine sinnvolle Zusammenstellung von erprobten Komponenten ist; es zwingt den Entwickler außerdem in einen eng geschnittenen Anzug, was letztendlich die Qualität steigert.

Für bestimmte Zwecke aber ist Symfony viel zu fett. Ich hatte ja bereits über die Micro-Service-Architecture geschrieben. Dafür würde ich Symfony nicht einsetzen.

Ich habe mir diesbezüglich eine Übersicht über aktuell verfügbare Microframeworks gemacht.

Alle gelisteten Frameworks benötigen mindestens PHP 5.3, welches am 29. Juni 2009 veröffentlich wurde. Wenn dein Webhoster oder Serverbetreiber der Meinung ist, dass das nicht möglich ist, unterstelle ihm technische Inkompetenz und wechsel. Alles vor PHP 5.3 ist eine Zumutung für jeden professionellen PHP Entwickler.

Silex Micro PHP Framework

Silex ist ein Micro Framework von Sensiolabs.

Beispiel:

// web/index.php
require_once __DIR__.'/../vendor/autoload.php';

$app = new Silex\Application();

$app->get('/hello/{name}', function ($name) use ($app) {
    return 'Hello '.$app->escape($name);
});

$app->run();

Silex ist sehr gut dokumentiert; im Grunde genau so gut wie Symfony auch; was vielleicht daran liegt, dass Symfony auch von Sensiolabs kommt. Sylex ist entpackt ca. 1.2MB groß. Das klingt zwar viel für "micro", aber Silex bietet trotz der "micro" Bezeichnung viel.

  • Twig
  • URL Generator
  • Session
  • Validator
  • Form
  • HTTP Cache
  • HTTP Fragments
  • Security
  • Remember Me
  • Swiftmailer
  • Monolog
  • Translation
  • Serializer
  • Doctrine
  • Controllers as Services

Wenn man vieles davon nicht benötigt, muss man es ja nicht benutzen.

http://silex.sensiolabs.org

Slim Micro PHP Framework

Slim kenne ich schon seit einigen Jahren; anfangs war es noch recht simpel; mittlerweile kann es fuer "slim" schon recht viel.

Beispiel:

<?php
$app = new \Slim\Slim();
$app->get('/hello/:name', function ($name) {
    echo "Hello, $name";
});
$app->run();

Hier einige Features:

  • Powerful router

    • Standard and custom HTTP methods
    • Route parameters with wildcards and conditions
    • Route redirect, halt, and pass
    • Route middleware
  • Template rendering with custom views

  • Flash messages

  • Secure cookies with AES-256 encryption

  • HTTP caching

  • Logging with custom log writers

  • Error handling and debugging

  • Middleware and hook architecture Simple configuration

    Slim ist entpackt ca. 200kByte groß.

http://www.slimframework.com/

Flight Micro PHP Framework

Flight wirbt damit erweiterbar zu sein und grundlegende Funktionen bietet es bereits von Haus aus. Man muss immer vorsichtig sein, wenn ein Framework damit wirbt "erweiterbar" zu sein, denn eigentlich ist das Standard. Hier wird oft damit geworben, um zu vertuschen, dass die Basis nicht komplett ist. Das soll aber kein Vorwurf sein; Flight konzentriert sich darauf "micro" zu sein; das ist ja auch der eigentliche Sinn. Es bietet HTTP Caching; ein ganz wichtiges Feature.

Beispiel:

require 'flight/Flight.php';

Flight::route('/', function(){
        echo 'hello world!';
});

Flight::start();

Flight ist entpackt ca. 52kByte groß.

http://flightphp.com/

Jolt Micro PHP Framework

Jolt sieht aus wie viele anderen Micro Frameworks auch.

Beispiel:

<?php
$app = new \Jolt\Jolt();
$app->get('/hello/:name', function ($name) use ($app) {
    echo "Hello, $name";
});
$app->listen();

Jolt ist entpackt ca. 43kByte groß.

http://joltframework.com/

Hydra Micro PHP Framework

Hydra macht einen sehr guten Eindruck.

Beispiel:

$app->route('GET', 'hello/%name', function($name) {
    return "Hello, $name!";
});

Hydra ist entpackt ca. 180kByte groß.

https://github.com/sandulungu/hydra

Dispatch Micro PHP Framework

Dieses Framework liste ich nur auf, weil mir die häufige Verwendung von anonymen Funktionen, oder auch Closures genannt, aufgefallen ist. Außerdem ist es wirklich klein.

Beispiel:

// get route for /
on('GET', '/', function () {
    echo "hello, world!\n";
});

// get route for /index
on('GET', '/index', function () {
    echo "hello, world!\n";
});

// support the route for multiple methods
on(['GET', 'POST'], '/greet', function () {
    echo "hello, world!\n";
});

// handle any method
on('*', '/multi', function () {
    echo "it works!\n";
});

Dispatch besteht aus exakt einer Datei und ist entpackt ca. 26kByte groß.

Interessant ist auch die Beschreibung des Authors:

Dispatch is another PHP micro-framework. It's very small and very simple to use. No classes, no namespaces.

Dispatch ist gut dokumentiert, klein, einfach zu deployen und einfach zu nutzen. Meiner Meinung nach eignet es sich am besten für eine Micro-Service-Architektur.

http://noodlehaus.github.io/dispatch/

Verfasst am 06.04.2014 (Permalink).

GNU Assembler unter Linux x86

Puh! Es sind bestimmt schon mehr als 10 Jahre vergangen, als ich zuletzt Assembler Code geschrieben habe. Das war damals noch unter Windows NT4 und auch wenn ich bestimmte Dinge hinbekommen habe, habe ich doch fast alles wieder vergessen.

Aber heute ist ja Sonntag und weil ich mittlerweile viel mit Linux mache, schaute ich mir mal an, wie man so Assembler für Linux x86 schreibt. Vieles hatte ich zwar vergessen, aber sieht man es dann wieder, erinnert man sich doch wieder etwas.

Ich nutze dafür Debian 7.4 amd64 mit GNU assembler 2.22.

Ein erstes Programm

Das erste Programm ruft einfach nur den Systembefehl "exit" auf.

exit.s

.section .data

.section .text
.globl _start

_start:
    mov $1, %rax        # prepare to call exit
    mov $0, %rbx        # tell to exit with status code 0
    int $0x80           # interrupt and do the system call

Erstellen der ausführbaren Datei

as exit.s -o exit.o
ld exit.o -o exit

Man hat danach eine Datei "exit"; die man ausführen kann:

./exit
echo $?

"echo $?" gibt den Exitcode aus. In diesem Fall "0".

Ein zweites Programm

Das folgende Programm beinhaltet eine Liste mit Zahlen und gibt am Ende die höchste Zahl als Exit Code aus. Dieses Programm beinhaltet einen Loop.

maximum.s

#VARIABLES: the registers have the following uses:
#
# %edi - Holds the index of the data item being examined
# %ebx - Largest data item found
# %eax - Current data item
#
# The following memory locations are used:
#
# data_items - contains the item data. A 0 is used
#              to terminate the data
#

.section .data

data_items:
  # each of these take up 4 storage locations
  # means: 56 bytes
  .long 3,67,34,222,45,75,54,34,44,33,22,11,66,0

.section .text

.globl _start

_start:
  movl $0, %edi                   # move 0 into the index register
  movl data_items(,%edi,4), %eax  # load the first byte of data
  movl %eax, %ebx                 # move the value from %eax to %ebx

start_loop:
  # if %eax contains 0 jump to loop_exit
  cmpl $0, %eax                   # compare, put result in status register
  je loop_exit                    # both values are the same? -> loop_exit
  incl %edi                       # increment our index in %edi
  movl data_items(,%edi,4), %eax  # ...and load the next value
  cmpl %ebx, %eax                 # compare values
  jle start_loop                  # jump to start_loop if lower or equal
  movl %eax, %ebx                 # value in %eax is > %ebx, so overwrite
  jmp start_loop                  # jump to loop start

loop_exit:
  movl $1, %eax                   # exit system call
  int $0x80                       # %ebx contains the largest number

Die Kommentare erklären es im Grunde. Wichtig zu wissen ist, dass "je", "jle" immer den zweiten Wert vergleichen.

Folgender Befehl:

cmpl %ebx, %eax
jle start_loop

bedeutet: vergleiche (cmpl (compare long)) den Wert aus %ebx mit dem Wert aus %eax. Springe zu "start_loop", wenn der Wert aus %eax kleiner oder gleich dem Wert aus %ebx ist. Das hatte mich am Anfang etwas verwirrt.

Erstellen der ausführbaren Datei

as maximum.s -o maximum.o
ld maximum.o -o maximum

Man hat danach eine Datei "maximum"; die man ausführen kann:

./maximum
echo $?

"echo $?" gibt den Exitcode aus. In diesem Fall "222", weil das die höchste Zahl in data_items ist.

Das war es auch schon :). Ich werde weiter mit GNU assembler experimentieren, um so Performanceoptimierungen besser verstehen zu können.

Verfasst am 30.03.2014 (Permalink).

OpenShift von Redhat

OpenShift(.com) ist eine PaaS (Platform as a service) von Redhat und man kann dort innerhalb von Minuten eine PHP, Ruby on Rails, Node.js, Django, Java (und viele mehr) App deployen.

OpenShift reiht sich ein in die vielen Dienste der Cloudanbieter und ist eigentlich eine ganz passable und vor allem günstige Möglichkeit für Startups, die sich anfangs nur auf die Entwicklung konzentrieren möchten.

Wie funktioniert das bei OpenShift?

Im Grunde ist es ganz einfach. Man muss sich dort registrieren und bezahlt erst mal rein gar nichts. Man muss auch keine Kreditkarteninformationen hinterlegen.

Man kann über das Webinterface eine Applikation erstellen. Beim Erstellen muss man festlegen, welchen Typ von Applikation man erstellen möchte. Man hat hier die Wahl zwischen ganzen Applikationen wie e.g. Wordpress, Drupal oder aber PHP 5.3, PHP 5.4, Ruby 1.9, Ruby 1.8, Ruby on Rails, Node.js, Django, Go (ja, das Go von Google!), Perl!, Jboss, Tomcat usw...

Man muss sich also bei der Erstellung der Applikation für eine Technologie entscheiden. Wenn man e.g. Wordpress wählt, entscheidet man sich für PHP. Im Grunde sind diese "Typen" von Applikation wie e.g. Wordpress nur "Leckerbissen" für die User, die tatsächlich nur ihr Wordpress Blog in der Cloud hosten wollen.

Man wählt also e.g. PHP 5.4 und dann wird man gefragt welchen Namen die Applikation haben und in welchem Namespace diese "gespeichert" werden soll.

Im eigentlichen Sinne definiert man da aber nur den "Link", über den man die Applikation im Internet erreicht. Man bekommt also e.g. eine Url in der Form von "bar-foo.rhcloud.com" zur Verfügung gestellt.

Man kann bei der Erstellung der Applikation auch angeben, wie viele "Gears" diese Anwendung benötigt. "Gear" ist in diesem Kontext eine erfundene Einheit von Openshift, mit der die Leistungsfähigkeit bestimmt wird. Hat man lediglich den "Free"-Plan, so kann man hier gar nichts auswählen, sondern ist auf "Small" limitiert, was 512 MB Ram und 1GB Speicher beinhaltet. Zur tatsächlichen Prozessorleistung wird keine Aussage getroffen.

Man kann im "Free"-Plan aber angeben, ob die Applikation automatisch skalieren soll oder nicht. Es skaliert dann im "Free"-Plan immer nur bis zu 3 Gears, da man mehr nicht zur Verfügung hat.

Small Gears haben 512MB Ram, Medium Gears 1GB, Large Gears 2GB.

Hat man nun die Qual der Wahl getroffen, erstellt man die Applikation. Das dauert insgesamt keine 5 Minuten und die Applikation ist ready for the rumble.

Und wie bekomme ich die Daten auf den "Server"?

Ist die Applikation einmal erstellt, wird man auch direkt damit konfrontiert, wie man die Dateien auf den "Server" bekommt. Man benötigt dafür "git" und man muss initial das automatisch erstellte Repository der Applikation clonen. Man macht dann Änderungen und committed. Danach stehen die Änderungen sofort zur Verfügung. Die Art und Weise ist für mich erst einmal eigenwillig, weil es den Anschein macht, dass man für jede Änderung einen Commit machen muss. Im Entwicklungsprozess macht man aber viele Änderungen.

Aber ich denke, dass das so nicht gemeint ist. Eine der Vorteile bei Openshift ist ja, dass man nicht auf ein bestimmtes API beschränkt ist (wie bei Google App Engine e.g.); das heißt, dass man die Applikation lokal erst einmal implementieren und testen sollte. Dieses "committen", damit die Änderungen auf dem OpenShift System zur Verfügung stehen, sollte einfach Bestandteil vom Deployment sein. Es gibt bei Openshift ein Tool, dass man sich lokal installieren kann; es heißt "rhc"; mit diesem Tool kann man viele Schritte vereinfachen und auch Backups der Applikation machen und wieder einspielen. Ich vermute, dass hier die Versionierung kein unwichtiger Bestandteil ist.

Wie auch immer: man sollte OpenShift auf jeden Fall nicht als Entwicklungsumgebung betrachten, da man ja durch den fehlenden "lock-in" auch wunderbar lokal entwickeln kann und sollte (Debugger einrichten ist dann viel einfacher (bei PHP)).

Man richtet sich also für das Projekt ein separates Repository ein, welches man nicht auf OpenShift hostet. In dieses Repository committed man, wie gewohnt, seine Änderungen, nachdem man sie getestet hat.

Hat man dann ein entsprechendes Feature entwickelt, einen Bug gefixt oder aber einen Milestone erreicht, so kann man dann gerne nach OpenShift "committen" und pushen.

Auch Datenbanken?

Eine Applikation nutzt ja in der Regel auch Datenbanken. Man kann nach Erstellung der Applikation bei Openshift jeder Applikation eine Datenbank hinzufügen. Man hat die Auswahl zwischen MySQL, Postgresql und auch MongoDB. Das war es dann aber auch schon. Das Hinfügen ist mit einem Mausklick passiert und sofort einsatzbereit. Es wird auch kein weiterer Gear berechnet. Von den kostenlosen 3 hat man dann also immer noch 2 übrig. Der Nachteil ist, dass man bei den Datenbanken nicht wie bei den Applikationen entscheiden kann, ob man etwas mehr Leistung braucht oder nicht. Ich kann mir vorstellen, dass das für einige Projekte eine kritische Sache sein kann.

Aber aus Sicht eines Startups ist das erst mal irrelevant. Wenn man will, kann man ja immer noch den Service von AWS (Amazon) in Anspruch nehmen; dort kann man auch leistungsfähige MySQL-Datenbanken zur Verfügung stellen; dies aber zu einem deutlich höherem Preis.

Fazit

Ich persönlich finde dieses Produkt recht interessant, weil es kleinen Startups die Möglichkeit bietet für absolut wenig Geld (oder gar kostenlos) ein Produkt zu "starten", ohne sich mit Serveradministration oder gar Deployment auseinanderzusetzen. Wächst das Produkt mit der Zeit, so kann man bei Openshift ohne administrativen Aufwand die Gears erhöhen und so über die Runden kommen.

Meine einzige Kritik gilt den Datenbanken, da man hier nicht wirklich die Kontrolle über die Performance und der Leistungsfähigkeit hat. Das könnte ein Nadelöhr werden, dass man dann so einfach nicht gelöst bekommt, da man die Daten im schlimmsten Fall auf einen anderen Server mit leistungsfähigerem MySQL migrieren muss.

Ein anderer Punkt ist die Latenz. Mir ist aufgefallen, dass die Latenz der Server von hier aus (Deutschland->NRW) deutlich hinter denen von Amazon EC2 (und von mir aus S3) liegt. Meine persönliche Seite, die hauptsächlich statisch ist, braucht hier bei OpenShift fast 1 Sekunde, um ausgeliefert zu werden. Bei Amazon S3 ist es doppelt so schnell. Das muss man bedenken und unbedingt auch testen. Wenn das Produkt nicht für diesen Markt hier optimiert ist, macht es für Applikationen, die hier verwendet werden sollen, eventuell keinen Sinn.

Ich werde es weiter testen und vielleicht auch mal wieder berichten.

Verfasst am 22.03.2014 (Permalink).

Micro Service Architecture sinnvoll?

Es ist schon sehr lange her, als ich mal "geblogged" habe, aber aus aktuellem Anlass fühle ich mich wieder dazu verpflichtet, mal wieder etwas zu schreiben.

Es geht um das Thema Micro Service Architecture in Webapplikationen.

Skalierbarkeit

Wenn man sich darüber Gedanken macht, wie man eine Webapplikation entwickelt, so sollte man an einen Punkt gelangen, wo man sich Gedanken über die Skalierbarkeit dieser macht. Oft wird das vernachlässigt, aber es kann sich lohnen diese Probleme schon vorab zu lösen.

Man muss damit rechnen, dass die Webapplikation früher oder später nicht mehr nur auf einem einzigen Server läuft, weil die Serverlast zu hoch ist und die Anwendung zu langsam reagiert. Nun könnte man vermuten, dass man einfach mehr Server kauft / mietet und das Problem ist gelöst. Damit liegt man aber völlig falsch.

Eine Webapplikation hat in der Regel irgendeine Art von Datenspeicher, wie e.g. eine Datenbank (MySQL, Oracle, DB2, Postgresql usw...), verschiedenste Services wie e.g. User, News, Bilder Upload usw...

Hierbei gibt es verschiedene Probleme, die entstehen können. Der Bilder-Upload-Service ist ein gutes Beispiel, um zu zeigen, dass hier auch ein Lastproblem unabhängig vom Datenspeicher entstehen kann. So ein Bilder-Upload-Service verarbeitet Bilder und skaliert sie; hierbei ist zu erwarten, dass ein Lastproblem entsteht, sofern viele User Bilder hochladen.

Man hat also irgendwann die Situation, in der dieser Bilder-Upload-Service die CPU und Ram-Ressourcen des Servers zu stark auslastet und alle anderen Services ebenso darunter leiden und für den User entsteht eine Experience, die so nicht gewollt ist (lange Ladezeiten e.g.).

Die erste Idee dieses Problem zu lösen könnte sein den Prozess "skalieren" so zu optimieren, dass die Last verringert wird. Diese Lösung ist aber nur temporär und vielleicht nicht zielführend.

Der nächste Schritt wird sein, einen weiteren Server zu kaufen / mieten, um so die Last auf diesen Server zu verteilen. Mit "pound", einem reverse-Proxy, kann man das auch relativ leicht umsetzen. Man definiert für diesen Service ein Pattern, so dass die Requests zum neuen Server "geleitet" werden.

Man könnte einen Schritt weiter gehen und diesen zusätzlichen Server automatisiert in der "Cloud" erstellen, um so eine temporäre Lastspitze zu vermeiden oder zu bekämpfen, aber das ist hier nicht das Thema.

Man hat also nun 2 Server, um die Last durch den Bilder-Upload-Service zu verteilen. So weit so gut!

Wohin mit den Daten?!

Doch hat man nun ein anderes Problem: wo wird das skalierte Bild abgelegt? Hat man seine Applikation von Anfang an nicht darauf hin optimiert, so hat man nun ein Problem, denn diese beiden Server haben jeweils eigene Datenspeicher / Festplatten, die man nun synchronisieren muss oder anders ausgedrückt: man muss dieses skalierte Bild den entsprechenden Services zur Verfuegung stellen.

Die Cloud ist eine Lösung

Ein günstiger Ansatz ist es sich auf Cloud-Dienste zu verlassen. Mit dem Amazon SDK kann man e.g. S3 nutzen. Der Bilder Upload Service nutzt also als Datenspeicher Amazon S3 und in der Datenbank werden dann nur die Keys der Dateien gespeichert. Der entsprechende "Endpunkt" und das Bucket bei Amazon S3 ist dann ja bekannt und kann von allen Servern "global" genutzt werden.

Positiv bei dieser Lösung ist, dass man Bilder auch weltweit mit guter Anbindung im jeweiligen Land zur Verfügung stellen kann. Das mag aber für viele Projekte kein Argument sein.

Das Hauptargument dafür ist tatsächlich die einfache Handhabung. Alternativ müsste man ein performantes Storage kaufen / mieten, auf das alle Server die Daten ablegen oder man entwickelt ein komplexes und vermutlich fehleranfälliges System, um die Dateien zu synchronisieren. Kluge Menschen denken jetzt bestimmt an "rsync" und meinen, dass das alles ganz einfach ist, aber aus Erfahrung kann ich berichten, dass rsync mit vielen Dateien auch sehr langsam wird. Das macht ab einer bestimmten Datenmenge keinen Sinn mehr.

Negativ ist bei der Lösung, dass man Bilder bei Amazon ablegt und es gibt auch keine Garantie dafür, dass die Dateien da auch sicher sind (im Sinne von Datenverlust bei Hardwarefehler).

Man sollte also unbedingt per Projekt abwägen, ob die Daten überhaupt bei Amazon S3 liegen dürfen.

Möchte man vermeiden, dass Dateien verloren gehen, so sollte man sie mindestens an einem weiteren "Ort" speichern, aber nicht darauf zugreifen.

Dazu gibt es e.g. die Möglichkeit bei Amazon S3 die Dateien in verschiedene Regionen abzulegen. Wenn man das SDK benutzt, wird man damit konfrontiert und wird sich in der Regel fuer EU entscheiden, aber ist man ängstlich, läd man die gleiche Datei auch in eine weitere Region. Das verhindert bei einem Ausfall einer bestimmten Region den totalen Verlust dieser Datei. Wenn man schlau ist, weicht man per Software einfach auf die andere Region aus und muss so bei Ausfall nicht mal eingreifen.

Man kann natürlich auch als Fallback die Bilder nach Microsoft Azure, Google Drive, und keine Ahnung hochladen.

Man kann also ohne eigenen Hardwareaufwand seine Dateien relativ einfach und sicher verteilen, so dass höchstens bei einem Weltuntergang Datenverlust besteht.

Man sollte aber immer abwägen, wie sehr man die Daten verteilen muss.

Ich persönlich würde meine Bilder in 2 Amazon Regionen verteilen und zusätzlich auf dem Backupspeicher meines Serverproviders. Im Falle eines Ausfalls einer Amazon S3 Region könnte ich sehr leicht zu der anderen Region wechseln. Ist auch diese Region betroffen, würde ich einen Mehraufwand haben, da ich dann die Dateien aus dem Backup anderweitig zur Verfügung stellen müsste.

DBMS Cluster Funktionalität

Nun hat man diesen Fall vermutlich abgedeckt, jedoch hat man nun noch das Problem mit der Datenbank. Die meisten Webapplikationen machen Gebrauch von relationalen Datenbanken. Hier ist es wichtig vorab zu wissen, ob das DBMS eine gute Clusterfunktion unterstützt. Ich erwähne es, weil es tatsächlich DBMS gibt, die mit "cluster" werben, es aber eigentlich nicht gut unterstützen. Ein Negativbeispiel ist e.g. H2; es ist zwar eine Clusterfunktion gegeben, aber sinnvoll nur mit maximal 2 Servern.

Bei MySQL und Postgresql kann man mittlerweile einfach davon ausgehen, dass das gut funktioniert.

NOSQL ist mit Bedacht zu wählen

Aber viele Projekte nutzen mittlerweile auch NOSQL-Systeme wie e.g. redis und da ist die Clusterfunktion noch in der Entwicklung. Aktuell könnte man also bei der Wahl solcher Systeme tatsächlich in eine Falle geraten, aber bei redis ist das nur halb so wild, weil es einfach rasend schnell ist, aber man sollte zumindest mal daran gedacht haben, bevor man es verwendet.

Micro Services im Detail

Nun wollte ich ja eigentlich über Micro Service Architecture schreiben.

Bei der Micro Service Architecture hat man kleine Services, die eine bestimmte Funktion abbilden. Diese Services müssen beliebig oft auf verschiedenen Servern gestartet werden, um so jegliche Last verteilen zu können. Das Limit ist die Anzahl der Server und nicht der Service an sich oder gar ein einzelner Server. Hat man so eine Abhängigkeit, ist das problematisch für die Zukunft.

Der Nachteil bei der Micro Service Architecture ist die Kommunikation zwischen den einzelnen Services. Es ist zwar richtig, dass jeder Service nur eine bestimmte Funktion abbildet, aber jeder Service muss auch in irgendeiner Form die Funktionalität der anderen Services nutzen können.

Als Beispiel nenne ich einen Session-Service. Dieser Service kümmert sich um alles, was mit "sessions" zu tun hat. Dieser Service wird bei Applikationen, in denen sich User "anmelden", vermutlich häufig frequentiert sein. Dieser Service muss demnach auch von anderen Services genutzt werden, um e.g. zu entscheiden, ob ein User eingelogged ist oder nicht.

Man muss also irgendeine Art der Kommunikation zwischen den Services implementieren und hier wird es dann interessant.

Ich hatte damit mal experimentiert und meine erste Idee war Informationen zwischen den Services via JSON auszutauschen. Ich habe also zwei Services, die über HTTP JSON Inhalte austauschen. Jeder Service hat eine fest definierte und dokumentierte Schnittstelle und ist somit auch sehr gut testbar, aber problematisch bei dieser Idee ist HTTP. Tausche ich Daten über HTTP aus, entsteht ein Zeitaufwand, der sich mit der Anzahl der Services und der "Austausch"-Vorgänge multipliziert. Kurz gesagt: die Kommunikation über HTTP ist "teuer". Man hat initial auch einen Mehraufwand, weil man sich mehr Gedanken über die Schnittstellen machen muss, denn um das Gesamtsystem zu testen, muss man es auch "deployen" und alles muss zusammenspielen.

Ich hatte dann etwas im Netz recherchiert und man machte mich auf "protobuf" von Google aufmerksam; das hatte sich zwar alles ganz gut gelesen, passt aber nicht wirklich in diesen Kontext hinein, da es weiteren Aufwand erfordert, diese binären Protobuf-Dateien zu transportieren.

Meine letzte Idee war weiterhin HTTP zu benutzen, aber in Form von "websockets". Websockets bieten eigentlich alles, was man fuer Micro-Services benoetigt, um Informationen auszutauschen. Gemeint ist hier aber die Verwendung von Websockets auf reiner "serverside"-Ebene; nicht die Umsetzung im Webbrowser. Mit Jetty hat man einen websocket-Server als auch einen Client. Man kann das also direkt im Service implementieren und nutzen. Mehr Gedanken hatte ich mir aber noch nicht gemacht; ich werde aber in Zukunft damit experimentieren und meine Erfahrungen hier niederschreiben.

Hiermit habe ich auch verraten, womit ich micro-Services umsetzen wuerde: mit Jetty. Wenn man jetty embedded kommt man mit den notwendigen Modulen auf etwa 1.5MB pro *.jar Archiv.

Jetty ist vielfach erprobt und die Entwicklung ist durch die Eclipse Foundation gesichert. Jetty ist mit einer der schnellsten httpd, die es gibt. Jetty bietet viele "servlet" Funktionen, die man vielleicht nicht benötigt, aber das stellt kein Problem dar, da Jetty modular ist und man entsprechende Teile einfach weglassen kann.

Fazit

Mein Fazit zum Thema Micro Service Architecture ist dementsprechend ganz gut. Man kann damit skalierbare, abgetrennte und sichere Webapplikationen entwickeln. Man kann einzelne Services von verschiedenen Teams entwickeln lassen. Man kann sogar verschiedene Technologien einsetzen, denn http und websockets sind Schnittstellen, die auch von node.js, dart, go, clojure etc...bedient werden können. Diese Art von Architektur bietet also eine hohe Flexibilät.

Als Nachteil sehe ich trotzdem die Kommunikation zwischen den Services. Und letztendlich muss man diese Services ja auch irgendwie "verdrahten"; sie müssen korrekt miteinander funktionieren.

Negativ ist also eindeutig die Kommunikation und die Abstimmung. Im positiven Sinne muss man hier auch viel dokumentieren, da jeder micro-Service eine bestimmte Schnittstelle (API) zur Verfügung stellen muss.

Ich bin gespannt, ob ich das Problem mit der Kommunikation zwischen den Services mit Websockets gelöst bekomme.

M.f.G.
Andreas.

Verfasst am 16.03.2014 (Permalink).