1. Miguel Ángel Pastor Olivar
Reactive Applications
Building concurrent and distributed apps using Akka
miguelinlas3@gmail.com - Liferay Inc and MadridJUG
@miguelinlas3
Saturday, October 19, 13
2. About me
Writing software for the Liferay platform team
Phd student? on distributed and cloud
systems
Scala enthusiast
Twitter: @miguelinlas3
Saturday, October 19, 13
3. Agenda
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)
Saturday, October 19, 13
4. Reactive applications
Applications has become extremely
demanding
New kind of systems
Event driven, scalable , resilient, responsive
This is what Reactive Applications are all
about
Saturday, October 19, 13
5. Reactive applications: definitions
Blocking
Caller blocked. Wait for the results
Non blocking
Caller not blocked. Need to pool
Asynchronous
Caller not blocked. Select, epoll, signals
Event driven
Message flowing through the system
Saturday, October 19, 13
23. Going event driven: problems with locks
Composition
Saturday, October 19, 13
24. Going event driven: problems with locks
Composition
Locks don´t compose
Saturday, October 19, 13
25. Going event driven: problems with locks
Composition
Locks don´t compose
Saturday, October 19, 13
Granularity
26. Going event driven: problems with locks
Composition
Locks don´t compose
Have I taken too few
locks? Too many?
Saturday, October 19, 13
Granularity
27. Going event driven: problems with locks
Composition
Locks don´t compose
Have I taken too few
locks? Too many?
Encapsulation
Saturday, October 19, 13
Granularity
28. Going event driven: problems with locks
Composition
Locks don´t compose
Have I taken too few
locks? Too many?
Encapsulation
Breaking abstractions
Saturday, October 19, 13
Granularity
29. Going event driven: problems with locks
Composition
Locks don´t compose
Granularity
Have I taken too few
locks? Too many?
Encapsulation
Breaking abstractions
Saturday, October 19, 13
Correctness
30. Going event driven: problems with locks
Composition
Locks don´t compose
Granularity
Have I taken too few
locks? Too many?
Encapsulation
Breaking abstractions
Correctness
Have I taken the
correct lock?
Saturday, October 19, 13
31. Going event driven: problems with locks
Composition
Locks don´t compose
Granularity
Have I taken too few
locks? Too many?
Encapsulation
Breaking abstractions
Ordering
Saturday, October 19, 13
Correctness
Have I taken the
correct lock?
32. Going event driven: problems with locks
Composition
Locks don´t compose
Granularity
Have I taken too few
locks? Too many?
Encapsulation
Breaking abstractions
Ordering
Saturday, October 19, 13
Have I used the
correct order?
Correctness
Have I taken the
correct lock?
33. Going event driven: designing your system
Asynchronous message/event passing
Workflow of the events through your system
Benefits:
Better throughput
Lower latencies
Loosely coupled solutions
Saturday, October 19, 13
35. 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
39. 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
40. 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
41. 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
42. Actor model: Getting a reference
ActorSystem _agentSystem = ActorSystem.create("AgentSystem");
ActorRef handshakeActor =
_agentSystem.actorFor(
"akka://MonitoringServiceSystem@localhost:5557/user/
handshakeActor");
Saturday, October 19, 13
43. Actor model: Sending a message
metricsActor.tell(
new JVMMessage("JVM-MemoryUsage", new Date().getTime()));
Saturday, October 19, 13
44. 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
45. 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
46. Actor model: Routing
final ActorSystem monitoringServiceSystem =
ActorSystem.create("MonitoringServiceSystem");
ActorRef metricsActor =
monitoringServiceSystem.actorOf(
new Props(MetricsProcessorActor.class).withRouter(
new RoundRobinRouter(100), "metricsActor");
}
Dealing with routers does not change our code
metricsActor.tell(
new JVMMessage("JVM-MemoryUsage", new Date().getTime()));
Saturday, October 19, 13
47. Actor model: Configuring a router
akka {
actor {
deployment {
/metricsActor {
router = round-robin
nr-of-instances = 100
}
}
}
}
Saturday, October 19, 13
49. 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
50. Going scalable: transparent distributed computing
Distributed shared mutable state
Distributed objects
Distributed transactions
Saturday, October 19, 13
51. 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
55. 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 programming
Tangled within business logic
Scattered along all our codebase
Saturday, October 19, 13
56. Going resilient: actor topology and supervision
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
B5
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
57. Supervision strategies: One for one
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
B5
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
58. Supervision strategies: One for one
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
59. Supervision strategies: One for one
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
60. Supervision strategies: One for one
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
61. Supervision strategies: One for one
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
62. Supervision strategies: One for one
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
B5
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
63. Supervision strategies: One for all
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
B5
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
64. Supervision strategies: One for all
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
65. Supervision strategies: One for all
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
66. Supervision strategies: One for all
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
67. Supervision strategies: One for all
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
68. Supervision strategies: One for all
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
69. Supervision strategies: One for all
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
B5
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
70. Supervision strategies: One for all
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
B5
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
71. Supervision strategies: One for all
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
B5
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
72. Supervision strategies: One for all
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
B5
/A1/A2/A4
A4
/B1/B2/B7
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
B4
/B1/B2/B4
73. Supervision strategies: One for all
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
B5
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
74. Supervision strategies: One for all
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
B5
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
75. Supervision strategies: One for all
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
B5
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
76. Supervision strategies: One for all
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B5
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
77. Supervision strategies: One for all
System
/B1
/A1
B1
A1
/B1/B3
/A1/A2
/B1/B2
B3
B2
A2
/A1/A3
A3
B7
B5
/A1/A2/A4
A4
B6
B4
/B1/B3/B5
/B1/B2/B6
Saturday, October 19, 13
/B1/B2/B7
/B1/B2/B4
78. 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
80. More tools: futures
•Spawn concurrent computations
•Write once - Read many
•Freely sharable
•Non-blocking composition
•Composable (monadic operations)
•Managing failure
Saturday, October 19, 13
81. More tools: futures
val f: Future[List[String]] = future {
session.getRecentPosts
}
// handle both cases: Success and Failure
f onComplete {
case Success(posts) => for (post <- posts) println(post)
case Failure(t) => println("An error has occured: " +
t.getMessage)
}
// only handle Success
f onSuccess {
case posts => for (post <- posts) println(post)
}
// only handle Failure
f onFailure {
case t => println("An error has occured: " + t.getMessage)
}
Saturday, October 19, 13
82. 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
83. More tools: agents
// declare the agent
val counter = Agent(0)
// send the function: enqueued the change
counter send { _ + 1}
// long running or blocking operations
implicit val ec = defineSomeExecutionContext()
agent sendOff blockingOperation
// read the agent’ s value
val agentValue = counter.value
Saturday, October 19, 13
84. More tools: software transactional memory
Sometimes we will deal with shared state
Heap + Stack: transactional dataset:
Begin, commit, rollback
Retry on collision
Rollback on abort
Transaction composability
Saturday, October 19, 13
85. More tools: reactive extensions
•Futures + Stream concept
•Composables
•Async and event based
•Push collections
•JVM available through the RxJava project
Saturday, October 19, 13
86. 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
nextElement
nextElement
nextElement
nextElement
Saturday, October 19, 13
=>
=>
=>
=>
=>
foo_10_transformed
foo_11_transformed
foo_12_transformed
foo_13_transformed
foo_14_transformed
89. Layers of complexity
Declarative & immutable core
Logic or functional programming
Futures and/or dataflow
Non-determinism when needed
Actors, Agents or Rx
Shared mutability
Protected by Software Transactional Memory
Finally, only if it is really needed
Locks and explicit threads
Saturday, October 19, 13
91. 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
92. Takeaways
hammer
When all you have is a
everything looks like
a
nail.
Choose the
right tool for your job!
Saturday, October 19, 13
95. 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
96. 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
97. References: frameworks and toolkits
Erlang
Akka Toolkit
Scala language
Vert.x
Clojure language
GPars
Saturday, October 19, 13