Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

29
Concurrency, Scalability & Fault-tolerance 2.0 with Actors & STM by Mario Fusco [email protected] twitter: @mariofusco

Transcript of Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Page 1: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Concurrency, Scalability & Fault-tolerance 2.0 with Actors & STM

by Mario [email protected]: @mariofusco

Page 2: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Which are the biggest challenges in contemporary

software development?

Page 3: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Deal with overloaded systems

Page 4: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Do concurrency effectively

Page 5: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Design, develop

and deploy applications

that scale well

Page 6: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

The native Java concurrency model

Based on:

They are sometimes plain evil …

… and sometimes a necessary pain …

… but always the wrong default

Threads

Semaphores

SynchronizationLocks

Page 7: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Actors: a different model of concurrency

Implements Message-Passing Concurrency

Share NOTHING

Isolated lightweight processes

Communicates through messages

Asynchronous and non-blocking

Each actor has a mailbox (message queue)

A single thread can manage many (thousands of) actors

Page 8: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

People are bad at parallel thinking

With actors is easier to reason about and easier to avoid: Race conditions, Deadlocks, Starvation and Live locks

Page 9: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

What is Akka? An actor based concurrency framework Written in Scala, but also working in Java Now realeasing 1.0 after 2 years of development (currently RC4 available) Better performances and throughput and smaller memory footprint (650 bytes)

than native scala actors Open source (Apache2)

Page 10: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Untyped Actors

public class MyUntypedActor extends UntypedActor { public void onReceive(Object message) throws Exception { if (message instanceof String) { String msg = (String)message; System.out.println("Received message: " + msg); } }}

UntypedActorRef actor = UntypedActor.actorOf(MyUntypedActor.class);actor.start();// --- Do some work here ---actor.stop();

Page 11: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Sending message to Untyped Actors

There are 3 different ways to send a message to an actor:

1. Fire-and-forget ( ! In Scala )actor.sendOneWay(msg);

2. Uses a Future under the hood, blocking the sender Actor until either a reply is received or the Future times out ( !! In Scala )

Object res1 = actor.sendRequestReply(msg);Object res2 = actor.sendRequestReply(msg, 1000); // timeout

3. Explicitly returns a Future ( !!! In Scala )Future future = actor.sendRequestReplyFuture(msg);

IMPORTANT: Messages can be any kind of object but have to be immutable. Akka can’t enforce immutability (yet) so this has to be by convention

Page 12: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Typed Actors

public class CounterImpl extends TypedActor implements Counter { private int counter = 0; public void count() { counter++; System.out.println(counter); } public int getCountNr() { returncounter; }}

Counter counter = (Counter)TypedActor .newInstance(Counter.class, CounterImpl.class, 1000);

counter.count(); // Fire-and-forgetint count = counter.getCountNr(); // uses Future under the hood

Page 13: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

“Let it crash” fault-tolerance

through supervisor hierarchies

Page 14: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

You can’t avoid failures: shit happens

Page 15: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Java and other languages and frameworks (not designed with concurrency in mind) signal faults/errors with exceptions

Throwing an exception in concurrent code will just simply blow up the thread that currently executes the code that threw it:

1. There is no way to find out that things went wrong, apart from inspecting the stack trace

2. There is nothing you can do to recover from the problem and bring back your system to a normal functioning

What’s wrong in trying to prevent errors?

Page 16: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Fail fast & build self-repairing systems

Page 17: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Supervised actors Actors provide a clean way of getting error notification and do something about it Supervised actors also allow you to create sets (hierarchies) of actors where you

can be sure that either all are dead or none are dead That encourages non-defensive programming: don’t try to prevent things from go

wrong, because they will. Failures are a natural state in the life-cycle of your app: crash early and let someone else (that sees the whole picture), deal with it

A supervisor is responsible for starting, stopping and monitoring its child processes. It can act with 2 fault handling strategies: One-For-One or All-For-One

