Wer Microservices richtig macht, braucht keine Workflow Engine und kein BPMN

9 Kommentare

Bernd Rücker und Daniel Meyer schreiben im Fazit von „Wie lässt sich Ordnung in einen Haufen (Micro)Services bringen“, dass

gerade in einer Microservices-Architektur eine Workflow-Engine und BPMN einen festen Platz haben sollten.

Das ist eine pauschale Aussage. Man kann das zwar machen, aber es ist für mich alles andere als eine logische Konsequenz, so wie die Autoren es darstellen. Es ist ein Trade-Off, der einem wieder Nachteile einhandelt, die die wesentlichen Vorteile von Microservices zunichte machen können.
So, wie die beiden Microservices verstehen und darstellen, kommt man fast nicht umhin, ihnen Recht zu geben. Ich nehme mir jetzt mal den Geschäftsprozess aus obigem Artikel und zeige, wie man den mit Microservices so implementiert, dass sie wirklich Sinn machen. Und dann können wir am Ende die beiden Lösungen vergleichen.

Der Bestellprozess in einer Microservice-Architektur

Grundsätzlich sehe ich es auch so, dass Microservices möglichst asynchron kommunizieren sollten. Das Mittel der Wahl sollten aber nicht zielgerichtete Messages (Service A schickt eine Nachricht speziell an Service B), sondern Events ohne explizites Ziel sein. Services registrieren sich für Events, stoßen dann eine Verarbeitung an und erzeugen danach wieder ein Event. Service A weiß gar nicht, dass Service B existiert. Die Events müssen natürlich persistiert werden, damit Events im Sinne von Event Sourcing auch nachverarbeitet werden können. Soviel zur Theorie, schauen wir jetzt mal auf das BPMN-Diagramm des Geschäftsprozesses, den wir umsetzen wollen (ein Klick auf die Graphik vergrößert sie):
 
meyer_bpm_2
 
Ein typischer vereinfachter Bestellprozess. Das folgende Diagramm zeigt die Microservices des Gesamtsystems zusammen mit den Event-Typen, die geschrieben werden, für eine Umsetzung ohne Workflow Engine. Die Pfeile mit durchgezogenen Linien bedeuten dabei, dass ein Service ein Event schreibt, die Pfeile mit den dünnen gestrichelten Linien bedeuten, dass ein Service sich für das Event registriert hat. Zusätzlich dazu gibt es noch die dick gestrichelten Linien, die synchrone Aufrufe von der Benutzeroberfläche darstellen. Ein Klick auf die Graphik vergrößert sie.
 
BPMNVsMicroservices
 
Um das prinzipielle Vorgehen zu verdeutlichen, beschreibe ich im Folgenden zwei ausgewählte Services. Wer sich für weitere Details interessiert: die anderen Services und Events werden am Ende des Artikels im Anhang beleuchtet.

  • BestellEingangService. Wird synchron vom Kunden aufgerufen und hat im Wesentlichen die Aufgabe, eine eindeutige ID der Bestellung zu erzeugen, die im gesamten System verwendet wird. Schreibt die Bestellung dann mit erzeugter ID in ein BestellungErzeugtEvent.
    BPMNVsMicroservices_BestellEingangService
  • WarenReservierungService. Dieser Service horcht auf BestellungErzeugtEvents und versucht dann, die bestellten Waren zu reservieren. Gelingt das, wird ein WarenReserviertEvent verschickt. Gelingt das nicht, wird ein WarenNichtReserviertEvent verschickt. Außerdem horcht dieser Service auf BestellungAbgebrochenEvents. Wurden die Waren für eine abgebrochene Bestellung bereits reserviert, so wird diese Reservierung gelöscht. Ansonsten merkt sich der Service, dass eine Bestellung mit der übergebenen ID abgebrochen wurde und verhindert das Reservieren der Ware, wenn ein BestellungErzeugtEvent mit der gleichen ID nachträglich noch hereinkommt.BPMNVsMicroservices_WarenReservierungService

Vergleich mit Lösungen aus Bernds und Daniels Artikel

Asynchrone Microservices mit Punkt-zu-Punkt-Verbindungen

Die erste, auf asynchronen Microservices basierende Lösung in Bernds und Daniels Artikel geht davon aus, dass wir Punkt-zu-Punkt-Verbindungen über Queues realisieren. Die Nachteile, die die beiden aufzählen, greifen dann auch. In meiner obigen, Event-basierten Lösung greifen sie nicht. Ich gehe sie mal der Reihe nach durch.

Punkt-zu-Punkt-Verbindungen

Bernd und Daniel bemängeln, dass in ihrer Lösung jeder Service den nächsten Schritt kennen muss, damit die Nachricht in die passende Queue zugestellt wird. Bei mir ist diese Kopplung nicht vorhanden.

