Você está na página 1de 16

Akka: Programao concorrente

Fique por dentro


Este artigo ir apresentar um modelo de concorrncia baseado em troca de mensagens e uma implementao
deste modelo, o framework Akka. O desenvolvimento de aplicaes que demandam alto volume de
requisies e alta disponibilidade um grande desafio para quem adota o modelo convencional com threads
e locks.
Neste cenrio, o Akka uma opo interessante que usa um paradigma diferente de concorrncia que
possibilita uma escalabilidade muito grande.
Criar aplicaes que suportam alta concorrncia sempre foi um desafio, independente da tecnologia adotada.
O crescimento da capacidade de processamento dos computadores, resultado do aumento do nmero de
ncleos, memria, disco, etc. permitiu a criao de aplicaes com mais poder computacional e com suporte
a um maior nmero de requisies.
E quando o nmero de requisies extrapola a capacidade de um servidor, podemos ainda estruturar a
aplicao para funcionar em um cluster de mquinas, aumentando mais a capacidade de concorrncia.
Nos primrdios do Java, quando precisvamos lidar com concorrncia, crivamos uma ou vrias threads e
administrvamos manualmente esse volume necessrio para a execuo eficiente de determinada tarefa.
Na verso 5, o Java trouxe uma API de concorrncia de alto nvel, a java.util.concurrent [1], nos livrando
da gesto manual das threads atravs da utilizao de Executors. Algum tempo depois, no Java 7, foi
introduzido o Fork/Join framework [2], otimizando a utilizao de threads e elevando ainda mais a
capacidade de concorrncia.
Contudo, mesmo com estas evolues na API de concorrncia do Java, esta ainda se trata de algo de baixo
nvel quando desejamos criar aplicaes com alta concorrncia sem nos preocuparmos com detalhes de
threads, pool de threads, etc. Neste contexto, o Akka [3] um framework que nos oferece esta desejada
abstrao.
Escrito em Scala e com API para Scala e Java, o Akka foi desenvolvido sobre a API de concorrncia do Java
e que possibilita ao desenvolvedor utilizar um modelo de concorrncia baseado em atores. Com o Akka,
todas as buzzwords de concorrncia, como threads, pools, locks, etc., deixam de fazer sentido.
Assim, nos concentramos apenas na estruturao da nossa aplicao em atores e na lgica de negcio de
cada ator. Porm, antes de comearmos a falar de atores, vamos entender em que modelo de concorrncia os
atores se encaixam, para compreend-los melhor.
Modelos de concorrncia
De maneira generalista, podemos dividir os modelos de concorrncia em dois paradigmas: concorrncia
usando estado compartilhado e concorrncia usando troca de mensagens. O modelo de estado compartilhado
tem sido largamente adotado no campo, mas em aplicaes maiores ou com maior concorrncia, o modelo
de troca de mensagens preferido, pois sua caracterstica assncrona facilita a distribuio do
processamento, reduzindo gargalos.
Estado compartilhado x troca de mensagens
O modelo de estado compartilhado o modelo que adotamos normalmente em nossas aplicaes. Neste
modelo o cdigo a ser paralelizado executado simultaneamente atravs da criao de processos ou threads.
1

A complexidade aumenta quando estas threads precisam acessar a mesma informao (estado
compartilhado).
Para resolver este problema usamos blocos synchronized, que acabam gerando um gargalo na aplicao,
pois as instrues protegidas por synchronized so executadas apenas por uma thread por vez. Com o
crescimento da aplicao, consequentemente a quantidade de blocos synchronized cresce, eventualmente
causando lentido e casualmente um dead-lock.
Derek Wyatt, engenheiro de software atuante na comunidade Akka/Scala, no seu livro Akka Concurrency
[4], nos brinda com uma definio perfeita sobre este modelo: Em concorrncia com estado compartilhado
tendemos a criar os problemas primeiro, ento resolv-los usando primitivas de sincronizao.
. A Figura 1 ilustra o modelo de estado compartilhado e seus gargalos.

Figura 1. Representao grfica do modelo de concorrncia baseado em estado compartilhado.


No modelo de troca de mensagens (ver Figura 2) no temos o problema de locks encontrado no modelo de
estado compartilhado, pois os componentes no compartilham estado e se comunicam atravs de mensagens
predominantemente assncronas. O envio das mensagens normalmente feito por algum outro software que
atua como intermedirio entre os componentes.
Este desconhecimento entre os componentes garante um bom nvel de desacoplamento e favorece a
distribuio, pois permite a troca de mensagens entre componentes que estejam em servidores diferentes ou
at em outras redes. O modelo de atores uma derivao do modelo de troca de mensagens, e falaremos
sobre ele agora.
2

