O documento apresenta o framework Akka 2.0 para programação concorrente e tolerância a falhas. O Akka abstrai preocupações de baixo nível como threads e locks através do modelo de atores, onde entidades independentes se comunicam através de troca de mensagens de forma assíncrona. O Akka oferece escalabilidade horizontal e vertical e permite a criação hierárquica de atores.
5. Abstração!
● em OO aprendemos a abstrair conceitos
● programação concorrente não pode ser
abstraída?
● porque nos preocupar com Threads?
● e com locks?
● e em fazer isso direito...
6. Akka 2.0
● inspirado em Erlang
● abstrai preocupações baixo nível
● pensamos mais nos problemas de negócio
● API Java e Scala
● Actor Model !
7. Actor Model
● entidades independentes
● estado
● comportamento
● mailbox
● como uma classe em OO...
● ... mas mais "pura"
10. Abstração == Overhead?
● overhead do Akka é ínfimo
● extraído da página oficial:
● "50 million msg/sec on a single machine."
● obviamente, em um micro-benchmark...
12. Threads... cadê?
● Akka cria as threads necessárias
● ator != thread
● atores usando threads disponíveis
● akka fornece uma thread para o ator
● sem locks
13. Divisão de trabalho
● threads usando os "cores" disponíveis
● fork-join por padrão
● fork-join estará no Java 8...
● ... mas já está embutido no Akka
● tudo configurável
14. config. extraída da documentação:
fork-join-executor {
# Min number of threads to cap factor-based parallelism number to
parallelism-min = 8
# Parallelism (threads) ... ceil(available processors * factor)
parallelism-factor = 3.0
# Max number of threads to cap factor-based parallelism number to
parallelism-max = 64
}
15. Imutabilidade
● origem de muitos problemas
● para não precisar de locks
● nunca teremos deadlocks
● desnecessário sincronizar acesso ao estado
16. Uma mensagem - Scala
case class SendToS3(fileName: String)
17. Uma mensagem - Java
public class SendToS3 {
private final String fileName;
public SendToS3(String fileName) {
this.fileName = fileName;
}
public String getFileName() {
return fileName;
}
}
18. Um ator - Scala
class S3SenderActor extends Actor {
def receive = {
case SendToS3(fileName) =>
// lógica de negócios aqui
}
}
19. Um ator - Java
public class S3SenderActor extends UntypedActor {
public void onReceive(Object message)
throws Exception {
if (message instanceof String)
// lógica de negócios aqui
else
unhandled(message);
}
}
20. Lidando com alteração de estado
● atores não devem compartilhar estado
● um único ator será responsável pelos dados
● acesso a BD pode ser enfileirado
● ou atores responsáveis por "fatias" de dados
● veremos exemplo disso mais adiante
21. Criando atores
● métodos / classes especiais
● atores criados abaixo da raiz do nó principal
● ... ou relativos ao contexto atual
● todo ator tem um "pai"
● veremos mais sobre isso adiante
22. Criando um ator - Scala
val system = ActorSystem("MyActorSystem")
// ator com construtor default
val ator =
system.actorOf(Props[S3SenderAtor])
// ator com outro construtor
val ator2 =
system.actorOf(Props(new Ator(<params>)))
23. Criando um ator - Java
ActorSystem system =
ActorSystem.create("MyActorSystem");
// ator com construtor default
ActorRef ator = system.actorOf(
new Props(S3SenderActor.class));
24. Criando um ator - Java
// ator com outro construtor
ActorRef ator2 = system.actorOf(
new Props(new UntypedActorFactory() {
public UntypedActor create() {
return new Ator(<params>);
}
})
);
25. Protegendo o estado
val minhaInstancia = new Ator(<params>)
// erro em runtime
val ator2 =
system.actorOf(Props(minhaInstancia))
26. Atores relativos ao contexto
● todo ator tem um campo "context"
● esse campo pode criar novos atores
● esses atores serão "filhos" do ator atual
context.actorOf(Props[S3SenderActor])
27. "let it crash"
● tolerância a falhas
● não evitamos que atores quebre
● e decidimos o que fazer quando acontecer
● todo ator é supervisionado (2.0+)
● o supervisor decide o que fazer
32. Config. de tolerância a falhas - Scala
override val supervisorStrategy =
OneForOneStrategy(
maxNrOfRetries = 10, withinTimeRange = 1 minute) {
case _: ArithmeticException ⇒ Resume
case _: NullPointerException ⇒ Restart
case _: IllegalArgumentException ⇒ Stop
case _: Exception ⇒ Escalate
}
33. Config. de tolerância a falhas - Java
private static SupervisorStrategy strategy =
new OneForOneStrategy(10, Duration.parse("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();
}
}
});
34. Config. de tolerância a falhas - Java
@Override
public SupervisorStrategy supervisorStrategy() {
return strategy;
}
obs: exemplos de configs extraídos da doc.
35. Ponto para divisão de tarefas
● recomenda-se quebrar as tarefas
● roteadores são uma forma de fazer isso
● definem grupos de atores
● e o roteador divide as mensagens
39. Projeto Open Source: Lojinha
● um ator para lances de cada produto
● aguentaria milhões de produtos
● da página oficial do Akka:
"Small memory footprint; ~2.7 million actors per
GB of heap."
40. Atores da Lojinha
Play Akka
System
Image
Master Bid
Thumb
Actor
Router
S3 Sender
Router
Image
Process
Thumb
Bid Actor
S3 Sender Actor
Actor
um para cada produto vários, conforme configurado
vários, conforme configurado
41. código!
● lojinha no NetBeans...
● ... se der tempo
● senão, está tudo no github =)
42. Referências
● site oficial: akka.io
● meu blog: jcranky.com
● meu twitter: twitter.com/jcranky
● lojinha, no github: https://github.
com/jcranky/lojinha
43. coming soon...
● curso de Scala na Globalcode
● mais informações nas próximas semanas
● tópicos principais:
○ Scala
○ Akka
○ Play Framework