Keine Lösung für Reihenfolge, gegenseitigen Ausschluss, Synchronisation und Timeouts

Hier geht es in unserem Fall um die Problematik des Bestellabbruchs. Bernd und Daniel schlagen vor, eine Kompensationsnachricht zu schicken, die jeder Service weiterreichen muss – hängt mit der Fehlannahme der Punkt-zu-Punkt-Verbindungen zusammen. Im Event-basierten System gibt es einen BestellAbbruchService, der auf Events horcht, die einen Bestellabbruch auslösen, und schreibt dann ein BestellungAbgebrochenEvent. In diesem steht natürlich auch die eindeutige ID der Bestellung. Alle Services, die das interessiert, weil sie eventuell Kompensation machen müssen, horchen auf dieses Event. Falls sie in ihrem Datenbestand noch keine Bestellung mit der ID haben, speichern sie trotzdem, dass die Bestellung abgebrochen wurde. Für den Fall, dass ein Event hereinkommt, bei dem der Service eigentlich aktiv werden würde, wird dann einfach nichts gemacht. Reihenfolge, Ausschluss und Synchronisation sind kein Problem.
Timeouts innerhalb eines Services sind auch kein Problem. In unserem Fall kann der GeldeinzugService die zwei Tage auf das ZahlungsdatenGeändertEvent warten und entsprechend aktiv werden, wenn es kommt, oder wenn es nach zwei Tagen nicht gekommen ist.

Fehlender Zustand einer Bestellung

Prinzipiell richtig, die einzelnen Microservices haben die Datenhoheit auf ihren Daten, und ein Weg, um den Zustand einer Bestellung zu erfahren, wäre, alle Services zu fragen. Ich würde da aber eher einen BestellStatusService schreiben, der alle Events zum Bestellprozess abonniert und die Daten bei sich dupliziert. Er hat keine Hoheit auf den Daten, er sammelt nur. Das ist auch für die Performance einer GUI besser. Für die Frage, ob eine Bestellung storniert werden kann, ist so ein BestellStatusService aber gar nicht notwendig, da reicht ein viel schlankerer StornierungService, der nur VersandVorbereitetEvents abonniert.
Wenn man darauf reagieren muss, wenn Bestellungen zu lang in einem Zustand verweilen (warum auch immer das passieren kann), kann man kleine, unabhängige Microservices bauen, die bestimmte Zustandsübergänge überwachen. Ein Service könnte beispielsweise BestellungErzeugtEvents, WarenReserviertEvents und WarenNichtReserviertEvents abonnieren. Immer, wenn nach einem BestellungErzeugtEvent eine Zeit X kein zugehöriges WarenReserviertEvent oder WarenNichtReserviertEvent kommt, löst der Service ein Alarm-Event aus. Darauf könnte dann wiederum ein NachrichtenService für Sachbearbeiter oder eventuell der BestellAbbruchService reagieren.

Steigende Komplexität

Ja, in der Realität sind viel mehr Services beteiligt, und da den Überblick zu behalten, ist eine Herausforderung. Ein BPMN-Diagramm, das genau so ausgeführt ist, ist eine perfekte Dokumentation, das ist charmant. Auch ein BPMN-Diagramm wird mit steigender Komplexität größer und größer, vor allem, wenn Fehlerbehandlungen und Asynchronität auch komplett abgebildet sind. Meine (wenigen) Erfahrungen mit BPMN sagen mir, dass diese Diagramme für Entwickler da sind und Sourcecode darstellen. Die Wartbarkeit leidet mit der Größe, dann muss man modularisieren mit Subprozessen, hat eventuell auch nicht mehr den guten Überblick. Für Diskussionen mit Fachbereichen muss man sie eh stark vereinfachen. Ich will damit nur sagen, dass die Welt der BPMN-Diagramme auch nicht so heil ist, wie sie vielleicht manchmal vermittelt wird.
In der Event-basierten Lösung ist es wichtig zu wissen, welche Services es gibt, welche Events sie auslösen und welche sie abonnieren. So eine Landkarte, vergleichbar mit einer Context Map aus DDD, kann automatisiert aus dem bestehenden System erstellt werden. Ein BPMN-Diagramm wird dagegen im Voraus erstellt und enthält zusätzliche Fachlichkeit, die im Event-basierten System den Services zugeordnet ist. Hier sehen wir schon die unterschiedlichen Denkweisen, die dahinter stehen, und wir kommen zum Thema Trade-Offs, auf das ich später noch eingehen möchte.

Microservices orchestriert durch eine Workflow Engine

