Desenvolvimento

4 abr, 2017

Dados pequenos com Elixir

Publicidade

Este é o primeiro artigo de uma série sobre “dados pequenos” (em contraste com “big data”) no Elixir. Vamos começar definindo o que são “dados pequenos”, porque isso é importante e, em seguida, descreveremos brevemente a ferramenta Flow e o que esperar nos próximos artigos da série.

O quão pequeno é pequeno?

Definimos dados pequenos como aqueles que podem ser processados por uma única máquina em um intervalo de tempo desejável. Tal trabalho pode ser feito em batches, em que todos os dados são conhecidos de antemão, ou em streaming, onde uma ou mais máquinas podem acompanhar a taxa de entrada de eventos sem a necessidade de sincronização.

Yanpei Chen, Sara Alspaugh e Randy Katz, da Universidade da Califórnia, caracterizaram diferentes cargas de trabalho do MapReduce e concluíram que:

Para o planejamento de nível de trabalho e planejamento de execução, todas as cargas de trabalho contêm uma variedade de tipos de trabalho, sendo mais comuns os pequenos trabalhos. Esses trabalhos são pequenos em todas as dimensões em comparação com outros trabalhos na mesma carga de trabalho. Eles envolvem 10s de KB para GB de dados, exibem uma gama de padrões de dados entre o mapa e os estágios reduce, e têm durações de 10s de segundos para alguns minutos.

Ionel Gog, Malte Schwarzkopf, Natacha Crooks, Matthew P. Grosvenor, Allen Clement e Steven Hand, da Universidade de Cambridge e Max Planck Instituto para Sistemas de Software, ao desenvolver Musketeer, compararam diferentes soluções e descobriram que

Para pequenas entradas (≤ 0,5 GB), o sistema MapReduce de máquina única Metis funciona melhor. Isso é importante, já que as pequenas entradas são comuns na prática: 40-80% dos trabalhos MapReduce dos clientes Cloudera e 70% dos trabalhos em um rastreamento do Facebook têm ≤ 1GB de entrada.

Muitas vezes, a computação não era o gargalo, mas sim a leitura dos dados de fontes externas. Ser capaz de transmitir de e para fontes externas em paralelo é primordial para o desempenho de tais sistemas.

Finalmente, Frank McSherry, Michael Isardm e Derek G. Murray publicaram “Scalability! But at what COST?”. O CUSTO de uma determinada plataforma para um determinado problema é a configuração de hardware necessária antes que a plataforma supere uma implementação de thread única competente.

O ambiente de computação em cluster é diferente do ambiente de um laptop. O primeiro muitas vezes valoriza a alta capacidade e o rendimento sobre a latência, com cores, armazenamento e memória mais lentos. O laptop agora incorpora o computador pessoal, com menor capacidade, mas cores, armazenamento e memória mais rápidos. Embora os sistemas escaláveis sejam frequentemente uma boa correspondência para os recursos do cluster, é importante considerar hardware alternativo para o desempenho máximo.

Em outras palavras, há um grande conjunto de problemas que são mais eficientemente resolvidos em uma única máquina, pois evita os custos em complexidade, comunicação em rede e pontos de verificação de dados comuns a grandes sistemas de dados.

O que exatamente constitui os dados pequenos depende do problema, do tamanho dos dados (ou da sua taxa de entrada) e dos tempos de processamento esperados. Nesta série de artigos, vamos explorar soluções para diferentes problemas com a biblioteca Flow. Flow alavanca a concorrência em máquinas individuais e pode ser uma opção adequada para cargas de trabalho pequenas, salvando equipes que precisam recorrer a soluções de big data totalmente desenvolvidos.

GenStage e Flow

No ano passado, introduzimos o GenStage, uma abstração para troca de dados entre processos Elixir. GenStage foi projetado com contrapressão em mente para que os desenvolvedores Elixir pudessem consumir dados de sistemas externos, como Apache Kafka, RabbitMQ, bancos de dados, arquivos e assim por diante, sem sobrecarregar o sistema de processamento de dados.

Estágios podem ser produtores e/ou consumidores de dados. Um simples estágio producer pode ter vários consumidores, que receberão eventos de acordo com uma estratégia escolhida. Isso significa que os desenvolvedores podem criar pipelines de estágio arbitrariamente como uma forma de alavancar a concorrência.

No entanto, se os desenvolvedores são os responsáveis pela construção desses pipelines, eles podem acabar com fluxos de trabalho abaixo do ideal. É por isso que desenvolvemos uma ferramenta chamada Flow, construída sobre o GenStage. Flow permite aos desenvolvedores expressar seus cálculos de dados usando operações funcionais, como map, reduce, filter e amigos. Flow também fornece conveniências para particionamento de dados e janelas. Uma vez que tais parâmetros são especificados, o Flow cuida de construir uma rede de estágios conectados por onde os dados fluem. Aqui está o exemplo clássico (e clichê) de usar o Flow para contar palavras em um arquivo:

File.stream!("path/to/file", :line)
|> Flow.from_enumerable()
|> Flow.flat_map(&String.split/1)
|> Flow.partition()
|> Flow.reduce(fn -> %{} end, fn word, map ->
Map.update(map, word, 1, & &1 + 1)
end)
|> Enum.into(%{})

Não se preocupe com os detalhes do exemplo acima por agora. Vamos revisitá-lo em textos futuros.

Próximos passos

No próximo artigo, vamos falar sobre computações lazy e streams assíncronos, que fornecem algum plano de fundo útil antes de saltar para Flow. Se você quiser ter uma vantagem, assista ao meu keynote sobre GenStage & Flow no ElixirConf e leia a excelente documentação do projeto Flow.

***

José Valim faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: http://blog.plataformatec.com.br/2017/03/small-data-with-elixir/.