Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Segue o Fluxo: Elixir's GenStage e Flow

Segue o Fluxo: Elixir's GenStage e Flow

Guilherme de Maio, nirev

March 18, 2017
Tweet

More Decks by Guilherme de Maio, nirev

Other Decks in Programming

Transcript

  1. @nirev
    Guilherme Nogueira
    Segue o

    Fluxo
    Elixir's GenStage e Flow

    View Slide

  2. Por quê?
    Flow e GenStage

    View Slide

  3. Processamento de
    Dados
    Flow e GenStage

    View Slide

  4. Processamento de
    Dados
    Flow e GenStage
    • Processamento de Logs
    • Indexação de dados para busca
    • Algoritmos de Recomendação
    • Dashboards em tempo real
    • etc…

    View Slide

  5. Processamento de Dados
    1.ávido
    2.preguiçoso
    3.???
    4.PROFIT

    View Slide

  6. Processamento de Dados
    1.ávido
    2.preguiçoso
    3.concorrente
    4.distribuído

    View Slide

  7. Ávido
    (Eager)

    View Slide

  8. Ávido
    File.read!("path/to/some/file")
    |> Enum.flat_map(&String.split(&1, " "))
    |> Enum.reduce(%{}, fn word, acc ->
    Map.update(acc, word, 1, & &1 + 1)
    end)
    |> Enum.to_list()

    View Slide

  9. Ávido
    • Simples
    • Tudo em memória
    • Lento para arquivos muito grandes
    • 0% de concorrência
    File.read!("path/to/some/file")
    |> Enum.flat_map(&String.split(&1, " "))
    |> Enum.reduce(%{}, fn word, acc ->
    Map.update(acc, word, 1, & &1 + 1)
    end)
    |> Enum.to_list()

    View Slide

  10. Preguiçoso
    (Lazy)

    View Slide

  11. Preguiçoso
    File.stream!("path/to/some/file")
    |> Stream.flat_map(&String.split(&1, " "))
    |> Enum.reduce(%{}, fn word, acc ->
    Map.update(acc, word, 1, & &1 + 1)
    end)
    |> Enum.to_list()

    View Slide

  12. Preguiçoso
    • Melhor, um de cada vez
    • Menos uso de memória
    • Ainda lento para arquivos muito grandes
    • 0% de concorrência
    File.stream!("path/to/some/file")
    |> Stream.flat_map(&String.split(&1, " "))
    |> Enum.reduce(%{}, fn word, acc ->
    Map.update(acc, word, 1, & &1 + 1)
    end)
    |> Enum.to_list()

    View Slide

  13. Concorrente

    View Slide

  14. Concorrente
    File.stream!("path/to/some/file")
    |> Flow.from_enumerable()
    |> Flow.flat_map(&String.split(&1, " "))
    |> Flow.partition()
    |> Flow.reduce(fn -> %{} end, fn word, acc ->
    Map.update(acc, word, 1, & &1 + 1)
    end)
    |> Enum.to_list()

    View Slide

  15. Concorrente
    • Agora, sim! Multi-processos
    • Perde noção de ordem
    File.stream!("path/to/some/file")
    |> Flow.from_enumerable()
    |> Flow.flat_map(&String.split(&1, " "))
    |> Flow.partition()
    |> Flow.reduce(fn -> %{} end, fn word, acc ->
    Map.update(acc, word, 1, & &1 + 1)
    end)
    |> Enum.to_list()

    View Slide

  16. Concorrente
    • Agora, sim! Multi-processos
    • Perde noção de ordem
    File.stream!("path/to/some/file")
    |> Flow.from_enumerable()
    |> Flow.flat_map(&String.split(&1, " "))
    |> Flow.partition()
    |> Flow.reduce(fn -> %{} end, fn word, acc ->
    Map.update(acc, word, 1, & &1 + 1)
    end)
    |> Enum.to_list()

    View Slide

  17. Flow

    View Slide

  18. Flow
    • Um meio de expressar processamento em cima de
    coleções (tipo Enum e Stream), mas feitas em paralelo
    com GenStage
    • Funciona com dados finitos e não-finitos
    • Inspirado no Apache Spark

    View Slide

  19. GenStage

    View Slide

  20. GenStage
    • É um behaviour
    • Feito para trocar dados entre “estágios”
    • de forma transparente
    • e com back-pressure

    View Slide

  21. GenStage
    Producer/
    Consumer
    Producer
    Producer/
    Consumer
    Consumer

    View Slide

  22. GenStage
    • O Consumidor se subscreve ao Produtor
    • Quem dita a velocidade é o Consumidor
    • Produtor pode enviar à vários Consumidores
    • Diferentes políticas para despacho aos Consumidores

    View Slide

  23. GenStage
    Producer Consumer
    Pede X
    Recebe no máximo X

    View Slide

  24. GenStage
    Producer Consumer
    Pede X
    Recebe no máximo X
    max_demand: máximo de itens que o consumidor pede
    min_demand: mínimo de itens, quando atingir esse número pede mais

    View Slide

  25. GenStage
    Producer
    1
    2,4
    3
    Despacho
    1,2,3,4
    DemandDispatcher

    View Slide

  26. GenStage
    Producer
    1,2
    1,2
    1,2
    Despacho
    1,2
    BroadcastDispatcher

    View Slide

  27. GenStage
    Producer
    1,4
    2,5
    3,6
    Despacho
    1,2,3,4,5,6
    PartitionDispatcher
    rem(e,3)

    View Slide

  28. GenStage
    Exemplo
    (https://github.com/nirev/gen_stage_example)

    View Slide

  29. Distribuído

    View Slide

  30. Distribuído
    • Não tem ainda
    • Faltam mecanismos de garantias no Flow
    • Precisa mesmo distribuir?
    • Mais informações em breve…

    View Slide

  31. Conclusão

    View Slide

  32. Conclusão
    • Pipelines de dados como “cidadãos" do Elixir
    • API muito familiar pra quem já usou outros frameworks
    • Bastante promissor
    • Não tem garantias ainda: 

    ou seja, não usar para processar pagamento ;D

    View Slide

  33. Thanks!
    https://xerpa.recruiterbox.com/
    Estamos contratando!
    @nirev
    Guilherme Nogueira

    View Slide

  34. Referências
    • https://hexdocs.pm/gen_stage
    • https://hexdocs.pm/flow
    • https://www.youtube.com/watch?v=aZuY5-2lwW4
    • https://www.youtube.com/watch?v=IBcLOxW1Zgs
    • http://teamon.eu/2016/tuning-elixir-genstage-flow-pipeline-processing/
    • https://blog.discordapp.com/how-discord-handles-push-request-bursts-of-over-a-million-per-
    minute-with-elixirs-genstage-8f899f0221b4
    Documentação e Palestras
    Relatos de Uso

    View Slide