Die Variante, die Bernd und Daniel empfehlen, beinhaltet einen Microservice, der die Workflow Engine und den ausführbaren Prozess enthält, und viele weitere Microservices, die die Fachlichkeit ausführen. Standardmäßig würden die Service-Aufrufe synchron durchgeführt (beispielsweise über eine REST-Schnittstelle), aber am Ende bringen die beiden noch die Variante der External Tasks ins Spiel, bei der sich Services Tasks zur Verarbeitung abholen können, wenn sie es wollen.
Dass man das so machen kann, steht außer Frage. Es steht auch außer Frage, dass es in einem bestimmten Kontext genau das richtige Vorgehen sein kann. Man kann darüber diskutieren, ob das am Ende tatsächlich eine Microservices-Architektur ist, aber auch das ist am Ende nur eine Spitzfindigkeit bei der Namensgebung, weil ja eigentlich nur zählt, dass man die richtige Lösung für das Problem findet, und nicht, wie die Lösung nun heißt. Kommen wir also nun zu den Trade-Offs, die ich schon mehrmals erwähnt habe.
 
Mit einer Microservices-Architektur möchte ich schnell werden. Ich will schnell neue Features in Produktion bringen.
Wie mache ich das?

  • Ich habe Full-Stack-Teams, die sich auf eine bestimmte Fachlichkeit konzentrieren können.
  • Ich minimiere Abstimmungsbedarf, indem ich die Laufzeit entkopple und synchrone Schnittstellen vermeide -> jeder kann in Produktion gehen, wann er will.
  • Ich minimiere Abstimmungsbedarf für Schnittstellen, indem ich Punkt-zu-Punkt-Verbindungen vermeide und Schnittstellen abwärtskompatibel mache. Wenn im BestellungErzeugtEvent alle relevanten Daten enthalten sind, die der BestellEingangService zu bieten hat, ist es seltener notwendig, dass jemand Anforderungen an den BestellEingangService stellt. Natürlich kann man den Abstimmungsbedarf nie auf Null senken.
  • Jeder Service hat die Hoheit über seine Daten, kann die speichern, wie er will, und verarbeiten, wie er will. Das minimiert Wartezeit und ebenfalls Abstimmungsbedarf.

Warum ist ein zentraler Prozess-Microservice ein Problem?
Der zentrale Prozess-Microservice wird zum Engpass.

  • Organisatorische Unklarheit. Das Team, das diesen Microservice betreut, implementiert Fachlichkeit aus verschiedensten Verantwortlichkeiten (und ja, ein BPMN-Modell beinhaltet Fachlichkeit, in unserem Beispiel mindestens die Wartezeit für die Zahlungsdatenänderung).
  • Änderbarkeit des Gesamtsystems. Sagen wir, der Marketing-Vorstand stürmt morgens das Büro und sagt, dass der Kunde aber unbedingt benachrichtigt werden muss, wenn die Zahlung erfolgreich ist. Das ist in meinem System eine lokale Änderung. Der KundenPostfachService muss GeldEingezogenEvents abonnieren und eine Nachricht an den Kunden schreiben. Es ist tatsächlich realistisch, das nachmittags in Produktion zu haben. Da die Events persistiert werden, können wir das sogar noch für x Tage nachfahren und nachträglich Nachrichten schreiben. Wenn eine neue Version des zentralen BPMN-Prozesses erzeugt und getestet werden muss, zusätzlich zu den Änderungen am PostfachService, ist man sicher nicht nachmittags in Produktion. Dafür sind zu viele Personengruppen und Verantwortlichkeiten beteiligt.
  • Datenhaltung. Welche Daten werden im Prozess gehalten? Alle für den Prozess relevanten Daten? Dann degenerieren die anderen Microservices zu zustandslosen SOA-Komponenten. Die Datenhaltung im Prozess ist dabei vermutlich generisch, es gibt keine Wahlmöglichkeit, Daten so zu speichern, wie es optimal wäre. Werden die Daten nicht im Prozess gehalten, sondern nur IDs weitergereicht, müssen die Microservices selbst aktiv weitere Microservices aufrufen, um sich die Daten zusammenzusammeln. Sehr wahrscheinlich muss das synchron geschehen und sorgt wieder für eine höhere Kopplung im Gesamtsystem. Ein Dilemma.

Fazit

Geschäftsprozesse sind immer da, ob man sie nun explizit macht mit BPMN oder implizit im Code. Workflow Engines und BPMN haben den Charme, dass der Prozess als ausführbares Diagramm in seiner Gesamtheit visualisiert wird und man genau sehen kann, was wann passiert. Gleichzeitig wird dieses ausführbare Diagramm zum Engpass und zur Herausforderung für die Änderbarkeit des Gesamtsystems.

Microservices haben das Ziel, die Änderbarkeit des Gesamtsystems zu optimieren. Man will möglichst schnell neue Features in Produktion geben. Ein zentraler BPMN-Service verringert die Änderbarkeit des Gesamtsystems wieder. Wenn aber die gute Änderbarkeit gar nicht benötigt wird, wird unter Umständen auch gar keine Microservices-Architektur benötigt.

