JavaLand 2016 - Immer wieder gut

8 Minuten zum lesen

Die unter anderem von den deutschen Java User Groups organisierte Konferenz JavaLand hat im Jahr 2016 zum dritten mal statt gefunden. Aufgrund des frühen Termins von Ostern in diesem Jahr, fand das JavaLand bereits Anfang März statt. Die kühleren Temperaturen haben die Veranstaltung nicht geschadet.

Wie im letzten Jahr war das Konferenz Programm gefüllt mit interessanten Vorträgen. Bei den bis zu 7 parallel laufenden Tracks sind Überschneidungen nicht zu vermeiden. So habe ich versucht die für mich interessantesten Vorträge zu besuchen. Wie im letzten Jahr hier ein kurzer Bericht zu diesen Vorträgen.

Docker

Ich beschäftige mich schon länger mit Docker. Auf Konferenzen lerne ich immer wieder neue Dinge zu den verschiedenen Technologien rund um die Virtualisierung von Applicationen mit Docker kennen. Auf den Voxxed Days Anfang des Jahres in Berlin gab es z.B. Vorträge zum Thema Docker Swarm. Im Vortrag “Patterns für Docker” von Roland Huß wurde ein Aspekt beleuchtet, den ich bisher vermisst habe.

Welche wiederkehrenden Muster gibt es beim Einsatz von Docker?

Roland hat seine Erfahrungen beim Einsatz von Docker in drei Patterns zusammen gefasst:

  • Wie kann ich die Applikation in einem Container konfigurieren bzw. an die Umgebung anpassen?

  • Wie finden sich die einzelnen Services gegenseitig?

  • Wie baue ich am effizientesten Docker Images?

Zur Konfiguration von Images gibt es die Möglichkeit die einzelnen Konfigurationswerte als Environment-Variablen zu definieren. Diese Variablen können beim Bau eines Images oder beim Start eines Containers übergeben werden. Weiterhin besteht die Möglichkeit Konfigurationsdateien in einem sogenannten “Sidecar Container” zu verpacken. Dieser wird beim Starten des Container mit dem eigentlichen Container verbunden. Die letzte Möglichkeit zur Konfiguration von Container besteht durch die Nutzung von Key-Value Stores wie z.B. Zookeeper, Consul, etcd oder Redis.

Docker wird zur Realisierung von Microservice Architekturen eingesetzt. Hierzu ist es notwendig, dass sich die einzelnen Microservices gegenseitig finden können. Zur Lösung dieser Anforderung besteht die Möglichkeit die Adressen der benötigten Services über Environment-Variablen beim Starten zu “injizieren”. In umfangreicheren Installationen kommen Orchestrierungstools wie Kubernetes von Google zum Einsatz. Wie schon bei der Konfiguration können aber auch Key-Value Stores eingesetzt werden. Die einzelnen Dienste registrieren sich bei diesen Services und können umgekehrt andere registrierte Dienste abfragen. Interessant ist auch die Möglichkeit die Abfrage von Services über den guten alten DNS Dienst mittels _srv Records zu realsieren.

Aufgrund der fortgeschrittenen Zeit konnte Roland nur kurz auf die Lösungen zum effizienten Bau von Docker Images eingehen.

Über Dockerfile Templates können sehr einfach mehrere Variationen von Images erstellt werden. So kann ein und dasselbe Image z.B. mit einem JDK7 oder JDK8 erstellt werden. Mit der von Roland “Image Factory” genannten Techniken wird auf bestehende Techniken zurückgegriffen. Basierend auf einem Base Image werden die einzelnen Images automatisiert gebaut. Zum Einsatz kommen klassische Werkzeuge zum Konfigurationsmanagement wie Puppet, Chef oder Ansible. Letzteres hat den Vorteil, dass es direkt von Docker eingebunden wird.

Microservices

Gleich im Anschluss wurde das Thema “Microservices” von Lars Röwekamp intensiver besprochen. Ich habe schon einiges zu diesem Thema gelesen und gehört. Lars hat das ganze Thema sehr kompakt und anschaulich in einen Vortrag verpackt.

Wichtig finde ich den Bezug zu Domain Driven Design herzustellen. Die Sprache zur Definition der Architektur wird dabei zusammen mit den Fachleuten der Domäne erstellt. Ziel ist es eine für das Problem passende Sprache zu erstellen. Die Sprache umfasst dabei nicht die gesamte Mächtigkeit der fachlichen Domäne. Es werden nur die Aspekte berücksichtigt, die für die Lösung des fachlichen Problems notwendig sind. Das Modell der Anwendung basiert auf dieser von allen entwickelten Sprache. Ändert sich die Sprache muss sich dadurch auch das Modell ändern.

