reactive applications using akka
DESCRIPTION
Basic intro to reactive applications concepts and a crash course on some of the tools Akka and some other providers give useTRANSCRIPT
[email protected] - Liferay Inc and MadridJUG
@miguelinlas3
Miguel Ángel Pastor Olivar
Reactive ApplicationsBuilding concurrent and distributed apps using Akka
Saturday, October 19, 13
Writing software for the Liferay platform team
About me
Phd student? on distributed and cloud systems
Scala enthusiast
Twitter: @miguelinlas3
Saturday, October 19, 13
Reactive apps: do we really need them?
Crash course on basic Akka concepts
Old known problems
A quick look into newer (and more fun tools)
Agenda
Saturday, October 19, 13
Applications has become extremely demanding
New kind of systems
Event driven, scalable , resilient, responsive
This is what Reactive Applications are all about
Reactive applications
Saturday, October 19, 13
BlockingCaller blocked. Wait for the results
Non blockingCaller not blocked. Need to pool
AsynchronousCaller not blocked. Select, epoll, signals
Event drivenMessage flowing through the system
Reactive applications: definitions
Saturday, October 19, 13
Basic pillars
Saturday, October 19, 13
Basic pillars
Event Driven
Saturday, October 19, 13
Basic pillars
Event Driven
Resilient
Saturday, October 19, 13
Basic pillars
Event Driven
Resilient Scalable
Saturday, October 19, 13
Basic pillars
Event Driven
Responsive
Resilient Scalable
Saturday, October 19, 13
Going event driven
Old known problems,The actor model
Saturday, October 19, 13
Going Event Driven
Saturday, October 19, 13
Going Event Driven
Shared Memory
Saturday, October 19, 13
Going Event Driven
Shared Memory
Saturday, October 19, 13
Going Event Driven
Shared Memory
Thread 1
Saturday, October 19, 13
Going Event Driven
Shared Memory
Thread 1 Thread 2
Saturday, October 19, 13
Going Event Driven
Shared Memory
Thread 1 Thread 2
Saturday, October 19, 13
Going Event Driven
Shared Memory
Thread 1 Thread 2
Saturday, October 19, 13
Going Event Driven
Shared Memory
Thread 1 Thread 2
R/W
Saturday, October 19, 13
Going Event Driven
Shared Memory
Thread 1 Thread 2
R/WR/W
Saturday, October 19, 13
Going Event Driven
Shared Memory
Thread 1 Thread 2
R/WR/W AVOID IT!!
Saturday, October 19, 13
Going event driven: problems with locks
Saturday, October 19, 13
Going event driven: problems with locks
Composition
Saturday, October 19, 13
Going event driven: problems with locks
CompositionLocks don´t compose
Saturday, October 19, 13
Going event driven: problems with locks
Composition GranularityLocks don´t compose
Saturday, October 19, 13
Going event driven: problems with locks
Composition GranularityLocks don´t compose
Have I taken too few locks? Too many?
Saturday, October 19, 13
Going event driven: problems with locks
Composition Granularity
Encapsulation
Locks don´t compose
Have I taken too few locks? Too many?
Saturday, October 19, 13
Going event driven: problems with locks
Composition Granularity
Encapsulation
Locks don´t compose
Have I taken too few locks? Too many?
Breaking abstractions
Saturday, October 19, 13
Going event driven: problems with locks
Composition Granularity
EncapsulationCorrectness
Locks don´t compose
Have I taken too few locks? Too many?
Breaking abstractions
Saturday, October 19, 13
Going event driven: problems with locks
Composition Granularity
EncapsulationCorrectness
Locks don´t compose
Have I taken too few locks? Too many?
Have I taken the correct lock?
Breaking abstractions
Saturday, October 19, 13
Going event driven: problems with locks
Composition Granularity
EncapsulationCorrectness
Ordering
Locks don´t compose
Have I taken too few locks? Too many?
Have I taken the correct lock?
Breaking abstractions
Saturday, October 19, 13
Going event driven: problems with locks
Composition Granularity
EncapsulationCorrectness
Ordering
Locks don´t compose
Have I taken too few locks? Too many?
Have I taken the correct lock?
Have I used the correct order?
Breaking abstractions
Saturday, October 19, 13
Asynchronous message/event passing
Workflow of the events through your system
Benefits:Better throughputLower latenciesLoosely coupled solutions
Going event driven: designing your system
Saturday, October 19, 13
Going event driven: Amdahl’s law
Saturday, October 19, 13
Going event driven: the actor model
Fundamental unit of computation that embodies:• Processing• Storage• Communication
Three axioms. When an Actor receives a message it can:• Create new Actors• Send messages to Actors it knows• Designate how it should handle the next message it receives
Carl Hewitt
Saturday, October 19, 13
Going event driven: the actor model
Saturday, October 19, 13
Going event driven: the actor model
Saturday, October 19, 13
Going event driven: the actor model
Saturday, October 19, 13
Going event driven: the actor model
Zero sharing
Isolated, lightweight event based processes
Communication through asynchronous message passing
Location transparent
Built-in supervision
Saturday, October 19, 13
Actor model: Define a new actor
public class MetricsProcessorActor extends UntypedActor {
public void onReceive(Object message) { if (message instanceof JVMMetric) { JVMMetric jvmMetric = (JVMMetric)message;
_dataStore.save(jvmMetric); } }
private DataStore _dataStore = new LogDataStore();}
Saturday, October 19, 13
Actor model: Creating an actor
ActorSystem _agentSystem = ActorSystem.create("AgentSystem");
ActorRef metricsActor = _agentSystem.actorOf(
new Props(new UntypedActorFactory() { @Override public Actor create() {
return new MetricsActor(metricsActor);}
}),"metricsActor");
Saturday, October 19, 13
Actor model: Getting a reference
ActorSystem _agentSystem = ActorSystem.create("AgentSystem");
ActorRef handshakeActor = _agentSystem.actorFor(
"akka://MonitoringServiceSystem@localhost:5557/user/handshakeActor");
Saturday, October 19, 13
Actor model: Sending a message
metricsActor.tell(new JVMMessage("JVM-MemoryUsage", new Date().getTime()));
Saturday, October 19, 13
Actor model: Replying to a message
public class HandshakeActor extends UntypedActor {
public void onReceive(Object message) {
if (message instanceof AuthMessage) { AuthMessage authMessage = (AuthMessage)message;
if (authMessage.getUser() == "migue" && authMessage.getCredentials() == "migue")
getSender().tell("ok"); else
getSender().tell("fail"); } else throw new IllegalStateException("Unable to handle " +
message); }}
Saturday, October 19, 13
Actor model: Switching implementation
public class MetricsProcessorActor extends UntypedActor {
public void onReceive(Object message) { if (message instanceof SwappingMessage) { getContext().become(altPersistence, false) }
} Procedure<Object> altPersistence = new Procedure<Object>() { @Override public void apply(Object message) { altDatastore.save(message); }
DataStore altDatastore = new AltDataStore();};
private DataStore _dataStore = new LogDataStore();}
Saturday, October 19, 13
Actor model: Routing
final ActorSystem monitoringServiceSystem =ActorSystem.create("MonitoringServiceSystem");
ActorRef metricsActor = monitoringServiceSystem.actorOf(
new Props(MetricsProcessorActor.class).withRouter( new RoundRobinRouter(100), "metricsActor"); }
metricsActor.tell(new JVMMessage("JVM-MemoryUsage", new Date().getTime()));
Dealing with routers does not change our code
Saturday, October 19, 13
Actor model: Configuring a router
akka { actor { deployment { /metricsActor { router = round-robin nr-of-instances = 100 } } }}
Saturday, October 19, 13
Going scalable
Distributed computing,The actor model
Saturday, October 19, 13
Going scalable: scalability
I really do have an scalability problem ...
if my system is fast for a single user but slow when the system is under heavy load
Saturday, October 19, 13
Going scalable: transparent distributed computing
Distributed shared mutable state
Distributed objects
Distributed transactions
Saturday, October 19, 13
Going scalable: transparent distributed computing
Synchronous method dispatching across the network is a bad idea
Ignores partial failures
Raises Latency
General scalability and DC concerns
Saturday, October 19, 13
Going scalable: transparent distributed computing
EMBRACE THE NETWORK!!
Saturday, October 19, 13
Going scalable: remote actors
akka { actor { deployment { /metricsActor {
remote = "akka://monitorSystem@name:5557"
} } }}
final ActorSystem monitoringServiceSystem =ActorSystem.create("MonitoringServiceSystem");
ActorRef metricsActor = monitoringServiceSystem.actorOf( new Props(MetricsProcessorActor.class), "metricsActor");
No changes are required in our existing code!!
Saturday, October 19, 13
Going resilient
Error handling
Saturday, October 19, 13
Going resilient: common problems
Single thread of control
Thread blows up --> you are screwed
Error handling within single thread
Errors don´t get propagated
Defensive programmingTangled within business logicScattered along all our codebase
Saturday, October 19, 13
Going resilient: actor topology and supervision
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B5
B6
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7
Saturday, October 19, 13
Supervision strategies: One for one
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B5
B6
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7
Saturday, October 19, 13
Supervision strategies: One for one
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B6
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7
Saturday, October 19, 13
Supervision strategies: One for one
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B6
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7
Saturday, October 19, 13
Supervision strategies: One for one
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B6
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7
Saturday, October 19, 13
Supervision strategies: One for one
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B6
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7
Saturday, October 19, 13
Supervision strategies: One for one
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B6
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7B5
Saturday, October 19, 13
Supervision strategies: One for all
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B5
B6
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7B6
B7
Saturday, October 19, 13
Supervision strategies: One for all
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B6
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7B6
B7
Saturday, October 19, 13
Supervision strategies: One for all
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B6
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7B6
B7
Saturday, October 19, 13
Supervision strategies: One for all
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B6
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7B6
B7
Saturday, October 19, 13
Supervision strategies: One for all
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B6
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7B6
B7
Saturday, October 19, 13
Supervision strategies: One for all
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B6
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7B6
B7
Saturday, October 19, 13
Supervision strategies: One for all
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B6
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7B5
B6
B7
Saturday, October 19, 13
Supervision strategies: One for all
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B6
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7B5
B6
B7
Saturday, October 19, 13
Supervision strategies: One for all
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7B5
B6
B7
Saturday, October 19, 13
Supervision strategies: One for all
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7B5
B7
Saturday, October 19, 13
Supervision strategies: One for all
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7B5
B6
B7
Saturday, October 19, 13
Supervision strategies: One for all
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
B7
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7B5
B6
B7
Saturday, October 19, 13
Supervision strategies: One for all
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7B5
B6
B7
Saturday, October 19, 13
Supervision strategies: One for all
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7B5
B6
Saturday, October 19, 13
Supervision strategies: One for all
System
A1
A2
A4
B1
B2
B4
B3
A3
/A1
/A1/A2
/A1/A2/A4
/A1/A3
/B1
/B1/B2
/B1/B2/B4
/B1/B3
/B1/B3/B5
/B1/B2/B6
/B1/B2/B7B5
B6
B7
Saturday, October 19, 13
Going resilient: configure supervision
final SupervisorStrategy supervisorStrategy = new OneForOneStrategy(
3, Duration.create(1, TimeUnit.MINUTES),new Class<?>[] {Exception.class});
_metricsActor = _cloudServiceSystem.actorOf( new Props(MetricsProcessorActor.class).
withRouter( new RoundRobinRouter(100).
withSupervisorStrategy( supervisorStrategy)),
"metricsActor");
Supervision strategies are pluggable and you can develop and configure your own
Saturday, October 19, 13
More tools
We deserve better and more fun tools
Saturday, October 19, 13
More tools: futures
•Spawn concurrent computations
•Write once - Read many
•Freely sharable
•Non-blocking composition
•Composable (monadic operations)
•Managing failure
Saturday, October 19, 13
More tools: futures
val f: Future[List[String]] = future { session.getRecentPosts}
// handle both cases: Success and Failuref onComplete { case Success(posts) => for (post <- posts) println(post) case Failure(t) => println("An error has occured: " +
t.getMessage)}
// only handle Successf onSuccess { case posts => for (post <- posts) println(post)}
// only handle Failuref onFailure { case t => println("An error has occured: " + t.getMessage)}
Saturday, October 19, 13
More tools: agents
•Reactive memory cells
•Send update function to an agent
•Reads are “free”
•Composable
•Originally in Clojure, borrowed by Akka
Saturday, October 19, 13
More tools: agents
// declare the agentval counter = Agent(0)
// send the function: enqueued the changecounter send { _ + 1}
// long running or blocking operations
implicit val ec = defineSomeExecutionContext()agent sendOff blockingOperation
// read the agent’ s valueval agentValue = counter.value
Saturday, October 19, 13
More tools: software transactional memory
Sometimes we will deal with shared stateHeap + Stack: transactional dataset:
Begin, commit, rollback
Retry on collision
Rollback on abort
Transaction composability
Saturday, October 19, 13
More tools: reactive extensions
•Futures + Stream concept
•Composables
•Async and event based
•Push collections
•JVM available through the RxJava project
Saturday, October 19, 13
More tools: reactive extensions
def simpleComposition() { customObservableNonBlocking() .skip(10) .take(5) .map({ stringValue -> return stringValue + "_transformed"}) .subscribe({ println "nextElement => " + it})} // we should an output like this
nextElement => foo_10_transformednextElement => foo_11_transformednextElement => foo_12_transformednextElement => foo_13_transformednextElement => foo_14_transformed
Saturday, October 19, 13
More tools: reactive extensions
def Observable<T> getData(int id) { if(availableInMemory) { return Observable.create({ observer -> observer.onNext(valueFromMemory); observer.onCompleted(); }) } else { return Observable.create({ observer -> executor.submit({ try { T value = getValueFromRemoteService(id); observer.onNext(value); observer.onCompleted(); }catch(Exception e) { observer.onError(e); } }) }); }}
Saturday, October 19, 13
Useful approaches
Where should I use each tool?
Saturday, October 19, 13
Layers of complexity
Declarative & immutable coreLogic or functional programmingFutures and/or dataflow
Non-determinism when neededActors, Agents or Rx
Shared mutabilityProtected by Software Transactional Memory
Finally, only if it is really neededLocks and explicit threads
Saturday, October 19, 13
Takeways
A quick summary
Saturday, October 19, 13
Takeaways
Go reactive
Avoid locking (share nothing, lock free algs)
Already in the JVM? Akka could be good choice
Distributed systems are hard
Use the correct level of abstraction
And remember ...
Saturday, October 19, 13
Takeaways
When all you have is a hammer everything looks like
a nail.
Choose the
right tool for your job!
Saturday, October 19, 13
Questions?
And let’s hope answers
Saturday, October 19, 13
References
Interesting resources
Saturday, October 19, 13
References: slides, talks and books
High Performance Networking in the JVM by Eric Onnen
Going reactive talk by Jonas Bonér
Introducing Akka by Jonas Bonér
The future I was promised by Viktor Klang
Real world Akka recipes by Björn Antonsson et all
Saturday, October 19, 13
References: slides, talks and books
Programming Concurrency in the JVM: Mastering synchronization, STM and Actors by Venkat Subramaniam
Systems than run forever Self-heal by Joe Amstrong
The art of multiprocessor programming, Revised Reprint by Maurice Herlihy
Reactive Manifesto
Saturday, October 19, 13
References: frameworks and toolkits
Erlang
Akka Toolkit
Scala language
Vert.x
Clojure language
GPars
Saturday, October 19, 13
References: frameworks and toolkits
Cloud Haskell
NodeJS
Netty IO
Finagle
Saturday, October 19, 13