Was ist uns also wichtiger? Zentrale Kontrolle oder Änderbarkeit? Beides können wir nicht optimieren. Diese Frage lässt sich nur Fall für Fall klären und hat viel mit der Mentalität und Organisationsstruktur des Unternehmens zu tun.
Die Aussage, dass eine Workflow Engine zu jeder Microservices-Architektur dazugehören sollte, ist auf keinen Fall richtig.

Anhang

Der Vollständigkeit halber hier die noch fehlenden Service-Beschreibungen.

  • GeldeinzugService. Dieser Service horcht auf WarenReserviertEvents und versucht dann, Geld einzuziehen. Gelingt das, wird ein GeldEingezogenEvent geschrieben, gelingt das nicht, wird zunächst ein GeldeinzugFehlgeschlagenEvent geschrieben. Folgt in den nächsten zwei Tagen kein ZahlungsdatenGeändertEvent, das die Bestellung betrifft, wird ein GeldeinzugNichtMöglichEvent geschrieben. Folgt ein passendes ZahlungsdatenGeändertEvent, so wird wieder versucht, das Geld einzuziehen und mit dem Ergebnis wie oben beschrieben umgegangen. Außerdem horcht dieser Service auf BestellungAbgebrochenEvents. Falls das Geld bereits eingezogen wurde, wird es zurückgebucht. Falls es noch keinen Eintrag zur Bestellungs-ID gibt, so merkt sich der Service die ID, damit zukünftig hereinkommende Events mit dieser ID nicht zu einem Geldeinzug führen.BPMNVsMicroservices_GeldeinzugService
  • VersandVorbereitungService. Dieser Service horcht auf GeldEingezogenEvents, bereitet den Versand vor und feuert abschließend ein VersandVorbereitetEvent. Außerdem horcht dieser Service auf BestellungAbgebrochenEvents, um bei zukünftig hereinkommenden Events mit der Bestellungs-ID die Versandvorbereitung gar nicht erst zu starten.BPMNVsMicroservices_VersandVorbereitungService
  • StornierungService. Horcht auf VersandVorbereitetEvents, um eine Stornierung direkt zu verhindern, wenn der Versand einer Bestellung bereits vorbereitet wurde. Hat eine synchrone Schnittstelle für das Auslösen einer Stornierung, die bei erlaubter Stornierung ein BestellungStorniertEvent schreibt. BPMNVsMicroservices_StornierungService
  • BestellAbbruchService. Horcht auf BestellungStorniertEvents, WarenNichtReserviertEvents und GeldeinzugNichtMöglichEvents und feuert jeweils ein BestellungAbgebrochenEvent. Denkbar ist hier auch eine synchrone Schnittstelle für Sachbearbeiter.BPMNVsMicroservices_BestellAbbruchService
  • KundenPostfachService. Horcht auf GeldeinzugFehlgeschlagenEvents und stellt dem Kunden eine Nachricht ins Postfach, die ihn darauf hinweist, innerhalb von zwei Tagen seine Zahlungsdaten zu korrigieren.BPMNVsMicroservices_KundenPostfachService
  • ZahlungsdatenService. Hat eine synchrone Schnittstelle für den Kunden, der hier Daten ändern und ansehen kann. Bei Datenänderung wird ein ZahlungsdatenGeändertEvent gefeuert. BPMNVsMicroservices_ZahlungsdatenService
  • BestellStatusService. Dieser Service horcht auf alle Events, die für den Bestellprozess relevant sind, und bereitet die Daten in einer eigenen Datenhaltung so auf, dass sie optimal von der GUI verwendet werden können. Es wird immer nur lesend auf die Daten zugegriffen. Natürlich könnte die GUI sich die Informationen auch bei allen Microservices einzeln zusammensammeln, dieser Service ist also streng genommen nicht notwendig. Das Horchen auf Events ist für diesen Service der Übersicht halber im Diagramm nicht dargestellt. BPMNVsMicroservices_BestellStatusService
Tobias Flohre

Tobias Flohre arbeitet als Senior-Softwareentwickler/Architekt bei der codecentric AG. Seine Schwerpunkte sind Java-Enterprise-Anwendungen und Architekturen mit JEE/Spring. Er ist Autor diverser Artikel und schreibt regelmäßig Blogbeiträge zu den Themen Architektur und Spring. Zurzeit beschäftigt er sich mit Integrations- und Batch-Themen im Großunternehmen sowie mit modernen Webarchitekturen.

Share on FacebookGoogle+Share on LinkedInTweet about this on TwitterShare on RedditDigg thisShare on StumbleUpon