Intensiver hat sich Lars mit dem Begriff des “bounded context” beschäftigt. Diesen Kontext zu finden gehört zur Definition der Sprache. Es handelt sich dabei um einen in sich abgeschlossenen, fachlichen Bereich. Ein Context beschreibt dabei keinen “Service” sondern eher einen Use Case oder einen Business Prozess.

Abschließend hat Lars noch die Frage behandelt, wie mit den Gemeinsamkeiten von mehreren Bounded Context umgegangen wird. Kann hier ein “Haupteigner” der Daten ermittelt werden? Evtl. ist auch der Einsatz eines “shared kernel” interessant. Dieser beinhaltet die gemeinsamen Entities. Ein Microservice wird als federführend für die Entities bestimmt.

CDI 2.0

Mark Struberg und Thorben Janssen berichteten vom aktuellen Stand der Arbeiten an der neuen CDI Version 2.0. Beide gehören zur “Java EE Expert Group” und arbeiten am neuen Standard für Context und Dependency Injection mit.

Ihr Vortrag behandelte hauptsächlich die Neuerung der asynchronen Events. Neben Beispielen zur Implementierung dieser neuen Events wurde auch auf die Hintergründe der Realisierung eingegangen. Interessant waren dabei vor allem die Aspekte wie die Handhabung der Event-Objekte über mehrere Threads gehandhabt wird. Welche Objekte haben der sendende und der empfangende Teil der Event-Kommunikation gemeinsam?

Noch befindet sich bei der neuen Version von CDI wie bei allen neuen Standards für Java EE 8 alles im Fluss. Die Möglichkeiten klingen aber sehr vielversprechend und machen auf alle Fälle Lust sich möglichst bald mit der neuen Version zu beschäftigen.

Modelle der Nebenläufigkeit

Einen für mich sehr aufschlussreichen Einblick in die verschiedenen Möglichkeiten in Java mit Nebenläufigkeit umzugehen lieferte Lutz Hühnken mit seinem Vortrag “Neue JVM-Concurrency-Modelle wie Aktoren und Verticles”. Er stellte verschiedene Modelle vor, mit denen man auf einer abstrakteren Ebene als Threads und dem java.util.concurrent Package arbeiten kann.

Mit dem Modell der Fibers von Quasar lässt sich ähnlich wie mit Threads arbeiten. Fibers dienen hierbei als Abstraktion der tatsächlichen Threads. Diese haben aber keine direkte Bindung an Threads. Man bezeichnet sie als “extended” Threads oder Coroutines. Die Programmierung erfolgt weiterhin imperativ wie bei Threads auch.

Eine höhere Abstraktion bieten Channels, deren Konzept aus dem Jahr 1978 stammt. In der Programmiersprache Go ist dieses Modell fest integriert. Eine Go-Routine lauscht hierbei an einem Channel. Daten werden von anderen Routinen durch das Schreiben in den Channel übergeben. Es wird damit eine Datenfluss orientierte Programmierung realisiert. Die Daten werden hierbei im Channel und nicht im Thread gehalten.

Ein bekannter Vertreter des Modell des Event Loop stellt vert.x dar. Der Code befindet sich in Verticles. Diese kommunizieren über einen MessageBus, über den sie sich gegenseitig Event senden. Der Bus ermöglicht die Kommunikation von Verticles in einem Netzwerk. Für blockierende Aufrufe stellt vert.x sogenannte Worker Threads zur Verfügung.

Als letztes Modell stellt Lutz Actors vor, das ebenfalls aus den 70ern (1973) stammt. Weite Verbreitung findet dieses Modell durch die Programmiersprache Erlang. In der Java Welt setzt Akka dieses Modell um. Aktoren kommunizieren über Messages miteinander. Ein Supervisor überwacht alle laufenden Aktoren.

Der Vortrag hat mein Wissen zu diesem Thema wieder etwas weiter gebracht.

Java EE Connectors

Sehr inspirierend war für mich der Vortrag von David Blevins “Java EE Connectors: The Secret Weapon Reloaded”. Bisher bin ich mit Java Connectors nur selten in Berührung gekommen. Gerade bei der Anbindung von ActiveMQ an einen WildFly Application Server musste ich mich damit beschäftigen. Die API hatte aber auch bei mir den Ruf einer komplizierten Sache.