Figura 2. Representao grfica do modelo de concorrncia baseado em troca de mensagens.


Modelo de Atores
Em 1973, Carl Hewitt, Peter Bishop e Richard Steiger, introduziram pela primeira vez o modelo de atores,
no paper A Universal Modular Actor Formalism for Artificial Intelligence. Nos anos seguintes, diversas
intervenes foram feitas neste modelo e diversos papers foram publicados, o que culminou na definio da
teoria do modelo de atores.
Fundamentalmente, o modelo de atores prega que tudo so atores. Os atores so definidos como entidades
capazes de realizar um processamento computacional e que se comunicam entre si atravs do envio e
recebimento de mensagens.
Alm disso, podem criar outros atores, estabelecendo assim uma hierarquia entre eles. Como a comunicao
entre atores deve ser feita estritamente pela troca de mensagens, o estado interno de um ator no acessvel
por outros, mas somente por ele mesmo.
Aliando isso ao fato do processamento das mensagens ser sequencial, isto , um ator poder ter vrias
mensagens pendentes, mas apenas uma ser processada por vez, os problemas com locks simplesmente
deixam de existir. A Figura 3 mostra uma viso simplificada do modelo de atores.

Figura 3. Representao grfica do modelo de concorrncia baseado em atores


Com estas caractersticas, este tipo de soluo vem sendo adotado para aplicaes que processam grandes
volumes de dados, pois para atender esse tipo de demanda usando o modelo convencional de threads e o
processamento sncrono, ficamos limitados pela capacidade individual dos servidores.
Por sua vez, o modelo de atores permite uma distribuio mais fcil dos componentes da aplicao devido a
sua natureza assncrona e baseada em mensagens. O Erlang [5], linguagem originada na Ericsson com o
propsito de suportar aplicaes distribudas altamente concorrentes, possui em seu core uma
implementao deste modelo.
Contudo, apesar do Erlang ser uma linguagem de uso geral, no conquistou grande adoo. Em razo disso,
faltava ao mercado uma soluo para alta concorrncia baseada em atores. Assim surgiu o Akka.
Akka
O Akka foi desenvolvido em 2009 por Jonas Bonr, inspirado pelo modelo de atores do Erlang. Seu
primeiro release pblico, o Akka 0.5, foi anunciado em Janeiro de 2010. Atualmente esta soluo mantida
pela Typesafe Inc., a mesma empresa que mantm o Scala e o Play Framework. Recentemente, o Akka
passou a fazer parte da API padro do Scala, substituindo o modelo de atores original desta linguagem, e
apesar de ser escrito em Scala, possui uma API oficial tambm para Java.
De acordo com a definio da equipe, o Akka um toolkit e um runtime para construir aplicaes
altamente concorrentes, distribudas e tolerantes a falhas na JVM. Assim, aplicaes criadas usando o Akka
j nascem prontas para operar de maneira distribuda, pois esta caracterstica est na essncia do framework.
4

Criado com o foco em aplicaes distribudas e otimizado para operar de maneira standalone, o Akka prov:
Atores: conforme explicado anteriormente, a base do Akka sua implementao do modelo de atores;
Futures: apesar de podermos utilizar atores para resolver praticamente todos os problemas, s vezes pode
ser mais conveniente utilizar Futures. Os futures do Akka so muito parecidos com a implementao padro
do java.util.concurrent, porm possui integrao com atores;
Scheduler: integrado ao contexto de atores, o Akka permite o agendamento de tarefas usando vrios tipos
de schedulers.
Devido a estas caractersticas e recursos, o Akka vem sendo adotado por vrias empresas de porte. Dentre
elas, podemos citar a Amazon, Autodesk, Blizzard, VMware, dentre outros.
Hello World Primeiros passos
Uma forma de desenvolver aplicaes com o Akka fazer com que o framework seja uma dependncia do
projeto e usar a prpria aplicao para iniciar o sistema de atores. Alm dessa, existe outra opo para
desenvolver tais aplicaes: usando o Typesafe Activator, que um software que depois de instalado pode
ser utilizado para criar e executar aplicaes diversas baseadas em templates.
O Activator na verdade oferece muito mais, como por exemplo, uma IDE totalmente web para manuteno
dos projetos gerados por ele. Tanto o Activator quanto as dependncias do Akka podem ser obtidos na
pgina de downloads do site do prprio Akka [6]. Neste artigo, adotaremos a primeira opo, pois esta
permite uma compreenso melhor do funcionamento do framework.
Para criar uma aplicao usando o Akka podemos usar uma ferramenta de build como o Maven ou o SBT.
Aqui optaremos pelo Maven, por ele ser mais empregado pela comunidade. Antes de criar a aplicao, voc
deve ter o Eclipse com o plugin do Maven (m2e) instalado, ou apenas o Maven, caso voc prefira realizar o
build pela linha de comando.
Dito isso, crie um diretrio para hospedar o cdigo da aplicao, e depois crie o pom.xml com a dependncia
do Akka, conforme indica a Listagem 1.
Listagem 1. pom.xml base de uma aplicao com Akka.
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.devmedia.akka</groupId>
<artifactId>hello</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>

