Explorar as melhores práticas para a optimização do desempenho da faísca – desenvolvedor IBM

considero útil pensar e recordar os seguintes objectivos ao desenvolver e afinar as suas aplicações:

  1. Reduzir a e/S de Rede
  2. Reduzir a e/S de Disco
  3. Melhorar/otimizar a utilização da CPU, reduzindo desnecessário de computação, incluindo a filtragem de dados desnecessários, e garantir que seus recursos de CPU que estão chegando utilizados de forma eficiente
  4. Benefício de Ignição na memória de cálculo, incluindo cache, quando apropriado

Faísca características

vejamos algumas características da Centelha que nos ajudam a melhorar o desempenho.

comportamento preguiçoso de carga

a faísca Apache tem dois tipos de operações: transformações e acções.

Spark has lazy loading behavior for transformations. Isso significa que ele não vai desencadear o cálculo para a transformação; ele só mantém o controle da transformação solicitada. Quando você está escrevendo suas transformações que lhe dão outro conjunto de dados de um conjunto de dados de entrada, você pode codificá-lo de uma forma que torna o código legível. Você não precisa se preocupar em otimizá-lo e colocá-lo tudo em uma linha, porque faísca irá otimizar o fluxo sob as tampas para você. É bom escrever as transformações usando variáveis intermediárias com nomes significativos para que seja mais fácil ler o seu código.

as acções de faísca são desejosas de que desencadeiem um cálculo para a acção subjacente. Portanto, preste atenção quando você tem uma ação de faísca que você só chama quando necessário. Por exemplo, Contagem() em um conjunto de dados é uma ação de faísca. É uma questão comum que eu tenho visto onde há múltiplos Contagem () chamadas em aplicações Spark que são adicionados durante a depuração e eles não são removidos. É uma boa idéia procurar por ações de faísca e remover qualquer que não são necessários, porque não queremos usar ciclos de CPU e outros recursos quando não necessário.

formatos de ficheiro

quando estiver a desenhar os seus conjuntos de dados para a sua aplicação, certifique-se de que está a utilizar da melhor forma os formatos de ficheiro disponíveis com o Spark. Algumas coisas a considerar:

  • Spark é otimizado para Apache Parquet e ORC para leitura. Spark tem suporte de Vectorização que reduz os formatos de disco I/O. Columnar funcionam bem.
  • Use o formato de arquivo Parquet e faça uso da compressão.
  • existem diferentes formatos de arquivo e fontes de dados embutidas que podem ser usadas no Apache Spark.Usar formatos de ficheiros splitable.
  • certifique-se de que não há muitos arquivos pequenos. Se você tem muitos arquivos pequenos, pode fazer sentido fazer compactação deles para melhor desempenho.

paralelismo

  • aumenta o número de partições de faísca para aumentar o paralelismo com base no tamanho dos dados. Certifique-se de que os recursos do cluster são utilizados de forma otimizada. Poucas partições poderiam resultar em alguns executores sendo ociosos, enquanto muitas partições poderiam resultar em sobrecarga de programação de Tarefas.
  • Afine as partições e tarefas. Spark pode lidar com tarefas de 100ms+ e recomenda pelo menos 2-3 tarefas por núcleo para um executor.
  • Spark decide o número de partições com base na entrada do tamanho do arquivo. Às vezes, faz sentido especificar o número de partições explicitamente.
    • a API de leitura tem um número opcional de partições.
    • spark.banco.arquivo.maxPartitionBytes, disponível em Spark v2. 0.0, para Parquet, ORC, e JSON.
  • as partições de shuffle podem ser ajustadas ajustando spark.banco.embaralhar.partições, que corresponde por omissão a 200. Isto é realmente pequeno se você tiver Tamanhos Grandes de conjuntos de dados.

Reduce shuffle

Shuffle é uma operação cara, pois envolve mover dados através dos nós em seu cluster, que envolve rede e disco I/O. é sempre uma boa idéia para reduzir a quantidade de dados que precisa ser baralhado. Aqui estão algumas dicas para reduzir a baralhar:

  • Afine a faísca .banco.embaralhar.partições.
  • partita adequadamente o conjunto de dados de entrada para que cada tamanho da tarefa não seja muito grande.
  • Use a IU Spark para estudar o plano para procurar a oportunidade de reduzir o shuffle tanto quanto possível.
  • Formula recommendation for spark.banco.embaralhar.partições:
    • para grandes conjuntos de dados, apontar para qualquer lugar de 100MB a menos de 200MB de tamanho alvo tarefa para uma partição (usar o tamanho alvo de 100MB, por exemplo).
    • spark.banco.embaralhar.partições = quociente (tamanho da entrada no estágio de shuffle/Tamanho do alvo)/núcleos totais) * núcleos totais.

filtrar / reduzir o tamanho do conjunto de dados

