As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.
Tópicos principais no Apache Spark
Esta seção explica os conceitos básicos do Apache Spark e os principais tópicos AWS Glue para ajuste do desempenho do Apache Spark. É importante entender esses conceitos e tópicos antes de discutir estratégias de ajuste no mundo real.
Arquitetura
O driver do Spark é o principal responsável por dividir seu aplicativo Spark em tarefas que podem ser realizadas por trabalhadores individuais. O motorista do Spark tem as seguintes responsabilidades:
-
Executando
main()
em seu código -
Gerando planos de execução
-
Provisionamento de executores do Spark em conjunto com o gerenciador de cluster, que gerencia os recursos no cluster
-
Agendar tarefas e solicitar tarefas para os executores do Spark
-
Gerenciando o progresso e a recuperação de tarefas
Você usa um SparkContext
objeto para interagir com o driver do Spark na execução do seu trabalho.
Um executor do Spark trabalha para armazenar dados e executar tarefas que são passadas pelo driver do Spark. O número de executores do Spark aumentará e diminuirá com o tamanho do seu cluster.
nota
Um executor do Spark tem vários slots para que várias tarefas sejam processadas paralelamente. Por padrão, o Spark suporta uma tarefa para cada núcleo de CPU virtual (vCPU). Por exemplo, se um executor tiver quatro núcleos de CPU, ele poderá executar quatro tarefas simultâneas.
Conjunto de dados distribuído resiliente
O Spark faz o trabalho complexo de armazenar e rastrear grandes conjuntos de dados entre os executores do Spark. Ao escrever código para trabalhos do Spark, você não precisa pensar nos detalhes do armazenamento. O Spark fornece a abstração resiliente de conjunto de dados distribuído (RDD), que é uma coleção de elementos que podem ser operados paralelamente e particionados entre os executores do Spark do cluster.
A figura a seguir mostra a diferença em como armazenar dados na memória quando um script Python é executado em seu ambiente típico e quando executado na estrutura Spark (). PySpark
-
Python — Escrever
val = [1,2,3...N]
em um script Python mantém os dados na memória na única máquina em que o código está sendo executado. -
PySpark— O Spark fornece a estrutura de dados RDD para carregar e processar dados distribuídos pela memória em vários executores do Spark. Você pode gerar um RDD com códigos como
rdd = sc.parallelize[1,2,3...N]
, e o Spark pode distribuir e armazenar dados automaticamente na memória entre vários executores do Spark.Em muitos AWS Glue trabalhos, você usa RDDs por meio do AWS Glue DynamicFramesDataFramesSpark. Essas são abstrações que permitem definir o esquema de dados em um RDD e realizar tarefas de nível superior com essas informações adicionais. Como eles usam RDDs internamente, os dados são distribuídos de forma transparente e carregados em vários nós no código a seguir:
-
DynamicFrame
dyf= glueContext.create_dynamic_frame.from_options( 's3', {"paths": [ "s3://<YourBucket>/<Prefix>/"]}, format="parquet", transformation_ctx="dyf" )
-
DataFrame
df = spark.read.format("parquet") .load("s3://<YourBucket>/<Prefix>")
-
Um RDD tem as seguintes características:
-
Os RDDs consistem em dados divididos em várias partes chamadas partições. Cada executor do Spark armazena uma ou mais partições na memória e os dados são distribuídos entre vários executores.
-
Os RDDs são imutáveis, o que significa que não podem ser alterados após serem criados. Para alterar a DataFrame, você pode usar transformações, que são definidas na seção a seguir.
-
Os RDDs replicam dados nos nós disponíveis, para que possam se recuperar automaticamente de falhas nos nós.
Avaliação preguiçosa
Os RDDs oferecem suporte a dois tipos de operações: transformações, que criam um novo conjunto de dados a partir de um existente, e ações, que retornam um valor ao programa do driver após executar um cálculo no conjunto de dados.
-
Transformações — Como os RDDs são imutáveis, você só pode alterá-los usando uma transformação.
Por exemplo,
map
é uma transformação que passa cada elemento do conjunto de dados por meio de uma função e retorna um novo RDD representando os resultados. Observe que omap
método não retorna uma saída. O Spark armazena a transformação abstrata para o futuro, em vez de permitir que você interaja com o resultado. O Spark não atuará nas transformações até que você chame uma ação. -
Ações — Usando transformações, você constrói seu plano lógico de transformação. Para iniciar o cálculo, você executa uma ação como
write
,count
show
, ou.collect
Todas as transformações no Spark são lentas, pois não computam seus resultados imediatamente. Em vez disso, o Spark lembra uma série de transformações aplicadas a alguns conjuntos de dados básicos, como objetos do Amazon Simple Storage Service (Amazon S3). As transformações são computadas somente quando uma ação exige que um resultado seja retornado ao driver. Esse design permite que o Spark funcione com mais eficiência. Por exemplo, considere a situação em que um conjunto de dados criado por meio da
map
transformação é consumido somente por uma transformação que reduz substancialmente o número de linhas, como.reduce
Em seguida, você pode passar o conjunto de dados menor que passou por ambas as transformações para o driver, em vez de passar o conjunto de dados mapeado maior.
Terminologia dos aplicativos do Spark
Esta seção aborda a terminologia do aplicativo Spark. O driver do Spark cria um plano de execução e controla o comportamento dos aplicativos em várias abstrações. Os termos a seguir são importantes para desenvolvimento, depuração e ajuste de desempenho com a interface do usuário do Spark.
-
Aplicativo — Baseado em uma sessão do Spark (contexto do Spark). Identificado por um ID exclusivo, como
<application_XXX>
. -
Trabalhos — Com base nas ações criadas para um RDD. Um trabalho consiste em um ou mais estágios.
-
Estágios — Com base nos shuffles criados para um RDD. Um estágio consiste em uma ou mais tarefas. O shuffle é o mecanismo do Spark para redistribuir dados para que sejam agrupados de forma diferente nas partições RDD. Certas transformações, como
join()
, exigem um embaralhamento. O shuffle é discutido com mais detalhes na prática de ajuste do Optimize shuffles. -
Tarefas — Uma tarefa é a unidade mínima de processamento agendada pelo Spark. As tarefas são criadas para cada partição RDD, e o número de tarefas é o número máximo de execuções simultâneas no estágio.
nota
As tarefas são a coisa mais importante a se considerar ao otimizar o paralelismo. O número de tarefas aumenta com o número de RDD
Paralelismo
O Spark paraleliza tarefas para carregar e transformar dados.
Considere um exemplo em que você executa o processamento distribuído de arquivos de log de acesso (nomeadosaccesslog1 ... accesslogN
) no Amazon S3. O diagrama a seguir mostra o fluxo de processamento distribuído.
-
O driver do Spark cria um plano de execução para processamento distribuído entre vários executores do Spark.
-
O driver do Spark atribui tarefas a cada executor com base no plano de execução. Por padrão, o driver do Spark cria partições RDD (cada uma correspondendo a uma tarefa do Spark) para cada objeto do S3 ().
Part1 ... N
Em seguida, o driver do Spark atribui tarefas a cada executor. -
Cada tarefa do Spark baixa seu objeto S3 atribuído e o armazena na memória na partição RDD. Dessa forma, vários executores do Spark baixam e processam paralelamente a tarefa atribuída.
Para obter mais detalhes sobre o número inicial de partições e a otimização, consulte a seção Paralelizar tarefas.
Otimizador de catalisador
Internamente, o Spark usa um mecanismo chamado otimizador Catalyst para otimizar
Como o otimizador Catalyst não funciona diretamente com a API RDD, as APIs de alto nível geralmente são mais rápidas do que a API RDD de baixo nível. Para uniões complexas, o otimizador Catalyst pode melhorar significativamente o desempenho otimizando o plano de execução do trabalho. Você pode ver o plano otimizado do seu trabalho do Spark na guia SQL da interface do usuário do Spark.
Execução adaptativa de consultas
O otimizador Catalyst executa a otimização do tempo de execução por meio de um processo chamado Adaptive Query Execution. O Adaptive Query Execution usa estatísticas de tempo de execução para otimizar novamente o plano de execução das consultas enquanto seu trabalho está em execução. O Adaptive Query Execution oferece várias soluções para os desafios de desempenho, incluindo a coalescência de partições pós-aleatório, a conversão da junção de classificação e mesclagem em junção de transmissão e a otimização da junção inclinada, conforme descrito nas seções a seguir.
A Execução Adaptativa de Consultas está disponível na AWS Glue versão 3.0 e posterior e está ativada por padrão na AWS Glue versão 4.0 (Spark 3.3.0) e versões posteriores. A execução adaptativa de consultas pode ser ativada e desativada usando spark.conf.set("spark.sql.adaptive.enabled",
"true")
em seu código.
Partições coalescentes pós-embaralhamento
Esse recurso reduz as partições RDD (coalescem) após cada reprodução aleatória com base nas estatísticas de saída. map
Isso simplifica o ajuste do número da partição aleatória ao executar consultas. Você não precisa definir um número de partição aleatório para caber no seu conjunto de dados. O Spark pode escolher o número adequado da partição aleatória em tempo de execução depois que você tiver um número inicial de partições aleatórias grande o suficiente.
A coalescência de partições pós-reprodução aleatória é ativada quando ambas estão definidas como verdadeiras. spark.sql.adaptive.enabled
spark.sql.adaptive.coalescePartitions.enabled
Para obter mais informações, consulte a documentação do Apache Spark
Convertendo junção de classificação e mesclagem em junção de transmissão
Esse recurso reconhece quando você está unindo dois conjuntos de dados de tamanhos substancialmente diferentes e adota um algoritmo de junção mais eficiente com base nessas informações. Para obter mais detalhes, consulte a documentação do Apache Spark
Otimização de junções inclinadas
A distorção de dados é um dos gargalos mais comuns nas tarefas do Spark. Ele descreve uma situação na qual os dados são distorcidos para partições RDD específicas (e, consequentemente, tarefas específicas), o que atrasa o tempo geral de processamento do aplicativo. Isso geralmente pode reduzir o desempenho das operações de junção. O recurso de otimização de junções inclinadas manipula dinamicamente a distorção nas junções de classificação e mesclagem dividindo (e replicando, se necessário) tarefas distorcidas em tarefas de tamanho aproximadamente uniforme.
Esse recurso é ativado quando spark.sql.adaptive.skewJoin.enabled
definido como verdadeiro. Para obter mais detalhes, consulte a documentação do Apache Spark