<dependencies>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor_2.10</artifactId>
<version>2.2.3</version>
</dependency>
</dependencies>
</project>

Em seguida, crie uma classe no diretrio src/main/java chamada Start. Esta classe ser responsvel por
iniciar a aplicao e o sistema de atores do Akka. Inicialmente ela deve estar vazia, conforme a Listagem 2.
Listagem 2. Classe que ir iniciar o sistema de atores do Akka.
public class Start {
public static void main(String[] args) {
// aqui inicializaremos o Akka
}
}

Agora, antes de pormos as mos na massa, vamos analisar o conceito de sistema de atores do Akka.
Actor System O container de atores
Como principal caracterstica, o Akka implementa um modelo de atores. De modo simples, este modelo diz
que tudo so atores. Sendo assim, a lgica da aplicao que normalmente programada em classes que
costumamos chamar de o modelo da aplicao ou os componentes de negcio, deve ser estruturada em
um ou vrios atores que se comunicam de maneira assncrona atravs da troca de mensagens, todos sob a
gesto do actor system.
Veremos adiante que para criar um ator basta estender uma determinada classe do Akka e usar a sua API
para solicitar a instanciao. Contudo, para dar vida aos atores, precisamos antes inicializar o container
Akka, ou seja, iniciar o actor system.
O actor system o ponto de partida de toda aplicao, por isso, deve ser criado assim que ela iniciar. Em
relao ao nmero de actor systems, uma aplicao pode iniciar vrios deles, porm este tipo de design no
indicado por questes de organizao.
Para criar um actor system devemos usar a classe akka.actor.ActorSystem, como demonstra a Listagem 3.
Listagem 3. Criao do actor system.
import akka.actor.ActorSystem;
public class Start {
public static void main(String[] args) {
// Criao de um Actor System, container Akka.
ActorSystem system = ActorSystem.create("HelloSystem");
}
}

Podemos observar que o construtor do actor system recebe um texto como parmetro para definir o seu
nome. Este nome deve ser nico por aplicao e tambm deve ser nico por container, caso a aplicao seja
instalada em um microcontainer Akka. Como veremos adiante, o nome do actor system tambm ir compor
o path de localizao do ator.
6

Atores em todos os lugares


De acordo com a explicao anterior, no modelo de atores um ator um objeto capaz de receber e enviar
mensagens, alm de criar outros atores. No processamento das mensagens recebidas est a lgica de negcio
do ator. No exemplo que estamos desenvolvendo, iremos criar um ator que recebe uma mensagem e exibe
esta mensagem no console.
No Akka, para criarmos a classe de um ator, devemos estender a classe abstrata akka.actor.UntypedActor
e implementar o mtodo void onReceive(Object msg). Este mtodo responsvel pelo processamento das
mensagens. Deste modo, crie a classe EcoActor em src/main/java contendo o cdigo da Listagem 4.
Listagem 4. Um ator que exibe no console a mensagem recebida.
import akka.actor.UntypedActor;
import akka.event.LoggingAdapter;
import akka.event.Logging;
public class EcoActor extends UntypedActor {
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
@Override
public void onReceive(Object msg) throws Exception {
log.info("Mensagem recebida: " + msg);
}
}

