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 full-size slide

  2. Por quê?
    Flow e GenStage

    View full-size slide

  3. Processamento de
    Dados
    Flow e GenStage

    View full-size 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  7. Ávido
    (Eager)

    View full-size 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 full-size 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 full-size slide

  10. Preguiçoso
    (Lazy)

    View full-size 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 full-size 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 full-size slide

  13. 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 full-size slide

  14. 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 full-size 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 full-size slide

  16. 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 full-size slide

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

    View full-size slide

  18. GenStage
    Producer/
    Consumer
    Producer
    Producer/
    Consumer
    Consumer

    View full-size slide

  19. 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 full-size slide

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

    View full-size slide

  21. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  26. Distribuído

    View full-size slide

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

    View full-size slide

  28. 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 full-size slide

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

    View full-size slide

  30. 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 full-size slide