Entendendo o modelo de
        atores
programação concorrente e distribuída de
              verdade


         Paulo “JCranky” Siqueira
          jcranky.com / @jcranky
Paulo "JCranky" Siqueira


•   desenvolvedor Java e Scala

•   consultor independente

•   instrutor globalcode
    –   e criador do curso Core Scala

•   um dos fundadores dos Scaladores
Objetivos



•   programação concorrente

•   (um pouco) programação distribuída

•   modelo de atores

•   código
Programação concorrente... porque?



●   Aumentar performance

●   Melhorar a resposta ao usuário do sistema
Concorrência de forma correta?
Tolerância a falhas?
1a Opção na JVM: Threads


●   Forma “natural” para concorrência


    –   Um processo, pelo menos uma thread,
        possivelmente várias

    –   Temos que controlar “na mão” essas
        threads
Em tempo: o processador!


●   Para tarefas intensas, não importa
    quantas threads...

●   Concorrência real, só mais de um núcleo


    –   (o que não é difícil hoje em dia)
1 núcleo?
Ou vários?
Assincronia
●   para performance

●   para melhorar a resposta do sistema

●   controlar threads “na mão” começa a
    complicar...
Dividir para conquistar


●   dividir as tarefas
    –   Threads diferentes podem executá-las

●   temos que pensar diferente
estado compartilhado... ??



val numeros = (1 to 100).toList

def divSequential = {
  var div = 1000d
  numeros.foreach(x => div = div / x)
  println(div)
}
estado compartilhado... ??




// qual o resultado?

1 to 10 foreach(x => divSequential)
estado compartilhado... ??

def divParallel = {
  var div = 1000d
  numeros.par.foreach(
    x => {
     div = div / x
      Thread.sleep(10)
  })
  println(div)
}
estado compartilhado... ??




// qual o resultado?

1 to 10 foreach(x => divParallel)
"Shared Mutability is pure evil. Avoid it!"
Nossa nova filosofia

●   Podem esquecer tudo, menos isso!


●   mutabilidade isolada

●   imutabilidade compartilhada
Na mão? Mesmo?


●   Java 5 / 6 trouxeram diversas melhorias


    –   controlar Threads não é mais tão difícil

    –   mas ainda assim, não é trivial
Abstração!


•   que tal abstrair programação concorrente?



•   porque nos preocupar com Threads?
    –   e com locks?
    –   e em fazer isso direito...
Enter the “Actor Model”

•   entidades independentes
    – estado

    –   comportamento
    –   mailbox

•   como uma classe em OO...

•   ... mas mais "pura" (e com a tal da mailbox)
Novidade!

    Só que não.



•   Erlang, 1987.
Actor Model

mensagens      mailbox


                Comportamento



                   Estado
Actor Model



•   comunicação com troca de mensagens

•   "event-driven"

•   sempre assíncrono
Akka 2.0



•   inspirado em Erlang

•   abstrai preocupações baixo nível

•   pensamos mais nos problemas de negócio
Akka 2.0



•   API Java e Scala

•   Actor Model !

•   Open Source
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...

•   em uma máquina com 48 núcleos
Escalabilidade...

•   horizontal e vertical



•   Horizontal:
    – Programação distribuída



•   Vertical
    –   Programação concorrente
Onde estão as Threads ??

•   Akka cria as threads necessárias

•   ator != thread

•   atores usam threads disponíveis

•   akka fornece uma thread para o ator

•   sem locks
Divisão de trabalho

•   threads usando os "cores" disponíveis

•   fork-join por padrão
    –   com algumas melhorias que devem estar
        no Java 8...

•   ... mas já está embutido no Akka

•   tudo configurável
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
}
Mutabilidade: origem do mal
Imutabilidade



•   não precisamos de locks


•   nunca teremos deadlocks
Imutabilidade



•   Não sabe trabalhar com objetos imutáveis?



•   Sabe sim!


    –   String? BigDecimal? Integer?
Ou mutabilidade isolada



•   estado interno do ator é mutável


    –   mas apenas ele mesmo tem acesso


•   chave para um sistema concorrente correto
Uma mensagem




case class SendToS3(fileName: String)
Um ator

class S3SenderActor extends Actor {
  def receive = {
    case SendToS3(fileName) =>
      // lógica de negócios aqui
  }
}
Lidando com alteração de estado

•   Atores não devem compartilhar estado
    –   somente ele mesmo acessa seus dados


•   Acesso a BD poderia ser enfileirado
    –   ou atores com "fatias" de dados
Criando atores

•   métodos / classes especiais

•   criados abaixo de um nó principal
    –   ... ou relativos ao contexto atual

•   todo ator tem um "pai"

•   resultando em uma hierarquia de atores
Criando um ator
val system = ActorSystem("MyActorSystem")