Deixando os detalhes de criao do logger para depois, podemos reparar que a classe de um ator simples.
importante notar que a mensagem pode ser qualquer objeto Java, porm razovel que este implemente
Serializable (apesar do Akka no obrigar) para no termos problemas em um ambiente distribudo, onde
mensagens so serializadas para trafegar pela rede.
Voltando para a classe Start, agora que temos um ator implementado, podemos usar o actor system para
efetivamente dar vida a este ator. Assim, usamos o mtodo actorOf() de actor system para criar o ator. Este
mtodo recebe como parmetro uma instncia de akka.actor.Props e uma String com o nome que o ator
ter no actor system. Props uma classe que define um objeto de configurao, usado apenas para criar
atores.
Para a construo do objeto Props, usamos o mtodo esttico Props.create(), passando como parmetro a
classe do ator. Existem muitas maneiras de construir Props, mas para o nosso exemplo, usaremos a forma
mais simples. A Listagem 5 mostra a classe Start alterada, com a criao do ator.
Listagem 5. Criando o ator EcoActor.
import akka.actor.ActorSystem;
import akka.actor.ActorRef;
import akka.actor.Props;
public class Start {
public static void main(String[] args) {
// Criao de um Actor System, que o container Akka.
ActorSystem system = ActorSystem.create("HelloSystem");
// Criando o ator EcoActor
ActorRef actor = system.actorOf(Props.create(EcoActor.class), "eco");
}
}

importante perceber que o que obtemos ao criar um ator um ActorRef e no um objeto com a classe do
ator propriamente dita (EcoActor). Nesta informao reside um grande conceito do Akka e do modelo de
atores: os detalhes do ator no so expostos para quem envia a mensagem, pois o estado interno deste deve
ser visvel apenas para ele mesmo. Isso fica bem claro na implementao do ator.
Basta percebermos que o cdigo processado por ele (sua lgica de negcio) se restringe ao mtodo
onReceive(), que chamado pelo Akka para processar as mensagens. Como as mensagens so processadas
uma por vez (ou seja, apenas uma thread por vez), no existe nenhuma necessidade de blocos synchronized.
Com isso, locks e deadlocks no existem neste modelo.
ActorRef a interface para comunicao com o ator criado e o mtodo ActorRef.tell() utilizado para
enviar uma mensagem para este ator. Este mtodo recebe como parmetro a mensagem e o ator que a est
enviando. Como estamos enviando a mensagem do mtodo main() da casse Start (isto , no um ator que
est enviando a mensagem), usaremos ActorRef.noSender(), que um mtodo auxiliar que retorna uma
constante para identificar ao actor system que no existe nenhum ator origem. A Listagem 6 mostra o envio
dessa mensagem ao ator.
Listagem 6. Enviando uma mensagem para EcoActor.
import akka.actor.ActorSystem;
import akka.actor.ActorRef;
import akka.actor.Props;
public class Start {
public static void main(String[] args) {
// Criao de um Actor System, que o container Akka.
ActorSystem system = ActorSystem.create("HelloSystem");
// Criando o ator EcoActor
ActorRef ecoActor = system.actorOf(Props.create(EcoActor.class), "eco");
// Enviando a mensagem ao ator
ecoActor.tell("Al Mundo com Atores", ActorRef.noSender());
}
}

