Post on 16-Apr-2017
@johanjanssen42#VoxxedBerlin
Advanced Akka featuresMartin Kanters, Info Support
Johan Janssen, Info Support, @johanjanssen42
Content
▪ Introduction
▪ Why Akka?
▪ Local actor
▪ Remote actor
▪ Scheduling
▪ Cluster
▪ Routing
▪ Cluster singleton
▪ Sharding
▪ Persistence
▪ Akka HTTP
▪ Finite State Machines
▪ Conclusion
▪ Questions
Introduction
Why Akka?
Why Akka?
▪ Concurrent
▪ Scalable
▪ Fault tolerant
▪ More natural programming experience when connecting to other systems
▪ Easy to use?
Local actor
Local actor
Actor on JVM 1
Local actor
Coordinator Actor
Hello conference
Local actor
Coordinator Actor
println("Hello conference")
class Worker extends Actor {def receive = {case x =>println(x)
}}
implicit val system = ActorSystem("ExampleActorSystem")
val workerActorRef = system.actorOf(Props[Worker])workerActorRef ! "Hello conference"
Scala
public class AkkaExampleJava8 extends AbstractActor {
public AkkaExample() {
receive(
match(
String.class, System.out::println
).build()
);
}
}
ActorSystem actorSystem = ActorSystem.create();
ActorRef actorRef =
actorSystem.actorOf(Props.create(AkkaExampleJava8.class));
actorRef.tell("test", ActorRef.noSender());
Java 8
Remote actor
Remote actor
Actor on JVM 1
Actor on JVM 2
val workerActorRef = system.actorOf(Props[Worker])workerActorRef ! "Hello conference"
val workerActorRef = context.actorSelection("akka.tcp://ExampleActorSystem@127.0.0.1:9005/user/workerActor")
workerActorRef ! "Hello conference"
akka {actor {provider =
"akka.remote.RemoteActorRefProvider"}remote {enabled-transports =
["akka.remote.netty.tcp"]netty.tcp {hostname = "127.0.0.1"port = 9002
Remote actor
Coordinator actor
Worker actor
StartMessage
Hello conference
Remote actor
Coordinator actor
Worker actor
WorkerMessage
Greetings from the coordinator:
Hello Conference
Remote actor
Coordinator actor
Worker actor
WorkerResponseMessage
Item processed successfully
Shared protocol
Actor on JVM 1
Actor on JVM 2
Messages
CoordinatorActor on
laptop
WorkerActor on
Raspberry PiWorkerMessage
CoordinatorActor on laptop
WorkerActor on
Raspberry Pi
MessageProtocol
SharedMessages
object SharedMessages {case class WorkerResponseMessage(body: String)case class WorkerMessage(body: String)
}
Message used by application
val workerActorRef = context.actorSelection("akka.tcp://ExampleActorSystem@127.0.0.1:9005/user/workerActor")
workerActorRef ! SharedMessages.WorkerMessage("Greetings from the coordinator: " + body)
Scheduling
Scheduling
Actor
Scheduled once after 1 second
Tick
Scheduled every 5 seconds
Tock
Scheduling
▪ Does not work for fixed point in time like 17:00– Use Quartz
Cluster
Cluster
ActorSystemon JVM 1
ActorSystemon JVM 3
ActorSystemon JVM 2
ActorSystemon JVM 4
Seed nodes
▪ Contact points for automatically joining a cluster
akka {
cluster {
seed-nodes = [
"akka.tcp://ClusterNode@127.0.0.1:2551",
"akka.tcp://ClusterNode@127.0.0.1:2552"
]
}
}
Cluster Worker Node
Port 2551
Association failed with [akka.tcp://ClusterSystem@127.0.0.1:2552
Cluster Worker Node
Port 2551
Worker Node
Port 2552
Member Up with IP: 127.0.0.1 and port: 2551Member Up with IP: 127.0.0.1 and port: 2552
Member Up with IP: 127.0.0.1 and port: 2551Member Up with IP: 127.0.0.1 and port: 2552
Cluster Worker Node
Port 2551
Worker Node
Port 2552
Member Up with IP: 127.0.0.1 and port: 2550
Member Up with IP: 127.0.0.1 and port: 2550
CoordinatorNode
Port 2550
Cluster Worker Node
Port 2551
Worker Node
Port 2552
CoordinatorNode
Port 2550
RegisterWorker
RegisterWorker
Cluster Worker Node
Port 2551
Worker Node
Port 2552
CoordinatorNode
Port 2550
Worker registered with IP: 127.0.0.1 and port: 2551Worker registered with IP: 127.0.0.1 and port: 2552
Routing
Routing
Actor on JVM 1
Actor on JVM 3
Actor on JVM 4
Actor on JVM 2
Loadbalancer
akka {actor {provider = "akka.cluster.ClusterActorRefProvider"
deployment {/coordinator/router {router = round-robin-poolnr-of-instances = 10routees.paths = ["/user/emptystringactor"]cluster {enabled = onallow-local-routees = off
}}
}}
}
Routing
CoordinatorActor on
JVM 1
EmptyStringActor on
JVM 3
EmptyStringActor on
JVM 4
EmptyStringActor on
JVM 2""
Routing
CoordinatorActor on
JVM 1
EmptyStringActor on
JVM 3
EmptyStringActor on
JVM 4
EmptyStringActor on
JVM 2""
HashMap[hostname, counter]
Routing
CoordinatorActor on
JVM 1
EmptyStringActor on
JVM 3
EmptyStringActor on
JVM 4
EmptyStringActor on
JVM 2
""
Routing
CoordinatorActor on
JVM 1
EmptyStringActor on
JVM 3
EmptyStringActor on
JVM 4
EmptyStringActor on
JVM 2
""
Cluster singleton
Cluster singleton
▪ Only one instance of the actor in the cluster
▪ (Re)created on the oldest node
▪ Can be used for instance for scheduling/caching
Cluster singleton
Actor on JVM 1
Other actors on
JVM 3
Other actors on
JVM 4
Singleton actor and
other actors on JVM 2
Cluster singleton
CoordinatorEmptyString
Actor on JVM 3
EmptyStringActor on
JVM 4
EmptyStringActor on
JVM 2""
Cluster singleton
CoordinatorEmptyString
Actor on JVM 3
EmptyStringActor on
JVM 4
EmptyStringActor on
JVM 2""
HashMap[hostname, counter]
Cluster singleton
CoordinatorEmptyString
Actor on JVM 3
EmptyStringActor on
JVM 4
EmptyStringActor on
JVM 2""
Cluster singleton
CoordinatorEmptyString
Actor on JVM 3
EmptyStringActor on
JVM 4
EmptyStringActor on
JVM 2""
HashMap[hostname, counter]
Cluster singleton
CoordinatorEmptyString
Actor on JVM 3
EmptyStringActor on
JVM 4
EmptyStringActor on
JVM 2Crash
Cluster singleton
CoordinatorEmptyString
Actor on JVM 3
EmptyStringActor on
JVM 4
""
Cluster singleton
CoordinatorEmptyString
Actor on JVM 3
EmptyStringActor on
JVM 4
""
HashMap[hostname, counter]
Cluster singleton
CoordinatorEmptyString
Actor on JVM 3
EmptyStringActor on
JVM 4
""
Cluster singleton
CoordinatorEmptyString
Actor on JVM 3
EmptyStringActor on
JVM 4
""
HashMap[hostname, counter]
Sharding
Sharding
▪ Dividing a set of actors over a cluster
▪ Actors will be divided into groups called shards
▪ It will divide based on a logical identifier
Sharding
Actor on JVM 1
oddShard on
JVM 3
evenShard on
JVM 2
0, 2, 4, 6, 8
1, 3, 5, 7, 9
Sharding method: ShardResolver
def shardResolver(numberOfShards: Int): ExtractShardId = {case i: Int => (i % numberOfShards).toString
}
Sharding method: IdExtractor
def idExtractor: ExtractEntityId = {case i: Int => (i.toString, “New message: “ + i)
}
Actual message
Persistence
Persistence
▪ Store actor information
▪ Recover after crash
▪ Possibility to take snapshots
Example without persistence
Actor
Cobol
Example without persistence
Actor
Cobol
Example without persistence
Cobol
Actor
Example without persistence
Actor
Java Cobol
Example without persistence
CobolJava
ActorCrash
Restart
Example without persistence
Actor
Example without persistence
Actor
Scala
Example without persistence
Scala
Actor
Persistence
PersistentActor
Cobol
Command
Journal
Persistence
Journal
CobolEvent
PersistentActor
Persistence
Journal
ACKPersistentActor
CobolEvent
Persistence
Cobol
Journal
CobolEvent
PersistentActor
Persistence
Cobol
Journal
CobolEvent
PersistentActor
JavaEvent
Persistence
CobolJava
Journal
CobolEvent
PersistentActorCrash
Restart JavaEvent
Persistence
Journal
CobolEvent
PersistentActor
JavaEvent
Persistence
CobolJava
Journal
CobolEvent
PersistentActor
JavaEvent
Scala
Persistence
CobolJavaScala
Journal
CobolEvent
PersistentActor
JavaEvent
Snapshots
JournalPersistentActor
Snapshot store
State until Event C++
C++
Cobol
Snapshots
JournalPersistentActor
Snapshot store
State until Event C++
C++
Cobol
Snapshots
JournalPersistentActor
Snapshot store
State until Event C++ C++
Cobol
Snapshots
JournalPersistentActor
Snapshot store
State until Event C++
JavaC++
Cobol
Snapshots
JournalPersistentActor
Snapshot store
State until Event C++
Crash
Restart
C++
Cobol
Java
Snapshots
JournalPersistentActor
Snapshot store
State until Event C++ C++
Cobol
Java
Snapshots
CobolC++
JournalPersistentActor
Snapshot store
State until Event C++ C++
Cobol
Java
Snapshots
CobolC++Java
JournalPersistentActor
Snapshot store
State until Event C++ C++
Cobol
Java
Snapshots
CobolC++JavaScala
JournalPersistentActor
Snapshot store
State until Event C++ C++
Cobol
Java
Command Query Responsibility Segregation (CQRS)
CQRS in Akka
Journal
CobolEvent
Cobol
PersistentActor
Persistence Query
Akka HTTP
Akka HTTP
Actor on JVM 1
Actor on JVM 2
Finite State Machine
Finite State Machine
▪ State
▪ Event
Finite State Machines (FSM)
InprogressProject
CrappyProject
NewProject
Progress, iterationProgress, iteration
Progress, iteration
NoProgressProgress, 2
Finite State Machines (FSM)
InprogressProject
CrappyProject
NewProject
Work harder
Iteration: 0
Finite State Machines (FSM)
InprogressProject
CrappyProject
NewProject
Good job!
Iteration: 0
Finite State Machines (FSM)
InprogressProject
CrappyProject
NewProject
Wrong direction
Iteration: 0
Finite State Machines (FSM)
InprogressProject
CrappyProject
NewProject
Use Akka
Iteration: 0
Finite State Machines (FSM)
InprogressProject
CrappyProject
NewProject
Good job!
Iteration: 1
Finite State Machines (FSM)
InprogressProject
CrappyProject
NewProject
Wrong direction
Iteration: 1
Finite State Machines (FSM)
InprogressProject
CrappyProject
NewProject
Use Akka
Iteration: 1
Finite State Machines (FSM)
InprogressProject
CrappyProject
NewProject Get another job!
Iteration: 2
Finite State Machines (FSM)
▪ Two types of events– Progress
– NoProgress
▪ All events should be handled!
▪ Integer used to count the number of iterations
▪ After two iterations a message is shown
Conclusion
Conclusion
▪ Akka can be used with Scala or Java
▪ There is even a .NET version of Akka
▪ Akka is really powerful
▪ Akka is quite easy to use
▪ Some features are still experimental
Questions
Martin Kanters and Johan Janssen @johanjanssen42GitHub: https://github.com/johanjanssen/Akka-examples