// ator com construtor default
val ator =
  system.actorOf(Props[S3SenderActor])

// ator com outro construtor
val ator2 =
  system.actorOf(Props(new Ator(<params>)))
Enviando uma mensagem



ator ! SendToS3(“imagem.gif”)
Protegendo o estado



val meuAtor = new Ator(<params>)

// erro em runtime
val ator2 =
 system.actorOf(Props(meuAtor))
Expandindo a hierarquia de atores



●   todo ator tem um context

●   esse context pode criar novos atores

     ●   que serão "filhos" do ator atual
Expandindo a hierarquia de atores




context.actorOf(Props[S3SenderActor])
"let it crash"


•   tolerância a falhas

•   não evitamos que atores quebrem

•   decidimos o que fazer quando falhar
     –   o supervisor decide o que fazer

•   todo ator é supervisionado (2.0+)
Hierarquia de atores

                 A




         B             C




    D        E             F
Hierarquia de atores

                 A




         B             C




    D        E             F
Hierarquia de atores

                A



                       C




                           F
Hierarquia de atores

                 A




         B             C




    D        E             F
Config. de tolerância a falhas


override val supervisorStrategy =
  OneForOneStrategy(
    MaxNrOfRetries = 10,
    withinTimeRange = 1 minute) {
        case _: ArithmeticException ⇒  Resume
        case _: NullPointerException ⇒  Restart
        case _: IllegalArgumentException ⇒  Stop
        case _: Exception ⇒  Escalate
    }
Dividir para conquistar, outra vez



•   quebrar tarefas em pedaços pequenos

•   roteadores são uma forma de fazer isso
     –   definem grupos de atores
     –   e divide as mensagens
Exemplo de roteador



val s3SenderRouter = system.actorOf(
  Props[S3SenderActor].withRouter(
    SmallestMailboxRouter(2))
)
Programação distribuída – porque?




●   porque sim?
    ●   não faça
Programação distribuída – porque?



●   processador local não dá conta sozinho
●   aumentar tolerância a falhas


    ●   melhorou =)
Programação distribuída? Como??



●   CORBA?
●   RMI?
●   EJBs?
●   outra-coisa-qualquer na mão?
Programação distribuída?



●   que tal atores?


●   algo não funcionaria remotamente?
Programação distribuída?
Atores remotos



●   akka suporta atores remotos


●   ajustamos a configuração
●   ajustamos o código para usar a config.
Atores remotos

●   código cliente de atores continua igual


●   para o emitente da mensagem, atores
remotos e locais são iguais


●   “Atores locais são como otimizações”
Ator a partir de configuração




context.actorOf(Props[MeuAtor]
  .withRouter(FromConfig()),"nome­ator")
Tá difícil mesmo assim?

Akka Cluster
●


    ●   atores remotos, com menos configuração
    ●   mais inteligência para suportar nós
        entrando e saindo do cluster


    ●   em testes, previsto para Akka 2.1
Atores remotos
●   cuidados básicos:
    ●   quantidade de mensagens
    ●   tamanho das mensagens
    ●   delay em relação a atores locais


●   tudo afeta o design dos atores
    ●   portanto, o código
bonus: composição async com Futures

●   possibilita código totalmente sem block


●   usamos callbacks
    ●   executados quando uma resposta chegar


●   ou Futuros, e compomos o resultado final
bonus: composição async com Futures



val colorFuture = for {
  r <­ (rPartChooser ? FindColorPart)
                      .mapTo[ColorPartFound]
  g <­ (gPartChooser ? FindColorPart)
                      .mapTo[ColorPartFound]
  b <­ (bPartChooser ? FindColorPart)
                      .mapTo[ColorPartFound]
} yield (r.value, g.value, b.value)
Projeto Open Source: Lojinha




•   Scala

•   Akka 2.0

•   Play Framework 2.0
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."
Atores da Lojinha

                                Play Akka
                                 System



                                                                  Image
        Master
                                                                  Thumb
       Bid Actor
                                                                  Router
                                    S3
                                  Sender
                                  Router



                                                                  Image
       Process
                                                                  Thumb
       Bid Actor                    S3
                                                                   Actor
                                  Sender
                                   Actor
um para cada produto                                  vários, conforme configurado
                       vários, conforme configurado
Referências



•   Programming Concurrency on the JVM,
    Venkat Subramariam



•   akka.io
Referências

•   blog: jcranky.com

•   twitter: twitter.com/jcranky



•   lojinha, no github:
    https://github.com/jcranky/lojinha
    –   lojinha.paulosiqueira.com.br
Mais referências



•   Core Scala, na Globalcode

•   tópicos principais:
    o   Scala
    o   Akka 2
    o   Play Framework 2
Questions?




             ?
Thanks!


jcranky.com / @jcranky

Entendendo o Modelo de Atores