</TECH NEWS>
NEUESTES VON UNSEREN ENTWICKLERN:

07.12.2018 – von Linus|

PHP, Java und Self-describing Events (Teil 2)

Aufgrund historisch gewachsener Systeme und Strukturen, verwenden wir bei der SH Telekommunikation Deutschland derzeit als Haupt-Programmiersprachen PHP mit Symfony und Java mit Spring. Zudem kommt aktuell noch Typescript und Angular hinzu. Einer der Vorteile der Microservice Architektur ist, dass man die Programmiersprache je nach Einsatzzweck wählen kann. Dies führt zu der Herausforderung, Nachrichten im Kafkabus interoperabel zu serialisieren.

Dabei hilft uns Avro als Nachrichtenformat in Zusammenhang mit einer Schemaregistry. Durch das Avroformat und der Schemaregistry ist der Overhead einer Message, die durch Kafka versendet wird, verschwindend gering. Ein Schema wird zusammen mit seiner Versionsnummer einmal zentral in der Schemaregistry abgelegt und muss dadurch nicht komplett in einer Message mitgegeben werden. Jeder Consumer einer Message kann anhand des Schemanamens und dessen Version aus der Registry das Schema abrufen und so eine Message wieder deserialisieren.

Das hilft dabei die Durchsatz-Performance hochzuhalten. Zudem wird durch die Versionierung die Abwärtskompatibilität von Messages garantiert.
In Aktuellen Kafka/Avro Implementierungen wird im Normalfall pro Topic ein Schema festgelegt. Wir haben uns dazu entschieden einen anderen Ansatz zu verwenden und auf Self-describing Events zu setzen. So haben wir zwei weitere Vorteile gewonnen:

  1. Nachrichten unterschiedlichen Typs können innerhalb eines Topics verwendet werden, um unter anderem damit die korrekte Nachrichten Reihenfolge für eine Domäne zu garantieren.
  2. Die Anzahl der benötigten Topics kann deutlich minimiert werden.

In der Kommunikation zwischen PHP und Java muss zudem beachtet werden, dass beide Sprachen teils sehr unterschiedliche Auffassungen von Datentypen haben. Es muss für die Kommunikation ein einheitliches Muster gefunden werden, das beide Sprachen ohne Schwierigkeiten beherrschen. Auch müssen die “logicalTypes” von Avro in PHP selbst implementiert werden, sollten sie verwendet werden.

 

Datenformate

Datentypen

Damit sich Java und PHP verstehen, wurde sich auf folgendes Set an Datentypen und deren Maximalwerte in Messages geeinigt:

nullValue = null;

booleanValue = true;

intValue = 2.147.483.647;

longValue = (9.223.372.036.854.775.807-1)/2;

floatValue = 3.40282346638528860e+38;

doubleValue = 1.7976931348623157e+308;

byteValue = „testmessage“.getBytes();

stringValue = „testmessage“;

enumValue = Enum.ABC;

arrayValue = Arrays.asList(„test“, „message“);

mapValue = HashMap<>();

fixedValue = DigestUtils.md5Digest(„testmessage“.getBytes());

Wichtig war hier die Erkenntnis, dass Long und Integer Values in Java und PHP sehr unterschiedlich wahrgenommen werden. Somit musste hier der größte gemeinsame Nenner gefunden werden.

 

Self-describing Events

Eine Kafka Message besteht immer aus einem Key und einer Value. Bei unserem gewählten Self-describing Event Ansatz wird ein zweistufiger Serialisierungs- und Deserialisierungsprozess verwendet.

Das wird mit folgendem Beispiel verdeutlicht:

Ein Service mit dem Namen “CustomerService” stellt die Klasse “Customer” bereit und kann das Event “CustomerCreated” publizieren.

Customer

  • Id
  • Vorname
  • Nachname
  • Emailadresse

CustomerCreated (v1)

  • Key
  • Id
  • Value
  • Vorname
  • Nachname
  • Emailadresse

SelfDescribing (v1)

  • Key
  • CorrelationId
  • Value
  • Timestamp
  • Schemasubject
  • Schemaversion
  • Payload

 

Serialisierung

Schritt 1:

Zunächst wird ein neuer Kunde angelegt:

Customer

  • Id = 1
  • Vorname = Max
  • Nachname = Mustermann
  • Emailadresse = max.mustermann@email.de

Schritt 2:

Dadurch wird das Event „CustomerCreatedEvent“ serialisiert.
Der Serializer sucht dazu das passende Schema aus der Schemaregistry heraus und erzeugt den Avro Bytestream.

CustomerCreated (v1)

  • Key
  • Id = 1
  • Value
  • Vorname = Max
  • Nachname = Mustermann
  • Emailadresse = max.mustermann@email.de

Schritt 3:

Der CustomerCreated Avro Bytestream wird in den SelfDescribing Umschlag gepackt.
Der Serializer sucht dazu das passende Schema aus der Schemaregistry heraus und erzeugt den Avro Bytestream.

SelfDescribing (v1)

  • Key
  • CorrelationId = UUID
  • Value
  • Timestamp = 2018-10-05 05:38:25.123
  • Schemasubject = CustomerCreated
  • Schemaversion = v1
  • Payload = CustomerCreatedEvent Avro Bytestream

Schritt 4:

Der Kafkaproducer verschickt den Avro Bytestream in die Customer Kafkatopic.

 

Deserialisierung

Schritt 1:

Der Kafka Consumer nimmt eine neue Message aus der Customer Topic.

Schritt 2:

Der Self-describing Deserializer sucht zu der Self Describing Message das passende Schema aus der Schemaregistry heraus um den Avro Bytestream zu deserialisieren.

SelfDescribing (v1)

  • Key
  • CorrelationId = UUID
  • Value
  • Timestamp = 2018-10-05 05:38:25.123
  • Schemasubject = CustomerCreated
  • Schemaversion = v1
  • Payload = CustomerCreatedEvent Avro Bytestream

Schritt 3:

Die so ausgelesene und deserialisierte Message enthält die Informationen über Schema und Schemaversion, um die eigentliche Payload, das CustomerCreated Event zu deserialisieren.
Der Deserializer sucht in der Schemaregistry dazu das passende Schema aus und deserialisiert das CustomerCreated Event.

CustomerCreated (v1)

Aus dem nun deserialisierten CustomerCreated Event, kann sich der Service nun die Daten auslesen, die er benötigt um seine Arbeit zu erledigen.

 



WEITERE SPANNENDE BEITRÄGE



Unternehmen Marken Team Presse Karriere Tech-Blog SH Händler-Shop