1 Akka: Programação concorrente Fique por dentro Este artigo irá apresentar um modelo de concorrência baseado em troca de mensagens e uma implementação deste modelo, o framework Akka. O desenvolvimento de aplicações que demandam alto volume de requisições e alta disponibilidade é um grande desafio para quem adota o modelo convencional com threads e locks. Neste cenário, o Akka é uma opção interessante que usa um paradigma diferente de concorrência que possibilita uma escalabilidade muito grande. Criar aplicações que suportam alta concorrência sempre foi um desafio, independente da tecnologia adotada. O crescimento da capacidade de processamento dos computadores, resultado do aumento do número de núcleos, memória, disco, etc. permitiu a criação de aplicações com mais poder computacional e com suporte a um maior número de requisições. E quando o número de requisições extrapola a capacidade de um servidor, podemos ainda estruturar a aplicação para funcionar em um cluster de máquinas, aumentando mais a capacidade de concorrência. Nos primórdios do Java, quando precisávamos lidar com concorrência, criávamos uma ou várias threads e administrávamos manualmente esse volume necessário para a execução eficiente de determinada tarefa. Na versão 5, o Java trouxe uma API de concorrência de alto nível, a java.util.concurrent [1], nos livrando da gestão manual das threads através da utilização de Executors. Algum tempo depois, no Java 7, foi introduzido o Fork/Join framework [2], otimizando a utilização de threads e elevando ainda mais a capacidade de concorrência. Contudo, mesmo com estas evoluções na API de concorrência do Java, esta ainda se trata de algo de baixo nível quando desejamos criar aplicações com alta concorrência sem nos preocuparmos com detalhes de threads, pool de threads, etc. Neste contexto, o Akka [3] é um framework que nos oferece esta desejada abstração. Escrito em Scala e com API para Scala e Java, o Akka foi desenvolvido sobre a API de concorrência do Java e que possibilita ao desenvolvedor utilizar um modelo de concorrência baseado em atores. Com o Akka, todas as buzzwords de concorrência, como threads, pools, locks, etc., deixam de fazer sentido. Assim, nos concentramos apenas na estruturação da nossa aplicação em atores e na lógica de negócio de cada ator. Porém, antes de começarmos a falar de atores, vamos entender em que modelo de concorrência os atores se encaixam, para compreendê-los melhor. Modelos de concorrência De maneira generalista, podemos dividir os modelos de concorrência em dois paradigmas: concorrência usando estado compartilhado e concorrência usando troca de mensagens. O modelo de estado compartilhado tem sido largamente adotado no campo, mas em aplicações maiores ou com maior concorrência, o modelo de troca de mensagens é preferido, pois sua característica assíncrona facilita a distribuição do processamento, reduzindo gargalos. Estado compartilhado x troca de mensagens O modelo de estado compartilhado é o modelo que adotamos normalmente em nossas aplicações. Neste modelo o código a ser paralelizado é executado simultaneamente através da criação de processos ou threads.
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
1
Akka: Programação concorrente
Fique por dentro
Este artigo irá apresentar um modelo de concorrência baseado em troca de mensagens e uma implementação
deste modelo, o framework Akka. O desenvolvimento de aplicações que demandam alto volume de
requisições e alta disponibilidade é um grande desafio para quem adota o modelo convencional com threads
e locks.
Neste cenário, o Akka é uma opção interessante que usa um paradigma diferente de concorrência que
possibilita uma escalabilidade muito grande.
Criar aplicações que suportam alta concorrência sempre foi um desafio, independente da tecnologia adotada.
O crescimento da capacidade de processamento dos computadores, resultado do aumento do número de
núcleos, memória, disco, etc. permitiu a criação de aplicações com mais poder computacional e com suporte
a um maior número de requisições.
E quando o número de requisições extrapola a capacidade de um servidor, podemos ainda estruturar a
aplicação para funcionar em um cluster de máquinas, aumentando mais a capacidade de concorrência.
Nos primórdios do Java, quando precisávamos lidar com concorrência, criávamos uma ou várias threads e
administrávamos manualmente esse volume necessário para a execução eficiente de determinada tarefa.
Na versão 5, o Java trouxe uma API de concorrência de alto nível, a java.util.concurrent [1], nos livrando
da gestão manual das threads através da utilização de Executors. Algum tempo depois, no Java 7, foi
introduzido o Fork/Join framework [2], otimizando a utilização de threads e elevando ainda mais a
capacidade de concorrência.
Contudo, mesmo com estas evoluções na API de concorrência do Java, esta ainda se trata de algo de baixo
nível quando desejamos criar aplicações com alta concorrência sem nos preocuparmos com detalhes de
threads, pool de threads, etc. Neste contexto, o Akka [3] é um framework que nos oferece esta desejada
abstração.
Escrito em Scala e com API para Scala e Java, o Akka foi desenvolvido sobre a API de concorrência do Java
e que possibilita ao desenvolvedor utilizar um modelo de concorrência baseado em atores. Com o Akka,
todas as buzzwords de concorrência, como threads, pools, locks, etc., deixam de fazer sentido.
Assim, nos concentramos apenas na estruturação da nossa aplicação em atores e na lógica de negócio de
cada ator. Porém, antes de começarmos a falar de atores, vamos entender em que modelo de concorrência os
atores se encaixam, para compreendê-los melhor.
Modelos de concorrência
De maneira generalista, podemos dividir os modelos de concorrência em dois paradigmas: concorrência
usando estado compartilhado e concorrência usando troca de mensagens. O modelo de estado compartilhado
tem sido largamente adotado no campo, mas em aplicações maiores ou com maior concorrência, o modelo
de troca de mensagens é preferido, pois sua característica assíncrona facilita a distribuição do
processamento, reduzindo gargalos.
Estado compartilhado x troca de mensagens
O modelo de estado compartilhado é o modelo que adotamos normalmente em nossas aplicações. Neste
modelo o código a ser paralelizado é executado simultaneamente através da criação de processos ou threads.
2
A complexidade aumenta quando estas threads precisam acessar a mesma informação (estado
compartilhado).
Para resolver este problema usamos blocos synchronized, que acabam gerando um gargalo na aplicação,
pois as instruções protegidas por synchronized são executadas apenas por uma thread por vez. Com o
crescimento da aplicação, consequentemente a quantidade de blocos synchronized cresce, eventualmente
causando lentidão 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 definição perfeita sobre este modelo: “Em concorrência com estado compartilhado
tendemos a criar os problemas primeiro, então resolvê-los usando primitivas de sincronização.”
. A Figura 1 ilustra o modelo de estado compartilhado e seus gargalos.
Figura 1. Representação gráfica do modelo de concorrência baseado em estado compartilhado.
No modelo de troca de mensagens (ver Figura 2) não temos o problema de locks encontrado no modelo de
estado compartilhado, pois os componentes não compartilham estado e se comunicam através de mensagens
predominantemente assíncronas. O envio das mensagens normalmente é feito por algum outro software que
atua como intermediário entre os componentes.
Este “desconhecimento” entre os componentes garante um bom nível de desacoplamento e favorece a
distribuição, pois permite a troca de mensagens entre componentes que estejam em servidores diferentes ou
até em outras redes. O modelo de atores é uma derivação do modelo de troca de mensagens, e falaremos
sobre ele agora.
3
Figura 2. Representação gráfica do modelo de concorrência 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
intervenções foram feitas neste modelo e diversos papers foram publicados, o que culminou na definição da
teoria do modelo de atores.
Fundamentalmente, o modelo de atores prega que “tudo são atores”. Os atores são definidos como entidades
capazes de realizar um processamento computacional e que se comunicam entre si através do envio e
recebimento de mensagens.
Além disso, podem criar outros atores, estabelecendo assim uma hierarquia entre eles. Como a comunicação
entre atores deve ser feita estritamente pela troca de mensagens, o estado interno de um ator não é acessível
por outros, mas somente por ele mesmo.
Aliando isso ao fato do processamento das mensagens ser sequencial, isto é, um ator poder ter várias
mensagens pendentes, mas apenas uma ser processada por vez, os problemas com locks simplesmente
deixam de existir. A Figura 3 mostra uma visão simplificada do modelo de atores.
4
Figura 3. Representação gráfica do modelo de concorrência baseado em atores
Com estas características, este tipo de solução vem sendo adotado para aplicações que processam grandes
volumes de dados, pois para atender esse tipo de demanda usando o modelo convencional de threads e o
processamento síncrono, ficamos limitados pela capacidade individual dos servidores.
Por sua vez, o modelo de atores permite uma distribuição mais fácil dos componentes da aplicação devido a
sua natureza assíncrona e baseada em mensagens. O Erlang [5], linguagem originada na Ericsson com o
propósito de suportar aplicações distribuídas altamente concorrentes, possui em seu core uma
implementação deste modelo.
Contudo, apesar do Erlang ser uma linguagem de uso geral, não conquistou grande adoção. Em razão disso,
faltava ao mercado uma solução para alta concorrência baseada em atores. Assim surgiu o Akka.
Akka
O Akka foi desenvolvido em 2009 por Jonas Bonér, inspirado pelo modelo de atores do Erlang. Seu
primeiro release público, o Akka 0.5, foi anunciado em Janeiro de 2010. Atualmente esta solução é mantida
pela Typesafe Inc., a mesma empresa que mantém o Scala e o Play Framework. Recentemente, o Akka
passou a fazer parte da API padrão do Scala, substituindo o modelo de atores original desta linguagem, e
apesar de ser escrito em Scala, possui uma API oficial também para Java.
De acordo com a definição da equipe, o Akka é um “toolkit e um runtime para construir aplicações
altamente concorrentes, distribuídas e tolerantes a falhas na JVM”. Assim, aplicações criadas usando o Akka
já nascem prontas para operar de maneira distribuída, pois esta característica está na essência do framework.
5
Criado com o foco em aplicações distribuídas e otimizado para operar de maneira standalone, o Akka provê:
· Atores: conforme explicado anteriormente, a base do Akka é sua implementação 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 são muito parecidos com a implementação padrão
do java.util.concurrent, porém possui integração com atores;
· Scheduler: integrado ao contexto de atores, o Akka permite o agendamento de tarefas usando vários tipos
de schedulers.
Devido a estas características e recursos, o Akka vem sendo adotado por várias empresas de porte. Dentre
elas, podemos citar a Amazon, Autodesk, Blizzard, VMware, dentre outros.
Hello World – Primeiros passos
Uma forma de desenvolver aplicações com o Akka é fazer com que o framework seja uma dependência do
projeto e usar a própria aplicação para iniciar o sistema de atores. Além dessa, existe outra opção para
desenvolver tais aplicações: usando o Typesafe Activator, que é um software que depois de instalado pode
ser utilizado para criar e executar aplicações diversas baseadas em templates.
O Activator na verdade oferece muito mais, como por exemplo, uma IDE totalmente web para manutenção
dos projetos gerados por ele. Tanto o Activator quanto as dependências do Akka podem ser obtidos na
página de downloads do site do próprio Akka [6]. Neste artigo, adotaremos a primeira opção, pois esta
permite uma compreensão melhor do funcionamento do framework.
Para criar uma aplicação 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 aplicação, 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 diretório para hospedar o código da aplicação, e depois crie o pom.xml com a dependência
do Akka, conforme indica a Listagem 1.
Listagem 1. pom.xml base de uma aplicação 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>
6
<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 diretório src/main/java chamada Start. Esta classe será responsável por
iniciar a aplicação 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 mãos na massa, vamos analisar o conceito de sistema de atores do Akka.
Actor System – O container de atores
Como principal característica, o Akka implementa um modelo de atores. De modo simples, este modelo diz
que tudo são atores. Sendo assim, a lógica da aplicação que normalmente é programada em classes que
costumamos chamar de “o modelo da aplicação” ou os “componentes de negócio”, deve ser estruturada em
um ou vários atores que se comunicam de maneira assíncrona através da troca de mensagens, todos sob a
gestão 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 instanciação. 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 aplicação, por isso, deve ser criado assim que ela iniciar. Em
relação ao número de actor systems, uma aplicação pode iniciar vários deles, porém este tipo de design não é
indicado por questões de organização.
Para criar um actor system devemos usar a classe akka.actor.ActorSystem, como demonstra a Listagem 3.
Listagem 3. Criação do actor system.
import akka.actor.ActorSystem;
public class Start {
public static void main(String[] args) {
// Criação de um Actor System, container Akka.
ActorSystem system = ActorSystem.create("HelloSystem");
}
}
Podemos observar que o construtor do actor system recebe um texto como parâmetro para definir o seu
nome. Este nome deve ser único por aplicação e também deve ser único por container, caso a aplicação seja
instalada em um microcontainer Akka. Como veremos adiante, o nome do actor system também irá compor
o path de localização do ator.
7
Atores em todos os lugares
De acordo com a explicação anterior, no modelo de atores um ator é um objeto capaz de receber e enviar
mensagens, além de criar outros atores. No processamento das mensagens recebidas está a lógica de negócio
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 método void onReceive(Object msg). Este método é responsável pelo processamento das
mensagens. Deste modo, crie a classe EcoActor em src/main/java contendo o código da Listagem 4.
Listagem 4. Um ator que exibe no console a mensagem recebida.