Distributed systems vs compositionality

1,330 views

Published on

Distributed systems are becoming more and more commonplace, microservices and cloud deployments force this notion into the day to day routine of many developers. One of the great features of a strongly typed language like Scala—with its expressive type system—is that we can achieve a high level of safety and confidence by letting the compiler verify that our code behaves as specified. But can this safety be carried over into the interactions between distributed parts of an application? Can we for example safely compose Actor behaviours from different pieces?

This presentation introduces some approaches to this problem, including Session Types and π-calculus, and discusses their limitations. The practical ramifications are illustrated using Akka Typed, with a preview of composable and reusable behaviors.

Published in: Technology
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,330
On SlideShare
0
From Embeds
0
Number of Embeds
236
Actions
Shares
0
Downloads
19
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Distributed systems vs compositionality

  1. 1. Distributed Systems vs. Compositionality Dr. Roland Kuhn @rolandkuhn — CTO of Actyx
  2. 2. Caveat: This presentation shows unreleased APIs!
  3. 3. Weird starting point: π calculus
  4. 4. What is a calculus? • syntax for writing down a computation • reduction rules for evaluating the syntax 4
  5. 5. π calculus: the syntax 5 Robin Milner et al, 1992 ⇡ ::= 8 >< >: x(y) receive y along x xhyi send y along x ⌧ unobservable action (1) P ::= X i2I ⇡i.Pi P1|P2 new a P !P 0 (2)
  6. 6. π calculus: the reductions 6 TAU : ⌧.P + M ! P (3) REACT : x(y).P + M xhzi.Q + N ! z/y P Q (4) PAR : P ! P0 P|Q ! P0|Q (5) RES : P ! P0 new x P ! new x P0 (6) STRUCT : P ! P0 Q ! Q0 if P ⌘ Q ^ P0 ⌘ Q0 (7) Robin Milner et al, 1992
  7. 7. An example reduction 7 P = new z ⇣ (xhyi.0 + z(w).whyi.0) x(u).uhvi.0 xhzi.0 ⌘ possibility 1 possibility 2
  8. 8. An example reduction 8 P = new z ⇣ 0 yhvi.0 xhzi.0 ⌘
  9. 9. An example reduction 9 P = new z ⇣ (xhyi.0 + z(w).whyi.0) x(u).uhvi.0 xhzi.0 ⌘ possibility 2
  10. 10. An example reduction 10 P = new z ⇣ (xhyi.0 + z(w).whyi.0) zhvi.0 0 ⌘ only one possibility
  11. 11. An example reduction 11 P = new z ⇣ vhyi.0 0 0 ⌘
  12. 12. An example reduction 12 P = vhyi.0
  13. 13. There’s more! • structural congruence allows symbolic manipulation • rename, reorder sums, expand recursion, … • bi-simulation describes functional equivalence 13
  14. 14. So, what is a calculus? • a way to write down computations • a means to reason about computations • a tool to compose computations 14
  15. 15. Composition
  16. 16. Composition in the π calculus • you can • run computations sequentially • run computations concurrently • synchronize concurrent computations 16
  17. 17. Composing processes 17 new cA ⇣ Pclient PserviceA ⌘ channel where serviceA is reachable will send to cA and eventually react to response will react to cA and eventually send back a response
  18. 18. We need protocols!
  19. 19. What is a protocol? • defines a communication discipline: • who can send what kind of message, and when • which kinds of message to expect, and when • each distributed process must adhere to the common protocol • a global protocol can be checked for safety 19
  20. 20. Session types • Session: a unit of conversation • Session Type: the structure of a conversation,
 a sequence of interactions in a
 communication-centric program model • originally only binary sessions,
 multiparty session types introduced 2008 • primitives are
 sending, receiving, sequence, choice, recursion
 
 20 http://groups.inf.ed.ac.uk/abcd/
  21. 21. Session types example 21 Sreqresp = !Request(params) . ?Response(result) Sreqresp = ?Request(params) . !Response(result)
  22. 22. But is it safe? Does it compose? 22 Pclient PserviceA PbackendA PserviceB PbackendB
  23. 23. Protocols don’t compose! • at least not in general, as far as we know • some cases are (mostly?) okay • non-cyclic • non-interacting • what a bummer!
 ⟹ let’s find a smaller problem to solve 23
  24. 24. Composing Actor Behavior
  25. 25. Behavior composition 25 new cinternal ⇣ PserviceA PclientB ⌘
  26. 26. 26 case class DoStuff(stuff: Stuff) case class DoIt(it: It) case class DoneSuccessfully(result: Result) class MyActor(receptionist: ActorRef) extends Actor { override def preStart(): Unit = receptionist ! Register def receive = initializing def initializing: Receive = { case Registered => // do stuff context.become(running) } def running: Receive = { case DoStuff(stuff) => context.actorOf(Props[Child]) ! DoIt(???) context.become(waitingForResult(stuff)) } def waitingForResult(stuff: Stuff): Receive = { case DoneSuccessfully(result) => // do stuff, e.g. replying context.become(running) } }
  27. 27. We need reusable composable behavior snippets!
  28. 28. Radical idea: π calculus within! • idea sparked while listening to Alex Prokopec • create DSL inspired by π calculus • lifted representation of asynchronous actions • combinators for sequential & parallel composition 28
  29. 29. What does it look like? 29 π calculus Akka Typed Sessions new c P val serverChannel = channel[Command](128) P initialize: Process[ActorRef[Request]] π.P for {
 backend ← initialize
 server ← register(backend)
 } yield run(server, backend) P|Q fork(task): Process[Unit]
 read(serverChannel) race timeout(1.second)
 getThingA join getThingB x(y) read(serverChannel): Process[Command] x❬y❭ serverChannel.ref ! msg
 (synchronous send operation not there, yet)
  30. 30. Example of a Server Process 30 def run(server: Channel[ServerCommand], backend: ActorRef[BackendCommand]) : Process[Nothing] = for { cmd ← read(server) } yield cmd match { case GetIt(which, replyTo) => val spinOff = talkWithBackend(which, backend) .foreach(thing => replyTo ! GotIt(thing.weird)) fork(spinOff race timeout(5.seconds)) .then(run(server, backend)) }
  31. 31. Example of a Server Process 31 def talkWithBackend(which: String, backend: ActorRef[BackendCommand]) : Process[TheThing] = { val code = channel[Code](1) val thing = channel[TheThing](1) backend ! GetThingCode(0xdeadbeefcafeL, code.ref) for { c ← readAndSeal(code) } yield { c.magicChest ! GetTheThing(which, thing.ref) readAndSeal(thing) } }
  32. 32. What does this have to do with Akka? • Akka Typed Behavior to interpret Process • channel reference is a lean child ActorRef • this closes the gap between the Actor Model and CSP/π • Actors have stable identity but only one channel • anonymous Processes have multiple channels
 (with identity) 32
  33. 33. Outlook
  34. 34. Tracking effects • lifted representation of Process allows tracking of effects • embedding of session type in π calculus exists • verify Process against a session type 34
  35. 35. Irresponsible Speculation 35 // Effects is similar to HList (but a tree) trait Process[T, E <: Effects] { def map[U, UE <: Effects](f: T => Process[U, UE]) :Process[U, UE :*: E] def join[U, UE <: Effects](p: Process[U, UE]) :Process[(T, U), UE :+: E] def race // ??? } def read[T](c: Channel[T]): Process[T, Recv[c.type]] def write[T](ref: ActorRef[T]): Process[T, Send[ref.type]] def fork[T, TE <: Effects](p: Process[T, TE]) : Process[Unit, NoEffect :|: TE]
  36. 36. Current State • behaviors can be composed both sequentially and concurrently • effects are not yet tracked • Scribble generator for Scala not yet there • theoretical work at Imperial College, London
 (Prof. Nobuko Yoshida & Alceste Scalas) 36
  37. 37. ©Actyx AG 2016 – All Rights Reserved

×