Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

EBC und Nebenläufigkeit

29 views
Skip to first unread message

Tilmann Kuhn

unread,
Dec 6, 2011, 8:49:30 PM12/6/11
to event-based...@googlegroups.com
Hi EBC-Community,

Zur Zeit entwickle ich Teile eines Servers, der RPC-Anfragen von Clients beantwortet. Teile davon habe ich mit Flow Design entworfen und mit der Übersetzung in Methoden implementiert wie von Ralf im Cheat Sheet beschrieben: http://geekswithblogs.net/theArchitectsNapkin/archive/2011/03/20/flow-design-cheat-sheet-ndash-part-ii-translation.aspx

Prinzipiell finde ich (aus verschiedenen Gründen) aber die Übersetzung in EBCs sinnvoller und wollte sie diese Woche ausprobieren, wobei mir schon bei den ersten Versuchen klar geworden ist, dass das so nicht funktionieren kann, wie ich das gerne hätte:

Das Problem, dass sich auf tut ist, dass mein Flow parallel von verschiedenen Threads angestoßen wird, was aus Performance-Gründen auch so gewollt und erforderlich ist. Die Logik in den einzelnen Funktionseinheiten ist zustandsfrei und führt daher nicht zu Schwierigkeiten. Problem sind vielmehr die Joins im Flow, da diese Zustand halten während sie auf weiteren Input warten. Und hier geht das ganze in einem nebenläufigen Szenario schief. Bei der Übersetzung nach Methoden klappt alles, da hier der Zustand auf dem Thread-Stack statt in einem Objekt gehalten wird. Bei der EBC-Variante stellt sich jetzt die Frage, wie man das in den Griff bekommen kann. Spontan sind mir folgende Varianten eingefallen, die mir alle nicht so richtig gefallen möchten:

  1. Die komplette Flow-Abarbeitung synchronisieren, so dass immer nur ein Thread gleichzeitig im Flow ist. Geht in meinem Fall aus Performance-Gründen nicht.
  2. Für jede Flow-Abarbeitung eine eigene Instanz des kompletten Flows erstellen. Will ich in meinem Fall eigentlich auch nicht machen, da der Flow, wenn er dann komplett fertig implementiert ist aus über 500 EBCs bestehen wird.
  3. Die Joins so anpassen dass sie ihren Zustand nicht in der EBC selbst, sondern assoziiert mit dem aktuell ausführenden Thread speichern (ThreadLocal Variable in Java). Daran gefällt mir nicht, dass der Zustand nicht (wie im Stack-Fall bei Methoden) automatisch beim Verlassen des Flows wieder abgebaut wird. Das kann zu Interaktionen zwischen unterschiedlichen Abarbeitungen führen, wenn einzelne Inputs noch in einem Join hängen, die aktuelle Flow-Abarbeitung allerdings beendet wurde und der Thread (der aus einem Thread-Pool stammt) den gleichen Flow für die nächste Abarbeitung durchläuft. Das könnte man umgehen, wenn alle Boards im Flow die Joins verwenden, zu Beginn ihres internen Ablaufs alle ihre Joins zurücksetzen.
Habe ich irgendwelche Möglichkeiten übersehen? Gibt es schon Erfahrungen / Best Practices im Bereich EBC mit Nebenläufigkeit?

Viele Grüße

Tilmann Kuhn

pbedat

unread,
Dec 7, 2011, 2:00:09 AM12/7/11
to Event based Components
Dazu fallen mir spontan zwei Dinge ein:

- Pipeline Modell
- Pooling

Und an Stelle der ThreadLocal Variable kannst du ja einfach eine
"CallId" in den Nachrichten Mitgeben und dann das Join selbst
entscheiden lassen,
wann ein Join vollständig ist. Führt natürlich zu einem Bottle-Neck in
den Joins.

Gruß,
Patrick