Mit der Überarbeitung der API mit Java EE 7 hat sich das aber grundlegend geändert. David zeigte in seinem Vortrag wie einfach inzwischen die Erstellung eines Connectors ist. Dadurch, dass der Connector direkten Zugriff auf die Message Driven Bean bekommt, die die vom Connector “empfangene” Nachricht verarbeiten soll, ergeben sich ungeahnte Möglichkeiten.

David stellte in seinem Vortrag verschiedene Connectoren vor. Alle nutzen ein an JAX-RS angelehntes Programmiermodell. Durch Annotationen an die Methoden einer Message Driven Bean wird festgelegt, für welche Art von Messages die Methode aufgerufen werden soll. Das Empfangen der Message übernimmt der Connector. Durch das Evaluieren der Annotationen kann er die passende Methode aufrufen.

In einer Life Demo zeigte David die Verarbeitung von E-Mails. Die Kommunikation ist aber auch über Twitter möglich. Durch die Anbindung an Google Hangouts (Jabber) konnte er mit seinem Application Server - natürlich TomEE - quasi chatten. Fehlen durfte natürlich auch nicht eine Anbindung an Slack.

Der Quellcode der von David vorgestellten Connectoren zusammen mit einer den Connector nutzenden Message Driven Bean findet sich unter https://tomitribe.io/projects/chatterbox.

Reactive Microservices

Weiter geht es mit Microservices. Jochen Mader beschrieb in seinem Vortrag “Mit Vert.x vom Monolithen zum reaktiven Microservice” die Entwicklung von Microservices.

Zu Beginn lieferte Jochen seine Definition eines Microservice. Für ihn wichtig sind die folgenden Gesichtspunkte:

  • Realisierung eines Bounded Context (Domain Driven Design)

  • jeder Microservice hat eine eigene Datenhaltung

  • Jeder Microservice wird von einem Team entwickelt

  • Das Deployment kann für jeden Microservice unabhängig stattfinden

Seiner Meinung nach sind bei der Implementierung eines verteilten Systems die folgenden Mythen zu beachten.

  • Netzwerk sind zuverlässig

  • Der Datendurchsatz eines Netzwerks ist unendlich

  • Das Netzwerk ist sicher

  • Die Latenz ist nahe 0

  • Die Netzwerktopologie ist unveränderlich

  • Es gibt nur 1 Netzwerkadministrator

  • Der Datentransport ist kostenlos

  • Das Netzwerk ist homogen

Alle diese Probleme lassen sich mit Vert.x in den Griff bekommen. Die Applikation besteht aus Verticles. Jedes Verticle läuft im (immer gleichen) Thread. Die einzelnen Verticles kommunizieren über einen Bus. Der Bus kann über das Netzwerk verteilt sein. Über einen Broadcast finden sich die Teilnehmer selbst. Durch das dynamische Hoch- und Runterfahren von weiteren Instanzen kann das System elastisch auf veränderte Last reagieren.

Gut findet Jochen, dass eine Applikation als Fat JAR verpackt und damit sehr einfach deployt werden kann. Die Erstellung des JAR erfolgt mit dem Maven Shade Plugin.

Event Sourcing

Ein Thema, das oft zusammen mit Microservices verwendet wird ist das Event Sourcing. Eine Einführung in dieses Konzept der Speicherung von Daten haben Jörg Herbst und Jan Sauer in Ihrem Vortrag gegeben.

Bei der Nutzung von Event Sourcing werden die Datensätze nicht geändert. Stattdessen werden die Ereignisse, die zur Änderung von Datensätzen / deren Zuständen führen gespeichert. Um den aktuellen Zustand zu ermitteln, müssen alle Ereignisse durchgegangen und daraus der Zustand ermittelt werden. Die Lese- und Schreiboperationen werden voneinander getrennt.

Vorteil dieser Art der Speicherung ist, dass jederzeit die Ursache für die Änderung eines Zustandes / eines Datensatzes ermittelt werden kann. Auch führen Änderungen am Datenmodell nicht zu umfangreichen Migrationen. Die Ereignisse sind weitestgehend vom Schema der Datensätze getrennt.

Zur Verarbeitung werden die Events mit den Änderungen im sogenannten EventStore gespeichert. Die Events werden aber auch auf einen EventBus veröffentlicht. Dort können EventHandler andocken und aufgrund der Ereignisse weitere Operationen durchführen. Die EventHandler bauen somit das Lesemodell auf.

Fazit

Wie bereits in den letzten beiden Jahren hat sich für mich der Besuch des JavaLand mehr als gelohnt. Ich werde auch im nächsten Jahr auf dem JavaLand sein. Dies findet vom vom 28.03. - 30.03.2017 wieder im Phantasialand in Brühl statt.