Com essas duas classes j possvel ver o Akka em ao, mas antes, precisamos compilar a aplicao. Para
isso, usaremos o Maven atravs do comando mvn clean install. Em seguida, executaremos a aplicao
tambm pelo Maven, com o plugin exec:java, como indica a Listagem 7.
Listagem 7. Executando a aplicao.
$ mvn clean install exec:java -Dexec.mainClass=Start
.
. (detalhes do build omitidos)
.
[INFO]
[01/01/2014
19:00:00.384]
[HelloSystem-akka.actor.default-dispatcher-3]
[akka://HelloSystem/user/eco] Mensagem recebida: Al Mundo com Atores

Note que a mensagem enviada (Al Mundo com Atores) foi processada pelo ator e impressa no console
conforme esperado. O log do actor system ainda informa o timestamp, o nome da thread e o nome do ator
que est logando.
Falaremos destes detalhes adiante. Para interromper a execuo, digite Ctrl+c, caso contrrio o actor system
continuar executando.
8

Antes de partir para a modelagem de uma aplicao mais prxima do real, vamos apresentar algumas
funcionalidades do Akka usando o tradicional Hello, World!.
Atores criando atores
Conforme descrito anteriormente, um ator pode iniciar (ou criar) outros atores, estabelecendo uma
hierarquia entre eles. Esta hierarquia definida de acordo com a modelagem da aplicao. Contudo, nada
impede de modelarmos uma aplicao usando o Akka e criar todos os atores na raiz do actor system, como
fizemos com EcoActor.
Apesar dessa possibilidade, por questes de organizao e de gesto de excees, importante definir uma
estrutura coesa de atores e normalmente isso implica em vrios nveis.
Para criar um ator a partir de outro, indicado faz-lo dentro do mtodo preStart() de UntypedActor,
apesar de nada impedir de fazermos isso sob demanda, ou seja, na primeira vez que o ator for utilizar o ator
filho.
O actor system executa o prestar() (dentre outros que ainda analisaremos do ciclo de vida dos atores) antes
de completar a inicializao de um ator. Sendo assim, este um excelente lugar para inicializar eventuais
estados internos do ator, como por exemplo, dependncia de outros atores ou atributos privados utilizados
por ele.
Tendo em vista estas informaes, vamos alterar o cdigo da aplicao exemplo para que o EcoActor crie
um ator na sua inicializao e repasse toda mensagem recebida por ele para este ator filho.
Para isso, declare uma classe chamada ChildActor com o mesmo cdigo de EcoActor (ver Listagem 4).
Agora, devemos alterar EcoActor, sobrescrever o mtodo preStart() e instanciar o ator filho, do tipo
ChildActor. Assim como a criao de um ator via actor system, para instanciar um ator dentro de outro
usamos o mtodo actorOf() do contexto do ator.
Este contexto obtido atravs do mtodo getContext(). A Listagem 8 mostra a implementao do mtodo
preStart() e a criao do ator filho, bem como o repasse das mensagens recebidas em onReceive().
Listagem 8. Criando um ator filho via getContext().
public class EcoActor extends UntypedActor {
LoggingAdapter log = Logging.getLogger(getContext().system(), this);
//Declaramos o ator filho como atributo de EcoActor
private ActorRef childActor;
@Override
public void preStart() throws Exception {
super.preStart();
//Na inicializao do ator, instanciamos o ator filho
childActor = getContext().actorOf(Props.create(ChildActor.class), "childOfEco");
}
@Override
public void onReceive(Object msg) throws Exception {
log.info("Mensagem recebida: " + msg);
//Repassamos a mensagem recebida para o ator filho
childActor.tell(msg, getSelf());
}

Para ver os resultados destas alteraes, devemos repetir os comandos de compilao e execuo via Maven,
como mostra a Listagem 9.
Listagem 9. Executando a aplicao.
$ mvn clean install exec:java -Dexec.mainClass=Start
.
. (detalhes do build omitidos)
.
[INFO]
[01/01/2014
10:29:26.722]
[HelloSystem-akka.actor.default-dispatcher-2]
[akka://HelloSystem/user/eco] Mensagem recebida: Al Mundo com Atores
[INFO]
[01/01/2014
10:29:26.722]
[HelloSystem-akka.actor.default-dispatcher-3]
[akka://HelloSystem/user/eco/childOfEco] Mensagem recebida: Al Mundo com Atores

O log exibido no resultado mostra claramente a hierarquia dos atores, exposta pelo path do ator. Repare que
a mensagem foi recebida por EcoActor, que tem o path akka://HelloSystem/user/eco, e repassada ao ator
filho, que tem o path akka://HelloSystem/user/eco/childOfEco.
O path de um ator uma URI nica que o identifica. Ela composta pelo protocolo (akka://), o identificador
do actor system (HelloSystem), pela raiz dos atores criados pela aplicao (user), o identificador do ator pai
(caso exista) e o identificador do prprio ator. Sendo assim, na estrutura de atores criada pela aplicao
exemplo, temos dois atores identificveis por dois paths:
akka://HelloSystem/user/eco
akka://HelloSystem/user/eco/childOfEco
O identificador do actor system (HelloSystem) definido no start da aplicao, e o identificador de cada ator
definido no momento de sua criao. Apenas o prefixo user algo imposto pelo Akka, pois ele define a
raiz da hierarquia dos atores. Na prtica, todos os atores criados pelas aplicaes desenvolvidas com Akka
ficaro sob o guardio chamado user. Existem guardies disponveis para diversas finalidades, a saber:

/user: o guardio de todos os atores criados pelo cdigo da aplicao desenvolvida usando Akka;

/system: Este o guardio de atores criados pelo prprio Akka, para manter o funcionamento do
framework;
/deadLetters: um ator que recebe as mensagens enviadas para atores inexistentes, ou atores que no
esto em funcionamento;
/temp: o guardio de atores criados para necessidades temporrias, isto , so atores de vida curta;
/remote: Este um guardio para paths virtuais, que representam atores remotos, ou seja, que estejam
instanciados em outras JVMs.
Mensagens tipadas
muito comum no desenvolvimento de aplicaes Akka um determinado ator ser programado para receber
vrios tipos de mensagens e realizar processamentos distintos de acordo com a mensagem. Neste caso o
padro adotado utilizar classes diferentes para representar os diferentes tipos de mensagens.
A vantagem de usar este padro que ele deixa claro e visvel os tipos de mensagens que um ator processa e
principalmente os que ele no processa. Para exemplificar, vamos refatorar nosso cdigo para enviar uma
10

mensagem tipada para nossos atores e refutar qualquer outra mensagem. Para isto, criaremos uma classe
chamada HelloMessage, conforme a Listagem 10.
Listagem 10. Classe que representar a mensagem.
public class HelloMessage {
}

Como pode ser observado, esta classe no contm nenhum estado interno, pois o seu propsito apenas
identificar um tipo de mensagem. Dito isso, depois de cri-la, devemos alterar os nossos atores, para deixar
claro que eles recebem e processam apenas esse tipo de mensagem. Sendo assim, o mtodo receive() de
EcoActor deve ficar como exposto na Listagem 11.
Listagem 11. Alterao do mtodo onReceive() de EcoActor.
@Override
public void onReceive(Object msg) throws Exception {
if (msg instanceof HelloMessage) {
log.info("Mensagem recebida: " + msg);
// repassamos a mensagem recebida para o ator filho
childActor.tell(msg, getSelf());
}
else {
// informa ao actor system que este ator no processa esta mensagem
unhandled(msg);
}
}

Repare que usamos instanceof para filtrar as mensagens processadas de acordo com o tipo destas. Neste
cdigo importante ressaltar a chamada ao mtodo unhandled(), que deixa claro ao actor system que esta
mensagem no foi processada pelo ator. Deste modo, ela ser considerada pelo actor system para eventuais
tratamentos futuros.
Se o mtodo unhandled() no for chamado, o actor system no tem como saber que a mensagem no foi
processada. Para dar continuidade ao exemplo, devemos alterar tambm ChildActor, para receber apenas
mensagens do tipo HelloMessage. Veja a Listagem 12.
Listagem 12. Alterao do mtodo onReceive() de ChildActor.
@Override
public void onReceive(Object msg) throws Exception {
if (msg instanceof HelloMessage) {
log.info("Mensagem recebida: " + msg);
}
else {
unhandled(msg);
}
}

Ao executarmos a aplicao (Listagem 9) aps essas alteraes, ser possvel notar que nenhum log ser
exibido. Isso facilmente explicado pelo fato de nossos atores agora apenas processarem mensagens do tipo
HelloMessage e a mensagem enviada pela classe Start ser do tipo String. Para corrigir isso, devemos
alterar a classe Start de acordo com a Listagem 13.
Listagem 13. Alterando o envio da mensagem em Start.
11

// Enviando a mensagem ao ator


ecoActor.tell(new HelloMessage(), ActorRef.noSender());

Com essa simples mudana, ao reexecutar a aplicao teremos o resultado apresentado na Listagem 14.
Listagem 14. Resultado da reexecuo aps as alteraes.
$ mvn clean install exec:java -Dexec.mainClass=Start
.
. (detalhes do build omitidos)
.
[INFO]
[02/02/2014
11:22:00.668]
[HelloSystem-akka.actor.default-dispatcher-3]
[akka://HelloSystem/user/eco] Mensagem recebida: HelloMessage@7ee14288
[INFO]
[02/02/2014
11:22:00.668]
[HelloSystem-akka.actor.default-dispatcher-4]
[akka://HelloSystem/user/eco/childOfEco] Mensagem recebida: HelloMessage@7ee14288

Supervisores e estratgia de recuperao


Todos sabem o que acontece quando uma exceo lanada em um sistema convencional. A exceo
lanada a camadas superiores de servios at que uma dessas camadas tenha a capacidade de lidar com ela.
No modelo de atores o que acontece um pouco diferente, evidentemente por conta do desacoplamento
entre os componentes e pela caracterstica assncrona das chamadas.
Quando uma exceo lanada no processamento de uma mensagem, o supervisor do ator que lanou a
exceo deve decidir o que vai acontecer com o ator. O supervisor de um ator o ator que o criou, ou seja, o
seu pai.
Caso o ator tenha sido criado diretamente pelo actor system (como os atores criados na classe Start nos
exemplos), o ator no tem um pai conhecido ou explcito. Neste caso, o supervisor passa a ser o ator
guardio, ou seja, /user.
Antes de vermos o que pode acontecer com um ator que lana uma exceo, vamos entender um pouco mais
a respeito do ciclo de vida dos atores.
Ciclo de vida de um ator
importante ressaltar que no Akka a(s) vida(s) dos atores (so) representada(s) por encarnaes (ver
Figura 4). Isso significa que um ator pode nascer, morrer e reencarnar (nascer novamente) e assim
sucessivamente. O termo encarnao de fato utilizado na documentao do Akka e traz luz alguns
conceitos interessantes da vida do ator, a saber:
1. Inicialmente um ator simplesmente no existe at o ponto em que alguma chamada por actorOf()
executada, seja no actor system (raiz) ou pelo contexto de outro ator;
2. Aps a chamada de actorOf() o ator ainda no est encarnado, ou seja, ainda no responde por
mensagens, porm tem: o path reservado; um identificador nico (UID); a instncia do objeto criada; o
mtodo preStart() executado.
3. Aps a execuo do preStart() o ator est encarnado e recebendo/processando as mensagens destinadas a
ele;
4. Neste ponto algo errado pode acontecer e o ator pode lanar uma exceo. Assim, o ator passa para um
estado temporrio que chamaremos de doente. Neste momento o supervisor do ator deve decidir o que fazer
com o ator doente, tendo trs opes:
12

a. Continuar. Simplesmente ignorar que a exceo aconteceu e continuar com a vida do ator, processando
as mensagens normalmente;
b. Reiniciar o ator. O mtodo preRestart() executado na instncia em execuo, uma nova instncia
criada e o mtodo postRestart() executado na nova instncia. O path do ator se mantm, assim como o
UID, caracterizando uma mesma encarnao;
c. Encerrar o ator (morte). O ator pode ser terminado pelo seu supervisor ou pelo envio de uma mensagem
que o finalize (existe uma mensagem no Akka do tipo akka.actor.PoisonPill, que ao ser consumida por um
ator causa sua interrupo). Neste ponto, o mtodo postStop() executado. Caso o ator seja iniciado
novamente, uma nova encarnao ser criada, tendo o mesmo path, porm com um novo UID.

Figura 4. Ciclo de vida dos atores no container do Akka.


A definio da estratgia de recuperao feita no supervisor, ou seja, no ator pai, e vale para todos os seus
filhos. Caso o supervisor de um ator no defina a estratgia de recuperao dos seus filhos, se o ator em
questo lanar uma exceo, o Akka tenta usar a estratgia definida pelo pai do pai e assim sucessivamente
at a raiz, isto , o ator guardio /user.
Para definir uma estratgia de recuperao em um ator, devemos sobrescrever o mtodo
supervisorStrategy() de UntypedActor. Este mtodo deve retornar uma instncia de
akka.actor.SupervisorStrategy, que pode ser de dois tipos:
OneForOneStrategy: Se o retorno do mtodo supervisorStrategy() for uma instncia de
OneForOneStrategy, significa que a ao tomada ir afetar apenas o ator que lanou a exceo, ou seja, o
ator doente;
13

AllForOneStrategy: Se o retorno do mtodo supervisorStrategy() for uma instncia de


AllForOneStrategy, a ao tomada ser aplicada a todos os atores filhos do supervisor que est definindo a
estratgia.
O trecho de cdigo da Listagem 15 mostra a criao de uma estratgia de recuperao implementada em um
ator.
Listagem 15. Implementao de uma estratgia de recuperao.
@Override
public SupervisorStrategy supervisorStrategy() {
return
new
OneForOneStrategy(-1,
Duration.Inf(),
Directive>() {
public Directive apply(Throwable t) throws Exception {
return OneForOneStrategy.resume();
}
});
}

new

Function<Throwable,

Para implementar uma estratgia de recuperao em um supervisor (um ator com filhos), devemos
sobrescrever o mtodo supervisorStrategy(), que por sua vez, deve retornar uma instncia de
SupervisorStrategy. No caso do cdigo exemplo, foi escolhida a opo akka.actor.OneForOneStrategy.
Isso significa que a estratgia de recuperao ser aplicada apenas no ator que lanou a exceo.
Para construir um objeto do tipo OneForOneStrategy devemos informar trs parmetros no construtor:
maxNrOfRetries (nmero mximo de tentativas de reincio do ator), withinTimeRange (intervalo entre a
primeira e a ltima tentativa de reincio) e decider.
Deixando de lado os dois primeiros parmetros, o decider, ou decisor, deve ser uma implementao da
interface akka.japi.Function e possuir apenas o mtodo chamado apply(), que recebe como parmetro um
Throwable e retorna um akka.actor.SupervisorStrategy.Directive (explicado adiante).
Quando a aplicao estiver em execuo e um determinado ator lanar uma exceo no processamento de
uma mensagem, o Akka ir executar o mtodo apply() do objeto decider definido na estratgia do ator pai
passando como parmetro a exceo lanada e obtendo como retorno uma diretiva a ser utilizada para tomar
a devida ao.
As diretivas podem ser do tipo:
resume: Ignora a exceo atirada pelo ator supervisionado (filho). A mensagem simplesmente deixa de ser
processada e o ator continua processando normalmente outras mensagens;

restart: Reinicia o ator, conforme explicado anteriormente, na descrio do ciclo de vida do ator;
escalate: Repassa a deciso do que deve ser feito para o supervisor diretamente acima;
stop: Finaliza (mata) o ator.

Voltando a falar dos dois primeiros parmetros da construo de OneForOneStrategy, so aplicveis


somente ao de restart. O primeiro parmetro diz quantas vezes o ator pode ser reiniciado e o segundo
parmetro diz em qual intervalo esta quantidade de reincios pode acontecer.
Este tipo de estratgia faz sentido em situaes de erros intermitentes, por exemplo, uma dependncia de
uma conexo com o banco de dados. Caso este nmero seja ultrapassado no intervalo definido, o ator
finalizado (morto) e as mensagens enviadas para ele so perdidas.
Modelando atores
14

Assim como qualquer paradigma de desenvolvimento, o modelo de atores tem as suas peculiaridades. Ao
desenvolver uma aplicao usando este modelo, devemos estruturar a aplicao em atores, considerando que
a comunicao entre eles assncrona e realizada atravs troca de mensagens. Depois de uma vida inteira
desenvolvendo aplicaes com o modelo tradicional de concorrncia, inicialmente este paradigma poder
parecer um pouco confuso.
Para facilitar o aprendizado a respeito, existe uma grande quantidade de material na internet relacionada
modelagem de atores, mas para ficar apenas no universo do Akka, uma boa referncia o site Let It Crash
[7], mantido pela comunidade. Este site possui trechos de cdigo, artigos, discusses e outros contedos
relacionados ao desenvolvimento com Akka.
Prximos passos
Este artigo procurou introduzir os princpios bsicos do paradigma de concorrncia baseado em atores e o
framework Akka. Por esse motivo, ainda existe muito a ser explorado.
Pensando em facilitar os prximos passos, e direcionando nosso foco para o Akka, a seguir listamos os
tpicos mais importantes que o leitor pode se aprofundar:
Mailbox: Apesar do Akka abstrair a existncia deles, cada instncia de ator possui uma caixa de
mensagens, ou mailbox. Existem vrios tipos de customizaes que podem ser feitas com este recurso, como
por exemplo, podemos criar uma caixa de mensagens para vrios atores, balanceando o consumo, realizando
uma espcie de load balancing de processamento de mensagens;
Dispatchers: So implementaes de ExecutionContext que regem a criao das threads de
processamento de mensagens, schedulers e todo o funcionamento do framework. Tambm possui um alto
grau de customizao;
Persistncia: possvel configurar o Akka para persistir o estado interno de um ator, inclusive o seu
mailbox. Sendo assim, caso a aplicao caia ou seja desligada indevidamente, no restart do container este
estado recuperado. Este mdulo ainda experimental no Akka e foi introduzido na verso 2.3.0 do
framework;
Extenses: O Akka oferece um mecanismo padro para criar extenses. Com ele podemos atuar sobre
elementos centrais do framework, como o Actor system, para modificar o seu comportamento.
O modelo de concorrncia baseado em threads e estado compartilhado tem atendido razoavelmente as
necessidades do mercado, porm, quando nos deparamos com o desafio de construir uma aplicao que
suporte alta concorrncia e alta disponibilidade, importante considerarmos um modelo baseado em
mensagens assncronas.
No ecossistema do Java, o Akka a ferramenta ideal para esta finalidade e tem se tornado mais completo a
cada release. Alm de suas qualidades tcnicas, seguro apostar no Akka no apenas por tratar-se de uma
tecnologia suportada e mantida por uma empresa do porte da Typesafe, mas tambm por ser um excelente
framework, leve, bem estruturado, modular e muito fcil de escalar.
Links
[1] Pgina da API de concorrncia do Java.
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/packagesummary.html

15

[2] Documentao do Fork/Join framework.


http://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html
[3] Pgina principal do Akka.
http://akka.io
[4] Pgina da Amazon do livro Akka Concurrency, de Derek Wyatt.
http://www.amazon.com/Akka-Concurrency-Derek-Wyatt/dp/0981531660
[5] Pgina da linguagem de programao Erlang.
http://www.erlang.se
[6] Pgina de downloads do Akka.
http://akka.io/downloads/
[7] Pgina de um grupo de desenvolvedores da comunidade Akka.
http://letitcrash.com

16

Você também pode gostar