On 7 Dez., 02:49, Tilmann Kuhn <goo...@tkuhn.de> wrote:
> Hi EBC-Community,
>
> Zur Zeit entwickle ich Teile eines Servers, der RPC-Anfragen von Clients
> beantwortet. Teile davon habe ich mit Flow Design entworfen und mit der
> Übersetzung in Methoden implementiert wie von Ralf im Cheat Sheet

> beschrieben:http://geekswithblogs.net/theArchitectsNapkin/archive/2011/03/20/flow...


>
> Prinzipiell finde ich (aus verschiedenen Gründen) aber die Übersetzung in
> EBCs sinnvoller und wollte sie diese Woche ausprobieren, wobei mir schon
> bei den ersten Versuchen klar geworden ist, dass das so nicht funktionieren
> kann, wie ich das gerne hätte:
>
> Das Problem, dass sich auf tut ist, dass mein Flow parallel von
> verschiedenen Threads angestoßen wird, was aus Performance-Gründen auch so
> gewollt und erforderlich ist. Die Logik in den einzelnen Funktionseinheiten
> ist zustandsfrei und führt daher nicht zu Schwierigkeiten. Problem sind
> vielmehr die Joins im Flow, da diese Zustand halten während sie auf
> weiteren Input warten. Und hier geht das ganze in einem nebenläufigen
> Szenario schief. Bei der Übersetzung nach Methoden klappt alles, da hier
> der Zustand auf dem Thread-Stack statt in einem Objekt gehalten wird. Bei
> der EBC-Variante stellt sich jetzt die Frage, wie man das in den Griff
> bekommen kann. Spontan sind mir folgende Varianten eingefallen, die mir
> alle nicht so richtig gefallen möchten:
>

>    1. Die komplette Flow-Abarbeitung synchronisieren, so dass immer nur ein


>    Thread gleichzeitig im Flow ist. Geht in meinem Fall aus
>    Performance-Gründen nicht.

>    2. Für jede Flow-Abarbeitung eine eigene Instanz des kompletten Flows


>    erstellen. Will ich in meinem Fall eigentlich auch nicht machen, da der
>    Flow, wenn er dann komplett fertig implementiert ist aus über 500 EBCs
>    bestehen wird.

>    3. Die Joins so anpassen dass sie ihren Zustand nicht in der EBC selbst,

Ralf Westphal

unread,
Dec 7, 2011, 4:45:31 AM12/7/11
to event-based...@googlegroups.com
du kannst den flow immer wieder instanzieren, in jedem thread.

oder du kannst mit correlation ids arbeiten. das ist wahrscheinl der skalierbarere weg.
nachrichten haben dann "pro transaktion" eine corr id und werden von joins danach zusammengefasst.

--
Ralf Westphal

Tilmann Kuhn

unread,
Dec 7, 2011, 6:33:24 AM12/7/11
to event-based...@googlegroups.com
Danke für die Ideen pbedat und Ralf! Damit hätten wir also noch die Möglichkeiten (hoffe mal ich habe das richtig verstanden):

1. b) Pooling: Den Flow mehrfach instanziieren, aber die Instanzen über einen Flow-Pool verwalten.
4. Pipelining: Wenn ich das richtig verstehe meinst Du damit ein Context-Daten-Objekt zu erstellen das dann alle Daten enthält, die im kompletten flow benötigt werden, so dass schließlich ein linearer Flow ohne Abzweigungen und Joins möglich ist. Das würde natürlich als Nachteile dazu führen, dass alle Funktionseinheiten die gleichen in und out Parameter haben und der eigentliche Prozess nicht mehr ersichtlich ist. Man könnte das Pipelining aber auch immer auf einzelne Boards reduzieren, die einen Join haben, das würde das ganze etwas mildern. Dann hätte man mehrere geschachtelte Pipelines.
5. Correlation Ids/Call Ids:Das wäre eine gute Möglichkeit behebt allerdings nicht das Problem, das der Join-Zustand aufgeräumt werden muss und belastet die eigentlichen Daten-Nachrichten (oder Ids als ThreadLocal).

Nachdem ich im Zusammen hang mit 5. in Ralfs Post das wort Transaktion gelesen habe ist mir noch folgende Möglichkeit eingefallen:

6. Transaktions-Datenspeicher: Hier mappen alle Joins ihre Inputs in einem Transaktions-Speicher nach einer Id des jeweiligen Joins. Der Transaktions-Speicher kann dann entweder als Daten mitgegeben werden oder als ThreadLocal-Variable realisiert werden. Initialisierung und Zurücksetzten der Transaktion erfolgt dann zentral am Anfang des Flows.

Zu meinen Favoriten zählen nun 1.b) und 5.b)

Viele Grüße, Tilmann Kuhn

Ralf Westphal

unread,
Dec 7, 2011, 8:01:17 AM12/7/11
to event-based...@googlegroups.com
verstehe nicht, was "join zustand aufräumen" bedeutet.
--
Ralf Westphal - One Man Think Tank
Hans-Henny-Jahnn-Weg 44
D-22085 Hamburg
Germany
Tel 0170-3200458
Email in...@ralfw.de

Tilmann Kuhn

unread,
Dec 7, 2011, 8:45:57 AM12/7/11
to event-based...@googlegroups.com
Wenn ich in Joins für eine "Transaktions"-ID gemapped die Inputs speichere und der komplette Flow für diese "Transaktion" zu Ende ist, muss ich allen Joins die ich irgendwo im Flow habe mitteilen, dass die "Transaktion" mit der ID zu Ende ist und sie den für diese ID-Gespeicherten Zustand vergessen sollen. Sonst habe ich ein Memory-Leak.

Ralf Westphal

unread,
Dec 7, 2011, 9:08:18 AM12/7/11
to event-based...@googlegroups.com
naja, hängt vom join ab. bei einem "normalen" join, ja. bei einem autoreset-join, vergisst der join beide datenhälften nach dem join.


Am 7. Dezember 2011 14:45 schrieb Tilmann Kuhn <goo...@tkuhn.de>:
Wenn ich in Joins für eine "Transaktions"-ID gemapped die Inputs speichere und der komplette Flow für diese "Transaktion" zu Ende ist, muss ich allen Joins die ich irgendwo im Flow habe mitteilen, dass die "Transaktion" mit der ID zu Ende ist und sie den für diese ID-Gespeicherten Zustand vergessen sollen. Sonst habe ich ein Memory-Leak.



Mike Bild

unread,
Dec 7, 2011, 9:14:14 AM12/7/11
to Event based Components
Hallo Tilmann,
ich tendiere deshalb ebenfalls zur Instanzierung des gesamten Flows
pro Thread. (500 Frames im Stack und ein bisschen Memory - naja geht
schon ;-)) Damit entfallen Threadsychronisierungen, Sperren auf
Resourcen und das Programmiermodell ist ebenfalss einfacher. Zumal,
wie Patrick bereits schon sagte, der Engpass bei eigenen Sync/Lock-
Implementierung im Join liegen wird.
Ich hatte gerade vor kurzem ähnliche Problematik. Vielleicht helfen
dir ebenfalls nachfolgende Links. Mir ging es so.
- "Move away from Threads" -
Ein für mich brauchbares und auch gut skalierendes Konzept sind
Dispatch Queues. Dabei werden Pipelines über serielle Queues und
Thread-Joins bsw. über Grouped Dispatch Queues gelöst.
Grand Central
Dispatchhttp://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/ConcurrencyandApplicationDesign/ConcurrencyandApplicationDesign.html#//apple_ref/doc/uid/TP40008091-CH100-SW1
Ralf hatte bereits auch erste Implementierungen sequentieller/
serieller Dispatch Queues in EBC implementiert und unter
http://npantarhei.codeplex.com veröffentlicht.
Hawt Dispatchhttp://hawtdispatch.fusesource.org/
CCRhttp://msdn.microsoft.com/en-us/library/bb648752.aspx
TPL Dataflowhttp://msdn.microsoft.com/en-us/devlabs/gg585582
- "Scale-Out vs. Scale-Up"-
Ebenfalls denkbar, in der Anwendung jedoch weiter abstrahiert und mit
Implikationen zur Architektur (vs. RPC), ist das Aktor-Modell wie es
aus Scala und Erlang bekannt ist. In einem Aktor wird der Flow nicht
von einer Task Queue abgearbeitet, sondern er empfängt Nachrichten in
eine Queue (Mailbox) und arbeitet diese sequentiell ab. Joins können
dort sehr einfach über CorrelationId gemacht werden. Da Aktoren per
Design keine Resourcen teilen und ausschließlich über Nachrichten der
Queue arbeiten, skalieren sie horizontal (scale out statt threads mit
scale up) sehr gut.
Viele Grüße,Mike

