Entendendo o Modelo de Atores

1.885 visualizações

Publicada em

Publicada em: Tecnologia
  • Seja o primeiro a comentar

Entendendo o Modelo de Atores

  1. 1. Entendendo o modelo de atoresprogramação concorrente e distribuída de verdade Paulo “JCranky” Siqueira jcranky.com / @jcranky
  2. 2. Paulo "JCranky" Siqueira• desenvolvedor Java e Scala• consultor independente• instrutor globalcode – e criador do curso Core Scala• um dos fundadores dos Scaladores
  3. 3. Objetivos• programação concorrente• (um pouco) programação distribuída• modelo de atores• código
  4. 4. Programação concorrente... porque?● Aumentar performance● Melhorar a resposta ao usuário do sistema
  5. 5. Concorrência de forma correta?
  6. 6. Tolerância a falhas?
  7. 7. 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
  8. 8. 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)
  9. 9. 1 núcleo?
  10. 10. Ou vários?
  11. 11. Assincronia● para performance● para melhorar a resposta do sistema● controlar threads “na mão” começa a complicar...
  12. 12. Dividir para conquistar● dividir as tarefas – Threads diferentes podem executá-las● temos que pensar diferente
  13. 13. estado compartilhado... ??val numeros = (1 to 100).toListdef divSequential = {  var div = 1000d  numeros.foreach(x => div = div / x)  println(div)}
  14. 14. estado compartilhado... ??// qual o resultado?1 to 10 foreach(x => divSequential)
  15. 15. estado compartilhado... ??def divParallel = {  var div = 1000d  numeros.par.foreach( x => {     div = div / x Thread.sleep(10)  })  println(div)}
  16. 16. estado compartilhado... ??// qual o resultado?1 to 10 foreach(x => divParallel)
  17. 17. "Shared Mutability is pure evil. Avoid it!"
  18. 18. Nossa nova filosofia● Podem esquecer tudo, menos isso!● mutabilidade isolada● imutabilidade compartilhada
  19. 19. 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
  20. 20. Abstração!• que tal abstrair programação concorrente?• porque nos preocupar com Threads? – e com locks? – e em fazer isso direito...
  21. 21. Enter the “Actor Model”• entidades independentes – estado – comportamento – mailbox• como uma classe em OO...• ... mas mais "pura" (e com a tal da mailbox)
  22. 22. Novidade! Só que não.• Erlang, 1987.
  23. 23. Actor Modelmensagens mailbox Comportamento Estado
  24. 24. Actor Model• comunicação com troca de mensagens• "event-driven"• sempre assíncrono
  25. 25. Akka 2.0• inspirado em Erlang• abstrai preocupações baixo nível• pensamos mais nos problemas de negócio
  26. 26. Akka 2.0• API Java e Scala• Actor Model !• Open Source
  27. 27. 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
  28. 28. Escalabilidade...• horizontal e vertical• Horizontal: – Programação distribuída• Vertical – Programação concorrente
  29. 29. 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
  30. 30. 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
  31. 31. 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}
  32. 32. Mutabilidade: origem do mal
  33. 33. Imutabilidade• não precisamos de locks• nunca teremos deadlocks
  34. 34. Imutabilidade• Não sabe trabalhar com objetos imutáveis?• Sabe sim! – String? BigDecimal? Integer?
  35. 35. Ou mutabilidade isolada• estado interno do ator é mutável – mas apenas ele mesmo tem acesso• chave para um sistema concorrente correto
  36. 36. Uma mensagemcase class SendToS3(fileName: String)
  37. 37. Um atorclass S3SenderActor extends Actor {  def receive = {    case SendToS3(fileName) =>      // lógica de negócios aqui  }}
  38. 38. 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
  39. 39. 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
  40. 40. Criando um atorval system = ActorSystem("MyActorSystem")// ator com construtor defaultval ator =  system.actorOf(Props[S3SenderActor])// ator com outro construtorval ator2 =  system.actorOf(Props(new Ator(<params>)))
  41. 41. Enviando uma mensagemator ! SendToS3(“imagem.gif”)
  42. 42. Protegendo o estadoval meuAtor = new Ator(<params>)// erro em runtimeval ator2 = system.actorOf(Props(meuAtor))
  43. 43. Expandindo a hierarquia de atores● todo ator tem um context● esse context pode criar novos atores ● que serão "filhos" do ator atual
  44. 44. Expandindo a hierarquia de atorescontext.actorOf(Props[S3SenderActor])
  45. 45. "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+)
  46. 46. Hierarquia de atores A B C D E F
  47. 47. Hierarquia de atores A B C D E F
  48. 48. Hierarquia de atores A C F
  49. 49. Hierarquia de atores A B C D E F
  50. 50. Config. de tolerância a falhasoverride val supervisorStrategy =  OneForOneStrategy(    MaxNrOfRetries = 10,    withinTimeRange = 1 minute) {        case _: ArithmeticException ⇒  Resume        case _: NullPointerException ⇒  Restart        case _: IllegalArgumentException ⇒  Stop        case _: Exception ⇒  Escalate    }
  51. 51. 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
  52. 52. Exemplo de roteadorval s3SenderRouter = system.actorOf(  Props[S3SenderActor].withRouter(    SmallestMailboxRouter(2)))
  53. 53. Programação distribuída – porque?● porque sim? ● não faça
  54. 54. Programação distribuída – porque?● processador local não dá conta sozinho● aumentar tolerância a falhas ● melhorou =)
  55. 55. Programação distribuída? Como??● CORBA?● RMI?● EJBs?● outra-coisa-qualquer na mão?
  56. 56. Programação distribuída?● que tal atores?● algo não funcionaria remotamente?
  57. 57. Programação distribuída?
  58. 58. Atores remotos● akka suporta atores remotos● ajustamos a configuração● ajustamos o código para usar a config.
  59. 59. Atores remotos● código cliente de atores continua igual● para o emitente da mensagem, atoresremotos e locais são iguais● “Atores locais são como otimizações”
  60. 60. Ator a partir de configuraçãocontext.actorOf(Props[MeuAtor]  .withRouter(FromConfig()),"nome­ator")
  61. 61. 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
  62. 62. 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
  63. 63. 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
  64. 64. bonus: composição async com Futuresval colorFuture = for {  r <­ (rPartChooser ? FindColorPart)                      .mapTo[ColorPartFound]  g <­ (gPartChooser ? FindColorPart)                      .mapTo[ColorPartFound]  b <­ (bPartChooser ? FindColorPart)                      .mapTo[ColorPartFound]} yield (r.value, g.value, b.value)
  65. 65. Projeto Open Source: Lojinha• Scala• Akka 2.0• Play Framework 2.0
  66. 66. 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 perGB of heap."
  67. 67. Atores da Lojinha Play Akka System Image Master Thumb Bid Actor Router S3 Sender Router Image Process Thumb Bid Actor S3 Actor Sender Actorum para cada produto vários, conforme configurado vários, conforme configurado
  68. 68. Referências• Programming Concurrency on the JVM, Venkat Subramariam• akka.io
  69. 69. Referências• blog: jcranky.com• twitter: twitter.com/jcranky• lojinha, no github: https://github.com/jcranky/lojinha – lojinha.paulosiqueira.com.br
  70. 70. Mais referências• Core Scala, na Globalcode• tópicos principais: o Scala o Akka 2 o Play Framework 2
  71. 71. Questions? ?
  72. 72. Thanks!jcranky.com / @jcranky

×