Upload
roy-russo
View
436
Download
2
Embed Size (px)
Citation preview
Who am I?
• Former JBoss Portal Co-Founder
• LoopFuse Co-Founder
• ElasticHQ Founder
• http://www.elastichq.org
• Co-Author, Elasticsearch In Action
• Chief Architect, Altisource Labs
• VP Engineering, Predikto
2
Moore’s Law
The number of transistors on a chip will double
approximately every 18 months.
~ Gordon Moore, 1965
4
Moore’s Law
• Early 2000:
• Chips got BIG
• Signals couldn’t reach whole chip in one clock
cycle.
• Heat dissipation issues.
6
Moore’s Law
• Multi-core processors
• Multiple calculations in parallel
• CPU speeds are likely to not increase any time soon.
7
The Free Lunch is Over
• Build your applications to…
• take advantage of advances in new processors.
• take advantage of distributed computing.
• operate in a concurrent fashion!
8
Is Joe Armstrong Right?
• The world is concurrent. Things happen in parallel.
• Groups of people have no shared state.
• You have your memory. I have mine.
• Communication by messages; sound, light.
• State updates based on messages.
• Sh*t happens. (Things Fail)
• From: https://pragprog.com/articles/erlang
12
Alternatives?
13
Software Transactional Memory (STM)
Message-Passing Concurrency (Actors)
Dataflow Concurrency
Actors
• From a 1973 paper, written by Carl Hewitt
• Erlang, Occam, Oz
• Encapsulate state and behavior
• Implement Message-Passing Concurrency
15
• Share Nothing.
• No need to synchronize.
• Isolated. Lightweight event-based Processes.
• ~ 6.5m on 4GB RAM
• Communicate through Messages.
• Asychronous and Non-Blocking
• Messages are immutable
• Each actor has a mailbox (message queue)
• Supervision-based failure management.
16
Actor Model of Concurrency
Akka
Akka is a toolkit for building
Concurrent
Distributed
Fault-Tolerant
applications.
19
Actors
Remoting
Supervision
When to Akka?
• When you need to build a system that:
• reacts to Events … Event-Driven
• reacts to Load … Scalable
• reacts to Failure … Resilient
• reacts to Users … Responsive
20
REACTIVE APPLICATIONS
Actor System
Chat Architecture
21
Cassandra
Cluster
Elasticsearch
Cluster
User 1
Controllers
Services
websocket
Users
websocket
async
async async
async
Akka Actor
22
Actor
Behavior
State
mailbox• Lightweight object
• ~300 bytes/instance
• Keeps internal state
• Asynch / non-blocking
• Messages kept in mailbox
• Persistence
• Small call stack =
• Scalable and fast
When an actor receives a message…
23
• Actors can:
• Create new Actors
• Sends messages to
Actors
• Designate how it should
handle the next message
Actor
Behavior
State
mailbox
Sample pom
26
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor_2.10</artifactId>
<version>${akka.version}</version>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-persistence-experimental_2.10</artifactId>
<version>${akka.version}</version>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-cluster_2.10</artifactId>
<version>${akka.version}</version>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-slf4j_2.10</artifactId>
<version>${akka.version}</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>${scala.version}</version>
</dependency>
Actor System
27
• Actors created within this context/container.
• Manage shared facilities:
• scheduling, logging, configuration, etc…
• Can have many per JVM with different configs
• Can contain millions of actors.
Actor System
28
public void init() throws Exception {
actorSystem = ActorSystem.create("chatActorSystem");
}
Actor System
29
<bean id="actorSystemService" class="com.streamproject.akka.ActorSystemService"
init-method="init" destroy-method="destroy">
</bean>
On app-boot with Spring… (applicationContext.xml)
Actor System
30
/**
* Note that this will throw on servlet container shutdown. They are false alarms in Tomcat regarding
* Threads not being terminated correctly. The Thread.sleep call is merely here to make the noise less
* noisy.
*/
public void destroy() throws Exception {
actorSystem.shutdown();
Thread.sleep(5000);
}
Actor System - Configuration
31
akka {
# Loggers to register at boot time (akka.event.Logging$DefaultLogger logs
# to STDOUT)
loggers = ["akka.event.slf4j.Slf4jLogger"]
# Log level used by the configured loggers (see "loggers") as soon
# as they have been started; before that, see "stdout-loglevel"
# Options: OFF, ERROR, WARNING, INFO, DEBUG
loglevel = "DEBUG"
# Log level for the very basic logger activated during ActorSystem startup.
# This logger prints the log messages to stdout (System.out).
# Options: OFF, ERROR, WARNING, INFO, DEBUG
stdout-loglevel = "DEBUG"
actor {
provider = "akka.cluster.ClusterActorRefProvider"
…
}
application.conf || application.json || application.properties
Actor System - Configuration
32
public void init() throws Exception {
Config conf = ConfigFactory.load(“myconfig”);
actorSystem = ActorSystem.create(“chatActorSystem”, conf);
}
myconfig.conf
• Custom config naming/loading
• Configuration by string
• Override configuration values
Actor System
33
Actor System
Actor System location transparency
Event
• Remote and local process
actors treated the same
• Unified prog. model for
multicore and distributed
computing
msg
Mailbox
35
ActorRef MailboxActor
Instance
Invokes Actor Instance with Message.
Runs on a dispatcher - abstracts threading
DEFINE
39
public class MyActor extends UntypedActor {
public void onReceive(Object message) throws Exception {
}
}
CREATE
40
ActorSystem mySystem = ActorSystem.create("MyActorSystem");
ActorRef myActor = mySystem.actorOf(new Props(MyActor.class),"myActor");
Creates a top-level Actor
DEFINE - non-default constructor
41
public class PersistEventProcessor extends UntypedActor {
private SearchService searchService;
public PersistEventProcessor(SearchService searchService) {
this.messageEventService = messageEventService;
this.searchService = searchService;
}
@Override
public void onReceive(Object obj) throws Exception {…}
}
CREATE - non-default constructor
42
final ActorRef actorRef = actorSystemService.getActorSystem()
.actorOf(Props.create(PersistEventProcessor.class, searchService));
actorRef.tell(new PersistMessageEventCommand(event), null);
CREATE - Child Actor
43
public class SupervisorActor extends UntypedActor
{
ActorRef myChildActor = getContext().actorOf(new
Props(MyChildActor.class), “myChildActor” +
UUID.randomUUID());
}
SEND
44
• Fire and Forget
• Asynch
• No expected reply
• tell()
• Send and Receive
• Asynch
• Expects reply (Future)
• ask()
SEND - tell()
45
actor.tell(message);
// Explicit passing of sender actor reference
actor.tell(msg, getSelf());
SEND - ask()
46
import static akka.patterns.Patterns.ask;
Future<Object> future = ask(actor, message, timeout);
future.onSuccess(new OnSuccess<Object>() {
public void onSuccess(String result) {
System.out.println(result);
}
});
more on Futures in a bit…
SEND - An ask() reply
47
try {
String result = operation();
getSender().tell(result, getSelf());
} catch (Exception e) {
getSender().tell(new akka.actor.Status.Failure(e), getSelf());
throw e;
}
BECOME
• Dynamically redefines actor behavior
• Reactively triggered by message
• Like changing an interface, or implementation on-the-fly
48
BECOME
49
public class PingPongActor extends UntypedActor {
static String PING = "PING";
static String PONG = "PONG";
int count = 0;
public void onReceive(Object message) throws Exception {
if (message instanceof String) {
if (((String) message).matches(PING)) {
System.out.println("PING");
count += 1;
Thread.sleep(100);
getSelf().tell(PONG);
getContext().become(new Procedure<Object>() {
public void apply(Object message) {
if (message instanceof String) {
// do Something
}
}
}
});
if (count > 10)
getContext().stop(getSelf());
…
}
SUPERVISE
• Manage another actor’s failure
• Supervisors receive notifications, and can react upon
failure
• Every actor has a default supervisor strategy
• Can be overriden
• OneForOneStrategy (def)
• AllForOneStrategy
50
SUPERVISE
51
• On Failure, a supervisor defines what happens next:
• resume child, and keep internal state
• restart child, and wipe internal state
• stop child permanently
• stop itself and escalate the error
• AllForOneStrategy, affects all children.
SUPERVISE
52
public class Supervisor extends UntypedActor {
private static SupervisorStrategy strategy =
new OneForOneStrategy(10, Duration.create("1 minute"),
new Function<Throwable, Directive>() {
@Override
public Directive apply(Throwable t) {
if (t instanceof ArithmeticException) {
return resume();
} else if (t instanceof NullPointerException) {
return restart();
} else if (t instanceof IllegalArgumentException) {
return stop();
} else {
return escalate();
}
}
});
@Override
public SupervisorStrategy supervisorStrategy() {
return strategy;
}
SUPERVISE
• A contrast to Failure Management in Java
• You get one thread to control.
• If the thread blows up, then what?
• Defensive programming:
• Mix error handling within the thread
• == tangled business logic + error handling
• Errors don’t propagate between threads
54
Stopping Actors
55
//first option of shutting down the actors by shutting down the ActorSystem
system.shutdown();
//second option of shutting down the actor by sending a poisonPill message
actor.tell(PoisonPill.getInstance());
//third option of shutting down the actor
getContext().stop(getSelf());
//or
getContext().stop(childActorRef);
Killing Actors
56
actor.tell(Kill.getInstance());
• Synchronous
• Sends ActorKilledException to parent
UntypedActor API
• getSelf() : me
• getSender() : reply-to
• getContext() :
• factory for child actors
• get parent
• system the actor belongs to
• supervisionStrategy()
• onReceive(msg)
57
UntypedActor API
58
public void preStart() {
}
public void preRestart(Throwable reason, scala.Option<Object> message) {
for (ActorRef each : getContext().getChildren()) {
getContext().unwatch(each);
getContext().stop(each);
}
postStop();
}
public void postRestart(Throwable reason) {
preStart();
}
public void postStop() {
}
Message Delivery
60
ActorRef MailboxActor
Instance
Invokes Actor Instance with Message.
Runs on a dispatcher - abstracts threading
• At-Most-Once (Akka)
• At-Least-Once (Akka Persistence)
• Exactly Once
• What’s the definition of “Guaranteed Delivery”?
An Example
61
public class UserLoginProcessor extends UntypedActor {
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
CoreUserDetailsServiceImpl coreUserDetailsService;
public UserLoginProcessor(CoreUserDetailsServiceImpl userDetailsService) {
coreUserDetailsService = userDetailsService;
}
@Override
public void onReceive(Object message) throws Exception {
if (message instanceof ProcessLoginCommand) {
SomeEvent someEvent = ((ProcessLoginCommand) message).getSomeEvent();
User user = UserDTOUtil.fromDTOToUser(someEvent.getUserDTO());
coreUserDetailsService.updateLoginTS(user);
} else if (message instance ProcessLogoutCommand) { … }
}
}
Akka Logging
non-def constructor
Command-based messaging
An Example
62
public class ProcessLoginCommand extends BaseCommand {
private StreamEvent streamEvent;
public ProcessLoginCommand(Object streamEvent) {
super(streamEvent);
this.streamEvent = (StreamEvent) streamEvent;
}
public StreamEvent getStreamEvent() {
return streamEvent;
}
}
public class BaseCommand<T> {
private T commandObject;
public BaseCommand(T commandObject) {
this.commandObject = commandObject;
}
public T getCommandObject() {
return commandObject;
}
}
An Example
63
@Autowired
private CoreUserDetailsServiceImpl userService;
@Override
public void processInboundEvent(StreamEvent event) {
switch (event.getEventType()) {
case EventType.USER_LOGIN: {
final ActorRef actorRef = actorSystemService.getActorSystem()
.actorOf(Props.create(UserLoginProcessor.class, userService), "login-processor
actorRef.tell(new ProcessLoginCommand(event), null);
…
An Example
64
public class UserLoginProcessor extends UntypedActor {
LoggingAdapter log = Logging.getLogger(getContext().system(),
this);
CoreUserDetailsServiceImpl coreUserDetailsService;
public UserLoginProcessor(CoreUserDetailsServiceImpl
userDetailsService) {
coreUserDetailsService = userDetailsService;
}
…
}
Dispatchers
65
• Control execution flow
• based on the Java Executor framework
(java.util.concurrent)
• ThreadPoolExecutor: Executes each submitted task
using thread from a predefined and configured thread
pool.
• ForkJoinPool: Same thread pool model but
supplemented with work stealing. Threads in the pool
will find and execute tasks (work stealing) created by
other active tasks or tasks allocated to other threads in
the pool that are pending execution.
Dispatchers
67
default-dispatcher {
type = "Dispatcher"
executor = "fork-join-executor"
fork-join-executor {
parallelism-min = 8
parallelism-factor = 3.0
parallelism-max = 64
}
thread-pool-executor {
keep-alive-time = 60s
core-pool-size-min = 8
core-pool-size-factor = 3.0
core-pool-size-max = 64
max-pool-size-min = 8
max-pool-size-factor = 3.0
max-pool-size-max = 64
task-queue-size = -1
task-queue-type = "linked"
allow-core-timeout = on
…
Mailbox Types
71
• Backed by queue impl. from java.util.concurrent
bounded-mailbox {
mailbox-type = "akka.dispatch.BoundedMailbox"
mailbox-capacity = 1000
}
Priority Mailboxes
72
public class MyPrioMailbox extends UnboundedPriorityMailbox {
// needed for reflective instantiation
public MyPrioMailbox(ActorSystem.Settings settings, Config config) {
// Create a new PriorityGenerator, lower prio means more important
super(new PriorityGenerator() {
@Override
public int gen(Object message) {
if (message.equals("highpriority"))
return 0; // 'highpriority messages should be treated first if possible
else if (message.equals("lowpriority"))
return 2; // 'lowpriority messages should be treated last if possible
else if (message.equals(PoisonPill.getInstance()))
return 3; // PoisonPill when no other left
else
return 1; // By default they go between high and low prio
}
});
}
}
Routers
74
• Round-Robin Router
• Random Router
• Smallest Mailbox Router
• Broadcast Router
ActorRef router = system.actorOf(new Props(MyActor.class).
withRouter(new RoundRobinRouter(nrOfInstances)),"myRouterActor");
int lowerBound = 2;
int upperBound = 15;
DefaultResizer resizer = new DefaultResizer(lowerBound, upperBound);
ActorRef randomRouter = _system.actorOf(new Props(MsgEchoActor.class). withRouter(new RandomRouter(resizer)));
Futures
75
Timeout timeout = new Timeout(Duration.create(5, "seconds"));
Future<Object> future = Patterns.ask(actor, msg, timeout);
String result = (String) Await.result(future, timeout.duration());
Blocking!
• Callbacks: onSuccess, onFailure, onComplete
Future<Integer> future = future(new Callable<Integer>() {
public Integer call() {
return 1 / 0;
}
}, ec).recover(new Recover<Integer>() {
public Integer recover(Throwable problem) throws Throwable {
if (problem instanceof ArithmeticException)
return 0;
else
throw problem;
}
}, ec);
Persistence
• Experimental (from “Eventsourced”)
• Plugins: LevelDB, MongoDB, Cassandra, etc..
• Architecture:
• PersistentActor
• Journal
• AtLeastOnce Delivery
• Snapshots
• Event Sourcing (http://martinfowler.com/eaaDev/EventSourcing.html)
76
Some Code…
Event Bus
• Used internally by Akka: Event Stream, Dead Letters,
Logging, etc…
• Remember: No Sender access!
85
public boolean subscribe(Subscriber subscriber, Classifier to);
public boolean unsubscribe(Subscriber subscriber, Classifier from);
public void unsubscribe(Subscriber subscriber);
public void publish(Event event);
Some Code…
Stuff I didn’t cover
• Testing
• Typed Actors
• Application Monitoring
• MANY Configuration options
• http://doc.akka.io/docs/akka/snapshot/general/configurati
on.html
86
Questions?
87
• Beginner Examples: https://github.com/royrusso/akka-
java-examples
• Akka Java Doc:
http://doc.akka.io/docs/akka/snapshot/java.html