Apresentação sobre programação de sistemas concorrentes usando Akka, em Java e Scala, apresentada na QConSP 2011.
Ementa:
Conheça Akka, uma plataforma para o JVM para desenvolvimento de sistemas concorrentes e/ou distribuídos através do paradigma de Atores.
Descreveremos o paradigma de atores, suas vantagens e desvantagens, e mostraremos exemplos da API em Java e em Scala, com execução local e distribuída, memória transacional e tolerância a falhas.
Akka - Uma plataforma para o desenvolvimento de sistemas concorrentes e distribuídos para a JVM
1. Uma plataforma para o desenvolvimento de sistemas
concorrentes e distribuídos para a JVM
2. Akka
Uma plataforma para o desenvolvimento de sistemas
concorrentes e distribuídos para a JVM
• Daniel Capó Sobral
• Consultor pela Tecnisys
• Programador e Sysadmin
• Ex-committer FreeBSD
• Aficionado por Scala
3. Akka
Uma plataforma para o desenvolvimento de sistemas
concorrentes e distribuídos para a JVM
Conheça Akka, uma plataforma para o JVM para
desenvolvimento de sistemas concorrentes e/ou
distribuídos através do paradigma de Atores.
Descreveremos o paradigma de atores, suas
vantagens e desvantagens, e mostraremos
exemplos da API em Java e em Scala, com
execução local e distribuída, memória transacional
e tolerância a falhas.
4. Conteúdo
Objetivos Principais
• O que é Akka?
• Para que serve?
• O que são atores?
Não é tema
• Ensinar Akka
• Ensinar programação com atores
• Mostrar todos os módulos de Akka
9. Um componente do Typesafe Stack?
• A Typesafe foi fundada em 2011 pelos criadores da
linguagem de programação Scala e do middleware Akka.
• O Typesafe Stack contém Scala, Akka e ferramentas de
desenvolvimento, tudo open source.
• A Typesafe Subscription provê suporte comercial.
10. Uma solução de:
Concorrência
Escalabilidade
Tolerância à Falhas
11. Uma solução de:
Concorrência
• Atores
• STM
• Agentes
• Dataflow
Escalabilidade
Tolerância à Falhas
12. Uma solução de:
Concorrência
Escalabilidade
• Vertical
• Atores
• Horizontal
• Atores Remotos
• Gestão de Cluster
Tolerância à Falhas
13. Uma solução de:
Concorrência
Escalabilidade
Tolerância à Falhas
• Supervisão de Atores
• Todos Por Um
• Cada Um Por Si
• “Deixe falhar”
22. Fatos sobre Atores
Orientados à eventos
• Assíncronos
• Threads próprios
Comunicação via mensagens
• Caixa de mensagens
• Não compartilham estado!
Baratos
• Atores não são threads
• Aproximadamente 600 bytes
23. Definindo um Ator - Java
public class SampleUntypedActor extends UntypedActor {
public void onReceive(Object message) throws Exception {
if (message instanceof String)
EventHandler.info(this, String.format("Received String
message: %s", message));
else
throw new IllegalArgumentException("Unknown
message: " + message);
}
}
24. Criando um Ator - Java
import static akka.actor.Actors.*;
ActorRef myActor = actorOf(SampleUntypedActor.class);
myActor.start();
// Construtor com parâmetros
ActorRef actor = actorOf(new UntypedActorFactory() {
public UntypedActor create() {
return new MyUntypedActor("service:name", 5);
}
}).start();
25. ActorRef vs Actor
Portabilidade
• Serializável
• Remote-aware
Opacidade
• Actor é membro privado de ActorRef
this vs self
• Actor this
• ActorRef self
26. Ciclo de Vida
• Não processa mensagens
New
• Iniciado com “start”
Started • Processa mensagens
• Iniciado com “exit” ou “stop”
Shutdown • Não pode fazer nada
27. Enviando uma mensagem
Envie e esqueça
• actor.sendOneWay("Hello");
Envie, com remetente
• actor.sendOneWay("Hello", getContext());
Envie, talvez receba resposta (ou exceção)
• Object result = actorRef.sendRequestReply("Hello", getContext(),
1000);
Envie, receba futuro
• Future future = actorRef.sendRequestReplyFuture("Hello",
getContext(), 1000);
30. Respondendo ao Remetente - Java
public void onReceive(Object message) throws Exception {
if (message instanceof String) {
String msg = (String)message;
if (msg.equals("Hello") &&
getContext().getSenderFuture().isDefined()) {
// Reply to original sender of message using the channel
getContext().channel().sendOneWay(msg + " from " +
getContext().getUuid());
}
}
}
31. Respondendo Mensagem - Java
public void onReceive(Object message) throws Exception {
if (message instanceof String) {
String msg = (String)message;
if (msg.equals("Hello")) {
if (getContext().replySafe(msg + " from " +
getContext().getUuid())) ... // success
else ... // handle failure
}
}
}
33. Akka em Scala
Concisão
• router.tell(new Work(arg, nrOfElements),
getContext());
• router ! Work(arg, nrOfElements)
Parâmetros “by-name”
• val a = actorOf(new MyActor(..)).start()
Parâmetros implícitos
• Ver exemplo de concisão acima!
34. Akka em Scala
Melhor suporte a imutabilidade
• case class Work(arg: Int,
nrOfElements: Int)
• Coleções imutáveis por default
• Estruturas de dados persistentes
Pattern matching
• case Work(arg, n) => // do stuff
36. Agentes
Inspirado nos Agentes de Clojure
Modificações Assíncronas
• Uma modificação de cada vez
• Modificações de cada origem processadas em ordem
Integrado ao STM
• Toma parte em transações
Futuros
• Valor “atual” após todas modificações enfileiradas
37. Agentes - Scala
Criando e Parando
• val agent = Agent(5)
• agent.close()
Alterando
• agent send 7
• agent send (_ + 1)
Lendo
• val result = agent()
• val result = agent.future.await.result.get
38. STM
Mutabilidade Controlada
• Estado compartilhado
• Transações multi-atores (transactors)
Modelo Clojure de Referências
Multiverse STM
39. STM - Java
final Ref<Integer> ref = new Ref<Integer>(0);
public int counter() {
return new Atomic<Integer>() {
public Integer atomically() {
int inc = ref.get() + 1;
ref.set(inc);
return inc;
}
}.execute();
}
40. Dataflow
Concorrência Determinística
• Mesmo resultado todas as vezes
• Baseado em futuros
• Scala Delimited Continuations
Derivado da linguagem Oz
Nada de efeitos colaterais!
• Exceções, data/hora, números aleatórios, etc
41. Dataflow - Scala
Declarar variável dataflow
• val x = Promise[Int]()
Usar valor
• flow { ... x() ... }
Assinalar valor
• flow { ... x << 5 ... }
Assinalar a uma outra variável
• flow { ... x << y ... }
43. Atores Remotos - Java
// server code
class HelloWorldActor extends UntypedActor {
public void onReceive(Object msg) {
getContext().replySafe(msg + " World");
}
}
remote().start("localhost", 9999).register( "hello-
service", actorOf(HelloWorldActor.class));
// client code
ActorRef actor = remote().actorFor( "hello-
service", "localhost", 9999);
Object res = actor.sendRequestReply("Hello");
44. Atores Remotos
Um por tipo
Um por sessão
Um por requisição
45. Tolerância à Falhas
Deixe falhar...
• Não se proteja de exceções
• Deixe outro lidar com o problema
Supervisores
• Erlang OTP
• Proteção em Profundidade
Estratégias de Supervisão
• OneForOne
• AllForOne
46. Tolerância à Falhas
Estado
• Recuperável
• Não-recuperável
Ganchos de reinicialização
• Antes da reinicialização
• Depois da reinicialização
Ciclo de vida
• Permanente
• Temporário
47. Só isso?
Encaminhando mensagens
para outro Ator
• getContext().forward(message,
getContext());
Alterando o comportamento de
um ator
• become(scatter);
• actor ! HotSwap( self => { case message
=> self.reply("hotswapped body") })
48. Só isso?
Dispatcher
• Por eventos
• Por thread
• Eventos priorizados
• Eventos com work-stealing
Routing
• Dispatcher (roteador, não módulo)
• Load balance
• Actor pool
Futuros
• Usados por atores, agentes, dataflow e outros componentes