Fala galera do bem e dos dados, trazendo mais um post que pode ajudar nas reduções de custos e desempenho no seu ambiente.
Todos que trabalham com T.I tem algum conhecimento de paralelismo, é um recurso inevitável para alguns e extremamente complexo para outros, mas, nossos softwares não funcionariam bem sem ele.
Em poucas palavras o paralelismo é uma maneira de executar várias tarefas simultaneamente, aproveitando todo o recurso computacional disponível, no mundo de Analytics também é muito utilizado para processamento distribuído (Ai que nós entra rs), exemplo o Apache Spark que processa grandes massas de dados em paralelo.
Meu objetivo não é entrar em detalhes de paralelismo, mas que fique claro que isso não é restrito a desenvolvedores, se você utiliza Spark ou algum processamento distribuído você deveria conhecer bem esse conceito.
Paralelismo além de complexo se mal aplicado pode trazer gargalos a sua aplicação, então use com moderação e estude o assunto, pelo amor não saia paralelizando tudo.
Hoje vou trazer um exemplo de paralelismo com python usando o Databricks e mostrar um caso de como você pode reduzir custos de processamento se bem aplicado.
Esse código de exemplo está no github link no final do post.
Nesse exemplo estou realizando um processamento serial, ou seja, uma tarefa de cada vez.
Tempo total de execução: 10 segundos
Observação: O time.sleep(1) é proposital para termos uma espera de 1 segundo para cada execução.
Agora vamos para o modo paralelo, estou usando a mesma função anterior (Incluindo o delay 1 sec), contudo, agora estou enviando cada número para processar em paralelo utilizando a função executor.submit()
Tempo total de execução: 1 segundo
Chega ser maravilhoso né? "Ah Reginaldo, mas, não existe almoço grátis ne?!"
Até hoje não achei nenhum almoço grátis, ah não ser quando alguém me paga rsrs, estou sempre aberto para almoços grátis! Mas voltando ao tema, não existe almoço grátis, o paralelismo pode ser extremamente benéfico como também pode ser maléfico ao seu ambiente, por isso reforço, use com moderação.
Outro ponto extremamente importante falando de Databricks e Spark, dependendo de como você esta usando, todo o processamento vai acontecer apenas no Driver. Ou seja, você pode ter um cluster com 8 nodes, mas todo o processamento vai ficar apenas em 1 máquina, então use com sabedoria (de preferência usar pyspark para paralelizar o processamento entre os nodes do seu cluster).
Uma dica para você medir se está sendo eficiente é cruzar alguns indicadores como, tempo de execução, consumo de recursos do cluster, logs do driver e erros no processo.
Essa é uma imagem do Ganglia no momento da execução do meu processo:
A imagem está meio pequena, mas note que o workload(carga de processamento) está bem baixa e o meu cluster bem ocioso, meu processo caiu de 10 segundos para 1 segundo sem nenhum erro e warning (olhe no driver logs), considero esse caso benéfico, mas claro, é apenas um print() rs.
Bom vamos para outro exemplo então usando um pouco de pyspark.
Temos a tabela "db_festivaldemo.PatientInfoDelta" criada no post anterior, se você ainda leu, da uma olhada nesse link.
Objetivo: Quero descobrir quantas linhas tem cada versão da minha tabela.
Utilizando o describe history note que tenho 27 versões dessa tabela, com Updates e Deletes.
Em modo serial ficaria algo assim:
Colocar todas as versões em uma lista (dica uso a função COLLECT() é bastante útil), depois fazer um Loop e para cada versão fazer um COUNT.
Tempo total de execução: 18 segundos.
Em paralelo ficaria assim, quebrei o processo em algumas funções para organizar o código, então tenho a função que retorna o COUNT de uma versão que recebe como parâmetro, tenho uma função que dispara os COUNTs em paralelo. Note que estou usando paralelismo com 25 Threads, logo será executado 25 COUNTs em paralelo.
Tempo total de execução: 7 segundos.
Observe que a sequência das versões esta totalmente fora de ordem, isso acontece devido o processo ser assíncrono.
Eu poderia dar muitos outros exemplos, a imaginação e criatividade é o limite. "Reginaldo, não entendi como posso reduzir custos com isso!".
Em breve postarei um código de levantamento para Vacuum que utiliza esse recurso, consegui para alguns cenários uma redução de tempo de 32 horas para 10 horas. Isso mesmo, ou seja, economia de 22 horas de processamento (DBUs, VMs, discos, IPs).
Esse é um caso de uso que se aplicou muito bem, mas reforço que paralelismo é complexo e quando mal utilizado ou utilizado sem estudos, pode piorar seus processos.
Lembrem-se quando estamos em Cloud PERFORMANCE = CUSTO.
Link do github:
Referência:
[UPDATED]
Eu reforcei várias vezes sobre o uso correto e se mal utilizado você pode ter problemas, o @Eduardo Van Gasse deixou um comentário no LinkedIn pedindo alguns exemplos de quando ele poderia ser ruim, então trago um exemplo clássico de problema que você pode ter no seu cluster:
Erro:
"The spark driver has stopped unexpectedly and is restarting. Your notebook will be automatically reattached."
Esse erro é devido à sobrecarga no Driver do seu cluster devido à operação do Garbage Collector, nesse caso o cluster foi reiniciado e todo mundo que estava conectado foi automaticamente desconectado. Esse erro é muito comum quando você utiliza muito Python ao invés de PySpark, pois, o Python normal é Single Node ele vai sempre processar apenas no Driver. O pyspark já possui muitas extensões como o próprio Pandas (pyspark.pandas) para que você evite esses erros distribuindo a carga com todo o cluster.
Outra dica, se você usa Pandas, troque para pyspark.pandas assim que possível.
Espero que te ajude.
Fique bem e até a próxima.