procure oportunidades para filtrar os dados O MAIS CEDO POSSÍVEL no seu pipeline de aplicações. Se houver uma operação de filtro e você só estiver interessado em fazer análises para um subconjunto dos dados, aplique este filtro mais cedo. Se você pode reduzir o tamanho do conjunto de dados cedo, faça-o. Use os predicados de filtragem apropriados em sua consulta SQL para que a faísca pode empurrá-los para baixo para a fonte de dados subjacente; predicados seletivos são bons. Utilize-os conforme adequado. Usar filtros de partição, se forem aplicáveis.

Cache apropriadamente

Spark suporta a cache de conjuntos de dados na memória. Existem diferentes opções disponíveis:

  • Use caching quando a mesma operação é calculada várias vezes no fluxo de pipeline.
  • Use cache usando a API persistir para permitir a configuração de cache necessária (persistir no disco ou não; serializado ou não).
  • esteja ciente do carregamento preguiçoso e do cache prime se necessário à frente. Algumas APIs estão ansiosas e outras não.
  • confira a página de armazenamento da Spark UI para ver informações sobre os conjuntos de dados que tem em cache.
  • é uma boa prática desvendar o seu conjunto de dados em cache quando você terminar de usá-los a fim de liberar recursos, particularmente quando você tem outras pessoas usando o conjunto também.

Join

Join é, em geral, uma operação cara, por isso preste atenção às junções em sua aplicação para otimizá-las. Broadcastashjoin é o mais importante para os casos em que uma das relações é pequena o suficiente para que possa ser transmitida. Abaixo estão algumas dicas:

  • Join order matters; start with the most selective join. Para as relações inferiores a faísca.banco.autoBroadcastJoinThreshold, pode verificar se a transmissão HashJoin é captada.
  • Use dicas SQL se necessário para forçar um tipo específico de junção.Exemplo :quando se junta um pequeno conjunto de dados com um grande conjunto de dados, uma junção de transmissão pode ser forçada a transmitir o pequeno conjunto de dados.
  • confirme que Spark está captando hash join de transmissão; se não, pode-se forçá-lo usando a dica SQL.
  • evitar cruzamentos.
  • Broadcast HashJoin is most performant, but may not be applicable if both relations in join are large.
  • recolher estatísticas sobre as tabelas para a faísca para calcular um plano óptimo.
  • Tune cluster resources

    • Tune the resources on the cluster depending on the resource manager and version of Spark.
    • Sintonize a memória disponível para o driver: spark.controlador.memoria.
    • Afine o número de executores e a memória e o uso do núcleo baseado em recursos no cluster: executor-memória, num-executores, e executor-núcleos.

    confira a documentação de configuração para a libertação de faísca com a qual está a trabalhar e utilize os parâmetros apropriados.

    evite operações dispendiosas

    • evite ordem por se não for necessário.
    • quando estiver a escrever as suas consultas, em vez de usar select * para obter todas as colunas, apenas recupere as colunas relevantes para a sua consulta.
    • não faça a contagem desnecessariamente.

    Data skew

    • assegurar que as partições são iguais em tamanho para evitar dados distorcidos e problemas de baixa utilização de CPU.
      • como exemplo: se você tem dados provenientes de uma fonte de dados JDBC em paralelo, e cada uma dessas partições não está recuperando um número similar de registros, isso resultará em tarefas de tamanho desigual (uma forma de desvio de dados). Talvez uma partição seja apenas alguns KB, enquanto outra é algumas centenas MB. Algumas tarefas serão maiores do que outras, e enquanto os executores em tarefas maiores estarão ocupados, os outros executores, que estão lidando com a tarefa menor, terminarão e ficarão ociosos.
      • se os dados na fonte não são particionados de forma otimizada, Você também pode avaliar os tradeoffs de usar repartição para obter uma partição equilibrada e, em seguida, usar caching para persistir na memória, se apropriado.
    • Repartition vai causar um shuffle, e shuffle é uma operação cara, então isso deve ser avaliado em uma base de Aplicação.
    • Use a ignição UI para procurar os tamanhos de partição e duração da tarefa.

    UDFs

    Spark has a number of built-in user-defined functions (UDFs) available. Para o desempenho, Verifique se você pode usar uma das funções incorporadas, uma vez que elas são boas para o desempenho. UDFs personalizados na API Scala são mais performant do que UDFs Python. Se você tiver que usar a API Python, use o recém-introduzido pandas UDF em Python que foi lançado em Spark 2.3. O Suporte de UDF pandas (UDF vectorized) na Spark tem melhorias significativas de desempenho, ao invés de escrever uma UDF Python personalizada. Obtenha mais informações sobre escrever um pandas UDF.

    espero que isso tenha sido útil para você enquanto você vai escrevendo suas aplicações Spark. Feliz desenvolvimento! Em um blog próximo, eu vou mostrar como obter o plano de execução para o seu trabalho faísca.

    Deixe uma resposta

    O seu endereço de email não será publicado.