Page 18: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Declarative supervised actors configurationSupervisor supervisor = new Supervisor( new SupervisorConfig( new AllForOneStrategy( // or OneForOneStrategy new Class[]{Exception.class}, // Exceptions to handle 3, // maximum number of restart retries 5000), // within time in millis new Supervise[] { new Supervise( UntypedActor.actorOf(MyActor1.class), permanent()), // the actor will always be restarted new Supervise( UntypedActor.actorOf(MyActor2.class), temporary()) // the actor won’t be shut down normally }));

// You can also link and unlink actors from a supervisorsupervisor.link(actor1);supervisor.unlink(actor1);

Page 19: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Remote actors

Akka provides remote actors in a completely transparent way both in regards to sending messages, error handling and supervision

Uses a very efficient and scalable I/O implementation built upon JBoss Netty and Google Protocol Buffers

Can be secured with a cookie authentication mechanism

Can be both Typed and Untyped

Two types of remote actors: o server-managed: run on the machine that created it while client

can lookup and obtain a proxy o client managed: make them running on a different machine

while the local one just hold a proxy to send them messages

Page 20: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Typed

Untyped

Server-managed Client-managed

class MyActor extends UntypedActor {}

Actors.remote() .start("localhost", 9999) .register(“my-service", actorOf(MyActor.class) );

class MyActor extends UntypedActor {}

Actors.remote() .actorOf(MyActor.class, "192.68.23.69", 9999 );

Bean remoteActor = (Bean)TypedActor .newRemoteInstance( Bean.class, BeanImpl.class, timeout, "192.68.23.69", 9999 );

Bean actor = TypedActor.newInstance( Bean.class, BeanImpl.class, timeout); Actors.remote() .start("localhost", 9999) .registerTypedActor( “my-service", actor );

Page 21: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Software Transactional MemoryAn STM turns the Java heap into a transactional data set with begin/commit/rollback semantics. Very much like a regular database.

It implements the first three letters in ACID; ACI: • Atomic: all or none of the changes made during a transaction get applied• Consistent: a transaction gets a consistent of reality• Isolated: changes made by concurrent execution transactions are not visible to

each other

Akka’s STM implements the concept already present in Clojure’s STM

The STM is based on Transactional References (referred to as Refs). Refs: • are memory cells, holding an (arbitrary) immutable value• implement CAS (Compare-And-Swap) semantics • are managed and enforced by the STM for coordinated changes across many

Refs• are implemented using the excellent Multiverse STM

(http://multiverse.codehaus.org)

Page 22: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Why we need an STM?public class Container { private int value; private final ReadWriteLock lock = new ReentrantReadWriteLock();

public int getValue() { lock.readLock().lock(); try { return value; } finally { lock.readLock.unlock(); } }  

public void setValue(int value) { lock.writeLock().lock(); try { this.value = value; } finally { lock.writeLock.unlock(); } } }

What’s wrong with it?

Ad-hoc and hardly reusable logic Unnecessary complexity Locks limit concurrency and then

throughput

Page 23: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

How does Akka STM work?// Create a Ref with an initial value (also possible without)final Ref<Integer> ref = new Ref<Integer>(0);   public int counter() { // A transaction is delimited using an Atomic anonymous inner class return new Atomic<Integer>() { public Integer atomically() { int inc = ref.get() + 1; // Accessing the value of the Ref ref.set(inc); // Changing the value of the Ref return inc; } }.execute(); } A transaction is automatically retried when it runs into some read or write conflict In this case an (exponential) delay is used to prevent further contentions There shouldn’t be side-effects inside the transaction to avoid to repeat them

Page 24: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

final TransactionalMap<String, User> users = new TransactionalMap<String, User>();  

// fill users map (in a transaction) new Atomic() { public Object atomically() { users.put("bill", new User("bill")); users.put("mary", new User("mary")); users.put("john", new User("john")); return null; } }.execute();  

// access users map (in a transaction) User user = new Atomic<User>() { public User atomically() { return users.get("bill").get(); } }.execute();

Transactional Datastructures

Page 25: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Persistent Datastructures

Copyright Rich Hickey 2009

Page 26: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

public class Counter extends UntypedActor { private Ref<Integer> count = new Ref(0); private void increment() { count.set(count.get() + 1); } public void onReceive(Object incoming) throws Exception { if (incoming instanceof Coordinated) { Coordinated coordinated = (Coordinated) incoming; Object message = coordinated.getMessage(); if (message instanceof Increment) { Increment increment = (Increment) message; if (increment.hasFriend()) { increment.getFriend() .sendOneWay(coordinated.coordinate(new Increment())); } coordinated.atomic(new Atomically() { public void atomically() { increment(); } });}}}}

Coordinating Actors with STM

Page 27: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

public class Counter extends UntypedTransactor { Ref<Integer> count = new Ref<Integer>(0); @Override public Set<SendTo> coordinate(Object message) { if (message instanceof Increment) { Increment increment = (Increment) message; if (increment.hasFriend()) return include(increment.getFriend(), new Increment()); } return nobody(); } public void atomically(Object message) { if (message instanceof Increment) { count.set(count.get() + 1); } }}

Actors + STM = Transactors

Page 28: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

Other Akka goodies Implements Advanced Message Queuing Protocol (AMPQ) based on the

RabbitMQ

Integration with Apache Camel

Persistence module supporting many NoSQL DB like: Cassandra, MongoDB, Riak, Redis, Terrastore, CouchDB, Voldemort, Hbase

Integration between Akka STM and JTA (Java Transaction API)

OSGi support

Integration with Spring allowing to define Typed Actors as Spring managed bean

Integration with Lift Web Framework and Play! Framework

Page 29: Concurrency, Scalability & Fault-tolerance 2.0 with Akka Actors & STM

by Mario [email protected]: @mariofusco

Thanks a lot!

Happy Java (or Scala) h ing