Kommentare

  • 16. September 2015 von Daniel Meyer

    Hallo Tobias,

    Danke für den sehr interessanten Beitrag zu dieser Diskussion.

    Erstmal ist natürlich komplett klar wieso wir (Bernd und ich) solche Artikel schreiben: wir bauen seit Jahren Open Source BPM Engines. Wir haben das bei 100en von Kunden erfolgreich eingesetzt, in unterschiedlichsten Szenarien. In sofern ist klar dass wir BPM / BPMN /Workflow usw. dann auch gut finden! Wir machen vielleicht eine etwas pauschale Aussage in dem Artikel und machen uns damit auch angreifbar.

    Deinen Post finde ich sehr spannend und ich stimme mit Dir bei vielen Punkten überein. Ich finde zum Beispiel gut und wichtig (endlich sagt das mal jemand! dass Du den Fakt hervorhebst, dass Microservices eine eigene Datenhaltung haben sollten und dort genau die Daten halten sollen die sie benötigen um zu funktionieren. Ich habe zuviel frustrierende Zeit verbracht mit „Enterprise Architekten“ zu diskutieren die in einem SOA Kontext sagen: „Die Kundendaten dürfen aber nur an einer Stelle gespeichert werden und müssen als WS bereitgestellt werden.“. Ich: „Und wenn ich dann im meiner UI Kunden und Bestellungen zusammen-joinen will um eine Liste anzuzeigen?“ Er: „dann kannst Du ja für jede Bestellung Dir die Kundendaten vom Kundenservice holen“. Ich: „Bitte erschießt mich jemand, jetzt!“

    Ich glaube in dem SOA Kontext wurde viel Schaden angerichtet. Das Buch „Event Driven Architecture“ [1] (das einige Jahre vor dem Microservices Hype) herauskam benutzt die Metapher der „Spilled Milk“ dafür. Das Buch ist super (Du kennst es sicher) und beschreibt genau die Muster der Event Driven Enterprise Architecture die Du in deinem Post vorstellst. Diese Muster sind natürlich viel älter als der Microservices Hype und immer noch anwendbar. (Und werden es auch sein wenn Microservices total out sind). Das Gleiche gilt für Workflow / und Business Process Management. In dem SOA Kontext haben auch viele Leute schlechte Erfahrungen mit schlechten BPM Produkten gemacht. BPM wurde auch oft einfach „by default“ eingesetzt („weil es ja dazugehört“ HAHA) ohne zu schauen ob es in dem aktuellen Projekt tatsächlich Probleme löst. Ja da wurde auch viel „Milch verschüttet“. Die Autoren des EDA Buches sagen aber auch: „We often tell our children: ‚Don’t cry over spilled milk‘. In enterprise architecture, we should take that sentiment to heart.“

    Mit dem Abschnitt „Warum ist ein zentraler Prozess-Microservice ein Problem?“ habe ich natürlich ein Problem. Was Du dort schreibst kann ich nicht gelten lassen Du argumentierst dort dass der BPMN Prozess zum „Engpass“ wird. Du führst dann 3 Argument ins Feld:

    1) *Organisatorische Unklarheit*
    Wenn ich dich hier richtig verstehe, geht es Dir darum dass ja auch der BPMN Prozess von jemandem bzw. einem Team „geowned“ wird. Allerdings würde der BPMN Prozess ja Fachlichkeit aus unterschiedlichen Bereichen enthalten. Deshalb wäre das jetzt organisatorisch „unklar“. In BPM gibt es dafür eine klare Verantwortung und eine klare Rolle. Diese Rolle ist der „Process Owner“ (kann auch ein Team sein.). Der Process Owner verantwortet den Prozess (oder Teile) End-To-End. Also „Order to Cash“ und ist dafür verantwortlich dass „Das Ganze“ am Ende zusammenpasst. Gerade bei komplexen Kernprozessen von denen der Unternehmenserfolg abhängt (Beispiel: Online Bestellung bei Zalando) ist sowas ziemlich wichtig und eine Rolle mit hoher Verantwortung. Klar muss dann in Projekten entschieden werden „was gehört in den Prozess“ und was nicht. Oder in anderen Worten „was wird vom Process Owner verantwortet und was nicht“. Du schreibst „in unserem Beispiel mindestens die Wartezeit für die Zahlungsdatenänderung“. Das ist kein Problem: wenn der Process Owner sagt: „das muss ich nicht verantworten“, dann wird daraus ein Message Event und ein Microservice schickt eine Nachricht wenn seiner Meinung nach diese Zeit abgelaufen ist. Fazit ist aber: BPM gibt Dir die Möglichkeit diese Rolle der Prozessverantwortung zu haben und sie auch wirklich zu leben. Weil: der sichtbare Prozess ist der implementierte Prozess. Der von Dir unterstellte Bug ist ein Feature das man nutzen sollte wenn man es braucht

    2) „Änderbarkeit des Gesamtsystems“
    Hier kann ich etwas kürzer antworten: Wieso denn nicht? nur weil ich einen Prozess habe der gewisse Aspekte der Bestellabwicklung regelt (also die Aspekte die vom Process Owner verantwortet werden), heißt das ja nicht dass ich nicht auch andere Aspekte „am Prozess vorbei (und damit am Process Owner vorbei) regeln kann“. Ich kann Workflow und EDA wunderbar kombinieren. Idealerweise ist eine Workflow Engine einer von vielen Teilnehmern in einer EDA. Aber auch hier ist die Frage nicht OB ich BPM mache sondern WAS ich mit BPM mache. Im Minimalfall tackst Du nur den Zustand / Lifecycle der Bestellung und feuerst Events wenn dieser sich ändert. Du rufst nicht explizit Aktionen auf die gemacht werden müssen. ABER: du gibst den Dingen eine Reihenfolge und definierst gegenseitigen Ausschluss, Synchronisation zwischen Events usw…

    3) „Datenhaltung“
    Hier kann ich auch knapp antworten: Nein das ist ein explizites Antipattern dort alle fachlichen Daten durch den Prozess zu schleifen. Die Idee ist nur die Daten zu übermitteln die Du in deinem Beispiel als Payload der Events hat. Die Services besitzen ihre eigenen Daten, die Daten die sie zum Arbeiten brauchen.

    Noch einen Satz zu dem Abschnitt „Steigende Komplexität“. Natürlich ist ein komplexes System komplex, ob du nun EDA + Workflow machst oder nur EDA. Das Argument „Irgendwann wird der Prozess dann zu komplex ihn aufzumalen“ ist, naja, etwas widersinnig in sich selbst. Wenn die Realität so komplex wird dass man sie lieber nicht mehr aufmalt… dann haben wir in der Tat ein Problem, mit oder ohne BPMN 🙂 Allerdings glaube ich auch hier dass ein Missverständnis vorliegt: nicht alles was im Kontext einen Prozesses passiert muss notwendigerweise ausmodelliert werden: wie ich versucht habe Oben zu erklären: in den Prozess gehören nur die Aspekte die wirklich Prozess Aspekte sind.

    Diese Kommentare sollen nicht drüber hinwegtäuschen dass mir der Artikel sehr gut gefällt. Du redest immer von Trade off, da muss ich immer nicken. Allerdings sind BPM und EDA keine sich ausschließenden Alternativen.
    Ich finde Du solltest Workflow Engines doch nochmal eine Chance geben. Ich glaube gerade in einer EDA können sie sehr hilfreich sein und fokussiert Probleme lösen.

    Grüße,
    Daniel Meyer

    [1]: https://books.google.de/books?id=g1318W0CIm4C&printsec=frontcover&hl=de#v=onepage&q&f=false

    • Tobias Flohre

      18. September 2015 von Tobias Flohre

      Hallo Daniel,

      danke für den Kommentar. Wie Du schon erkannt hast, hat mich hauptsächlich die pauschale (angreifbare) Aussage in Kombination mit der vorgestellten suboptimalen Microservices-Architektur gestört. Deine inhaltlichen Anmerkungen lass ich mal so stehen, da kann sich der Leser dann seine eigenen Gedanken zu machen ;-). Und keine Angst, wenn ich ein konkretes Architekturproblem vor mir habe, gebe ich sicher auch Workflow Engines eine Chance, man sollte kein Werkzeug von vornherein ausschließen. Ob ich das dann nachher Microservices-Architektur nennen kann, steht auf einem anderen Blatt, ist aber für die konkrete Problemlösung ziemlich irrelevant.

      Man sieht sich sicher bald mal auf irgendeiner Konferenz,
      Grüße,
      Tobias

  • 17. September 2015 von Andreas Lichtenstein

    Hi Tobias,

    sehr inspirierender Artikel und letztendlich geht es auch um die Granularität eines (Micro)Services. Da wurde schon viel geschrieben…

    Daniel und Bernd haben einen grobgranulareren Ansatz gewählt (wenn ich es richtig verstanden habe), Deiner ist feingranularer. Generell ist der Bestellprozess ein endlicher deterministischer Automat mit „alter Zustand -> Übergang -> neuer Zustand“. Die Zustände werden durch die Services repräsentiert, die Übergänge sind Nachrichten (letztendlich URLs). Die Namen der Übergänge sollten zum Namen des neuen Zustands passen (ReserviereWarenEvent -> WarenReservierungService (WRS) -> ZieheGeldEinEvent -> GeldEinzugService (GES)-> …)

    Für die von Dir vorgeschlagene Entkopplung der Services benötigen wir dann aber eine Art Broker bei denen sich die Services für bestimmte Events registrieren (Observer/Observable Pattern?). Das heißt alle Services müssen ihre Events zu diesen Brokern senden (ist das so richtig?). Damit werden diese aber zu neuralgischen Punkten hinsichtlich Last und Verfügbarkeit und müssen entsprechend ausgelegt werden. Fällt einer aus steigt die Last bei den anderen stark an. Das LoadBalancing müsste ebenfalls vom Broker übernommen werden. Damit haben diese Broker sehr viele systemkritische Aufgaben.

    An dieser Stelle würde ich daher eine Punkt-zu-Punkt Architektur favorisieren. Der Grundgedanke ist das sich die Services

    1. bei einer Registry mit Ihrer ServiceID (z.B. WarenReservierungService) und einer EventID (z.B. http://{WarenReservierungService}/ReserviereWarenEvent) registrieren
    2. Die Registry erstellt für jede ServiceID eine Liste aller EventIDs (Ausfallsicherheit)
    3. Die Clients machen das LoadBalancing clientseitig anhand der EventID-Liste aus der Registry

    Dazu können wir die netflix Bibliotheken nutzen:

    + Service Discovery (Eureka-Server*) -> Registry für Services. Mappt ServiceIDs auf URLs (Events)
    + REST Client (Feign*)
    + Circuit Breaker (Hystrix*)
    + Client Side Load Balancer (Ribbon*) Stellt Eureka-Clients LoadBalancing Strategien zur Verfügung

    *Werden alle im Spring-Cloud-Netflix-Projekt bereitgestellt

    Ich orientiere mich immer gerne an der Arbeitsweise von Menschen. Wenn ich ein Formular bearbeite und es weiterreiche kann ich es natürlich in eine zentrale Ablage legen und das war’s. Wenn aber nun niemand das Formular abholt gibt es ein Problem. Daher bringe ich das Formular lieber zum nächsten Mitarbeiter und wenn dieser überlastet ist dann zu einem anderen. Damit stelle ich sicher, das das Formular weiterverarbeitet wird. Wenn kein Mitarbeiter erreichbar ist eskaliere ich.

    Die Stornierung einer Bestellung sollte imho ( bin mir hier nicht ganz sicher 🙂 ) in genau umgekehrter Reihenfolge das System durchlaufen wegen der Abhängigkeiten (Rollback: Versand -> Geldeinzug -> Warenreservierung). Dafür würde ich *StornoEvents und *StornoService vor schlagen (z.B. WarenReservierungStornoEvent -> WarenReservierungsStornoService -> BestellungErzeugtStornoEvent -> BestellungErzeugtStornoService -> …). Damit steigt zwar die Anzahl der Events und Services dafür haben wir ein klares Single-Responsibility-Prinzip. Der StornierungsService sendet einen VersandVorbereitenStornoEvent immer an den VersandVorbereitenService damit sichergestellt ist das die Tür zu ist 🙂 dann geht’s die ganze Kette rückwärts.

    Wie wir jetzt sehen haben wir eine Menge von Services und irgendwie muss ich noch mal darüber nachdenken ob das jetzt nicht zu feingranular ist… Obwohl es heißt ja MicroService und nicht Service 🙂 … Ob ich nun alle diese Services über Spring Boot starte oder vielleicht nur einen BestellService mit AKKA implementiere und den Ablauf ( Da ist er der Workflow! Gruß an Daniel & Bernd ) über Aktoren steuere weiß ich noch nicht…

    Ich wollte hier auch keine fertige Lösung anbieten sondern vielmehr nur Anregungen geben wie wir alle hier … Entscheiden muss jeder alleine, das ist unser hartes Los 🙂 …

    … und bei REST bitte nicht HATEOAS vergessen…

    Viele Grüße

    Andreas

    Links:

    https://github.com/Netflix/eureka/wiki/Eureka-at-a-glance
    https://spring.io/blog/2015/01/20/microservice-registration-and-discovery-with-spring-cloud-and-netflix-s-eureka
    http://callistaenterprise.se/blogg/teknik/2015/04/10/building-microservices-with-spring-cloud-and-netflix-oss-part-1/
    http://callistaenterprise.se/blogg/teknik/2015/04/15/building-microservices-with-spring-cloud-and-netflix-oss-part-2/
    https://jaxenter.de/infrastruktur-neu-gedacht-27123

  • 3. November 2015 von Benedikt Ritter

    Hallo Tobias,

    du schreibst: “ So eine Landkarte, vergleichbar mit einer Context Map aus DDD, kann automatisiert aus dem bestehenden System erstellt werden.“

    Kannst du das bitte ein bisschen mehr erläutern? Wie wird diese Context Map erzeugt? Aus dem laufenden System? Oder aus dem Code des Systems über den Build Prozess? Gibt es dafür spezielle Tools? Hast du vielleicht sogar ein Beispiel?

    Danke!

    • Tobias Flohre

      5. November 2015 von Tobias Flohre

      Hallo Bene,

      ja, das ist etwas lapidar daher gesagt, das gebe ich zu. Die Kommunikation zwischen Microservices gehört zur Makroarchitektur, in diesem Fall ist das die Nutzung einer Eventing-Infrastruktur (beispielsweise Kafka). Ich würde da im Rahmen der Makroarchitektur bestimmen, dass die Services monitoren müssen, was sie in welche Topics schreiben und welche sie lesen. Diese Daten kann man dann zur Laufzeit abgreifen. Das sind Informationen, die nicht nur für die Landkarte wichtig sind, sondern auch allgemein fürs Monitoring.
      Konkret zur Implementierung gäbe es da unterschiedliche Möglichkeiten. Von einer eigenen Client-Bibliothek, die einen Kafka-Client wrappt über einen Agenten etc. Und die Daten selbst könnte man wie bei Hystrix über einen Stream abgreifbar machen, oder man nutzt das Metrics-System von Spring Boot etc.

  • 25. März 2016 von Kay Lerch

    Hi Tobias,

    ich habe deinen Artikel aufmerksam gelesen und wollte in diesem Kommentar eigentlich mit einigen Vorurteilen über Workflow-Engines aufräumen und eine Möglichkeit vorstellen wie Workflows mit „Microworker“ funktionieren können ohne die genannten Nachteile mit sich zu bringen. Das ist dann irgendwie etwas lang geworden, sodass ich es in einem Post verfasst habe. Bei Interesse kannst du gern lesen und darauf eingehen. Ich beziehe mich im Speziellen auf die AWS Simple Workflows (SWF), die sich wirklich großartig machen.

    https://www.linkedin.com/pulse/why-workflow-engines-should-frighten-kay-lerch

    Viele Grüße,
    Kay

    • Tobias Flohre

      5. April 2016 von Tobias Flohre

      Hallo Kay,

      danke für den Artikel, ich werde die SWFs im Hinterkopf behalten. Um es 100%ig zu verstehen, müsste ich das mal ausprobieren – dafür fehlt mir leider gerade die Zeit.

      Gruß,
      Tobias

  • 16. Oktober 2016 von Bernd Korthaus

    Hallo Tobias,

    IMHO ist der Charme der Workflow Engines, dass sie die BPMN-Notation, die auch durch die Fachabteilung und non-IT-Menschen gut verstanden wird, direkt und ohne Bruch in einen ausführenden Automaten umsetzen kann.

    Die zweite Grafik oben mit Microservices hat dagegen keine offensichtlichen Gemeinsamkeiten mehr mit der übersichtlichen BPMN-Grafik, so dass eine Aussage darüber, ob diese Sammlung von Microservices nun tatsächlich den (vereinfachten) Prozeß „Bestellung“ korrekt abbildet, nicht mehr möglich ist. Das aber ist extrem wichtig.

    Vergleiche hinken immer, aber ich hätte bei einer Sammlung von lose gekoppelten Microservices ohne jede übergeordnete Instanz das Gefühl, kleine autonome Roboter loslaufen zu lassen, die ich nicht mehr ohne weiteres „von oben“ monitoren und damit beherrschen kann. 🙂
    Eine zentral gespeicherte Liste der laufenden Prozesse in einer Tabelle dagegen gibt mir diese Kontrolle, denn ich kann dann diese Prozesse jederzeit filtern, auswerten, stoppen, einem neuen Bearbeiter zuweisen etc.

    • Tobias Flohre

      25. Oktober 2016 von Tobias Flohre

      Hallo Bernd,

      ich verstehe den Wunsch, die „Wahrheit“ auf oberster Ebene betrachten zu können, und ich behaupte ja auch nicht, dass es nicht manchmal sinnvoll ist. Bei Domänen-übergreifenden Prozessen, bei denen unterschiedlichste Abteilungen beteiligt sind, ist das aber bezüglich Änderbarkeit problematisch. Irgendwer muss den Domänen-übergreifenden Prozess pflegen, implementieren, deployen – eine eigene Abteilung, die den anderen übergeordnet ist? Ein Komitee? Und warum sollte es überhaupt notwendig sein, für Prozessverbesserungen in einer Domäne den ganzen Prozess neu zu deployen? Es ist halt nicht immer für das Geschäft das beste, wenn es eine zentrale Kontrolle gibt und lokale Optimierungen erschwert werden. Monitoren und beherrschen (a.k.a. Kontrolle) sind übrigens zwei sehr verschiedene Dinge. Und die Art der manuellen Bearbeitung ist von Domäne zu Domäne sehr unterschiedlich, das in ein System zu pressen, kann auch wieder unnötige Aufwände hervorrufen.
      Und klar, da gibt es tausend Nuancen, Zwischenformen, etc. Ich hoffe aber trotzdem, dass meine Argumentation klargeworden ist.

Kommentieren

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.