On 7 Dez., 02:49, Tilmann Kuhn <goo...@tkuhn.de> wrote:
> Hi EBC-Community,
>
> Zur Zeit entwickle ich Teile eines Servers, der RPC-Anfragen von Clients
> beantwortet. Teile davon habe ich mit Flow Design entworfen und mit der
> Übersetzung in Methoden implementiert wie von Ralf im Cheat Sheet
> beschrieben:http://geekswithblogs.net/theArchitectsNapkin/archive/2011/03/20/flow...

>
> Prinzipiell finde ich (aus verschiedenen Gründen) aber die Übersetzung in
> EBCs sinnvoller und wollte sie diese Woche ausprobieren, wobei mir schon
> bei den ersten Versuchen klar geworden ist, dass das so nicht funktionieren
> kann, wie ich das gerne hätte:
>
> Das Problem, dass sich auf tut ist, dass mein Flow parallel von
> verschiedenen Threads angestoßen wird, was aus Performance-Gründen auch so
> gewollt und erforderlich ist. Die Logik in den einzelnen Funktionseinheiten
> ist zustandsfrei und führt daher nicht zu Schwierigkeiten. Problem sind
> vielmehr die Joins im Flow, da diese Zustand halten während sie auf
> weiteren Input warten. Und hier geht das ganze in einem nebenläufigen
> Szenario schief. Bei der Übersetzung nach Methoden klappt alles, da hier
> der Zustand auf dem Thread-Stack statt in einem Objekt gehalten wird. Bei
> der EBC-Variante stellt sich jetzt die Frage, wie man das in den Griff
> bekommen kann. Spontan sind mir folgende Varianten eingefallen, die mir
> alle nicht so richtig gefallen möchten:
>
>    1. Die komplette Flow-Abarbeitung synchronisieren, so dass immer nur ein

>    Thread gleichzeitig im Flow ist. Geht in meinem Fall aus
>    Performance-Gründen nicht.
>    2. Für jede Flow-Abarbeitung eine eigene Instanz des kompletten Flows

>    erstellen. Will ich in meinem Fall eigentlich auch nicht machen, da der
>    Flow, wenn er dann komplett fertig implementiert ist aus über 500 EBCs
>    bestehen wird.
>    3. Die Joins so anpassen dass sie ihren Zustand nicht in der EBC selbst,

Tilmann Kuhn

unread,
Dec 7, 2011, 9:41:00 AM12/7/11
to event-based...@googlegroups.com
Hey Mike, schön von Dir zu hören :)

Ich werde demnächst mal einen Spike machen bezüglich Flow neu instantiiren pro RPC-Anfrage und Performance, da doch ordentlich Last auf der Schnittstelle haben. Theoretisch besteht auch die Möglichkeit den Flow zu zerlegen und bei Bedarf Teile nachzuladen, da wähend einer Anfrage 95% des Flows ungenutzt bleiben. Das Thema wurde ja kürzlich hier diskutiert: https://groups.google.com/forum/#!topic/event-based-components/O7C7V5n-G2U

Vielen Dank auch für die weiteren Quellen, die klingen ziemlich spannend und ich werde sie mir demnächst zu Gmüte führen. Scala und sein Actor-Modell stehen ohnehin schon seit einiger Zeit auf meiner Todo-Liste ;)

Viele Grüße, Tilmann
Reply all
Reply to author
Forward
0 new messages