Uso do acelerador RAPIDS para Apache Spark com o Amazon EMR no EKS - Amazon EMR

Uso do acelerador RAPIDS para Apache Spark com o Amazon EMR no EKS

Com o Amazon EMR no EKS, você pode executar trabalhos para o acelerador RAPIDS da Nvidia para Apache Spark. Este tutorial aborda como executar trabalhos do Spark usando o RAPIDS em tipos de instância de unidade de processamento gráfico (GPU) do EC2. O tutorial usa as seguintes versões:

  • Amazon EMR no EKS na versão de liberação 6.9.0 e posteriores

  • Apache Spark 3.x

Você pode acelerar o Spark com os tipos de instância de GPU do Amazon EC2 usando o plug-in do acelerador RAPIDS da Nvidia para Apache Spark. Ao usar essas tecnologias em conjunto, você acelera os pipelines de ciência de dados sem a necessidade de realizar alterações no código. Isso reduz o tempo de execução necessário para o processamento de dados e para o treinamento de modelos. Ao fazer mais em menos tempo, você gasta menos com o custo da infraestrutura.

Antes de começar, certifique-se de ter os recursos apresentados a seguir.

  • Cluster virtual do Amazon EMR no EKS

  • Cluster do Amazon EKS com um grupo de nós habilitado para GPU

Um cluster virtual do Amazon EKS corresponde a um manipulador registrado para o namespace do Kubernetes em um cluster do Amazon EKS e é gerenciado pelo Amazon EMR no EKS. O manipulador permite que o Amazon EMR use o namespace do Kubernetes como destino para a execução de trabalhos. Para obter mais informações sobre como configurar um cluster virtual, consulte Configuração do Amazon EMR no EKS neste guia.

Você deve configurar o cluster virtual do Amazon EKS com um grupo de nós que tenha instâncias de GPU. Você deve configurar os nós com um plug-in para dispositivos da Nvidia. Consulte Grupos de nós gerenciados para saber mais.

Para configurar o cluster do Amazon EKS para adicionar grupos de nós habilitados para GPU, execute o seguinte procedimento:

Adicionar grupos de nós habilitados para GPU
  1. Crie um grupo de nós habilitado para GPU com o comando create-nodegroup apresentado a seguir. Certifique-se de realizar a substituição com os parâmetros corretos para o cluster do Amazon EKS. Use um tipo de instância compatível com RAPIDS para Spark, como P4, P3, G5 ou G4dn.

    aws eks create-nodegroup \ --cluster-name EKS_CLUSTER_NAME \ --nodegroup-name NODEGROUP_NAME \ --scaling-config minSize=0,maxSize=5,desiredSize=2 CHOOSE_APPROPRIATELY \ --ami-type AL2_x86_64_GPU \ --node-role NODE_ROLE \ --subnets SUBNETS_SPACE_DELIMITED \ --remote-access ec2SshKey= SSH_KEY \ --instance-types GPU_INSTANCE_TYPE \ --disk-size DISK_SIZE \ --region AWS_REGION
  2. Instale o plug-in para dispositivos da Nvidia em seu cluster com a finalidade de emitir o número de GPUs em cada nó do cluster e de executar contêineres habilitados para GPU em seu cluster. Execute o seguinte código para instalar o plug-in:

    kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.9.0/nvidia-device-plugin.yml
  3. Para validar quantas GPUs estão disponíveis em cada nó do seu cluster, execute o seguinte comando:

    kubectl get nodes "-o=custom-columns=NAME:.metadata.name,GPU:.status.allocatable.nvidia\.com/gpu"
Executar um trabalho do RAPIDS para Spark
  1. Envie um trabalho do RAPIDS para Spark ao cluster do Amazon EMR no EKS. O código a seguir apresenta um exemplo de comando para iniciar o trabalho. Na primeira vez em que você executar o trabalho, poderá demorar alguns minutos para fazer download da imagem e armazená-la em cache no nó.

    aws emr-containers start-job-run \ --virtual-cluster-id VIRTUAL_CLUSTER_ID \ --execution-role-arn JOB_EXECUTION_ROLE \ --release-label emr-6.9.0-spark-rapids-latest \ --job-driver '{"sparkSubmitJobDriver": {"entryPoint": "local:///usr/lib/spark/examples/jars/spark-examples.jar","entryPointArguments": ["10000"], "sparkSubmitParameters":"--class org.apache.spark.examples.SparkPi "}}' \ ---configuration-overrides '{"applicationConfiguration": [{"classification": "spark-defaults","properties": {"spark.executor.instances": "2","spark.executor.memory": "2G"}}],"monitoringConfiguration": {"cloudWatchMonitoringConfiguration": {"logGroupName": "LOG_GROUP _NAME"},"s3MonitoringConfiguration": {"logUri": "LOG_GROUP_STREAM"}}}'
  2. Para validar se o acelerador RAPIDS para Spark está habilitado, verifique os logs do driver do Spark. Esses logs são armazenados no CloudWatch ou no local do S3 que você especifica ao executar o comando start-job-run. O seguinte exemplo apresenta como geralmente é a aparência das linhas de log:

    22/11/15 00:12:44 INFO RapidsPluginUtils: RAPIDS Accelerator build: {version=22.08.0-amzn-0, user=release, url=, date=2022-11-03T03:32:45Z, revision=, cudf_version=22.08.0, branch=}
    22/11/15 00:12:44 INFO RapidsPluginUtils: RAPIDS Accelerator JNI build: {version=22.08.0, user=, url=https://github.com/NVIDIA/spark-rapids-jni.git, date=2022-08-18T04:14:34Z, revision=a1b23cd_sample, branch=HEAD}
    22/11/15 00:12:44 INFO RapidsPluginUtils: cudf build: {version=22.08.0, user=, url=https://github.com/rapidsai/cudf.git, date=2022-08-18T04:14:34Z, revision=a1b23ce_sample, branch=HEAD}
    22/11/15 00:12:44 WARN RapidsPluginUtils: RAPIDS Accelerator 22.08.0-amzn-0 using cudf 22.08.0.
    22/11/15 00:12:44 WARN RapidsPluginUtils: spark.rapids.sql.multiThreadedRead.numThreads is set to 20.
    22/11/15 00:12:44 WARN RapidsPluginUtils: RAPIDS Accelerator is enabled, to disable GPU support set `spark.rapids.sql.enabled` to false.
    22/11/15 00:12:44 WARN RapidsPluginUtils: spark.rapids.sql.explain is set to `NOT_ON_GPU`. Set it to 'NONE' to suppress the diagnostics logging about the query placement on the GPU.
  3. Para visualizar as operações que serão executadas em uma GPU, execute as etapas apresentadas a seguir para ativar o registro em log adicional. Observe a configuração “spark.rapids.sql.explain : ALL”.

    aws emr-containers start-job-run \ --virtual-cluster-id VIRTUAL_CLUSTER_ID \ --execution-role-arn JOB_EXECUTION_ROLE \ --release-label emr-6.9.0-spark-rapids-latest \ --job-driver '{"sparkSubmitJobDriver": {"entryPoint": "local:///usr/lib/spark/examples/jars/spark-examples.jar","entryPointArguments": ["10000"], "sparkSubmitParameters":"--class org.apache.spark.examples.SparkPi "}}' \ ---configuration-overrides '{"applicationConfiguration": [{"classification": "spark-defaults","properties": {"spark.rapids.sql.explain":"ALL","spark.executor.instances": "2","spark.executor.memory": "2G"}}],"monitoringConfiguration": {"cloudWatchMonitoringConfiguration": {"logGroupName": "LOG_GROUP_NAME"},"s3MonitoringConfiguration": {"logUri": "LOG_GROUP_STREAM"}}}'

    O comando anterior é um exemplo de trabalho que usa a GPU. Sua saída seria semelhante ao exemplo abaixo. Consulte esta legenda para obter ajuda para compreender a saída:

    • *: marca uma operação que funciona em uma GPU.

    • !: marca uma operação que não pode ser executada em uma GPU.

    • @: marca uma operação que funciona em uma GPU, mas não será executada porque está em um plano que não pode ser executado em uma GPU.

     22/11/15 01:22:58 INFO GpuOverrides: Plan conversion to the GPU took 118.64 ms
     22/11/15 01:22:58 INFO GpuOverrides: Plan conversion to the GPU took 4.20 ms
     22/11/15 01:22:58 INFO GpuOverrides: GPU plan transition optimization took 8.37 ms
     22/11/15 01:22:59 WARN GpuOverrides:
        *Exec <ProjectExec> will run on GPU
          *Expression <Alias> substring(cast(date#149 as string), 0, 7) AS month#310 will run on GPU
            *Expression <Substring> substring(cast(date#149 as string), 0, 7) will run on GPU
              *Expression <Cast> cast(date#149 as string) will run on GPU
          *Exec <SortExec> will run on GPU
            *Expression <SortOrder> date#149 ASC NULLS FIRST will run on GPU
            *Exec <ShuffleExchangeExec> will run on GPU
              *Partitioning <RangePartitioning> will run on GPU
                *Expression <SortOrder> date#149 ASC NULLS FIRST will run on GPU
              *Exec <UnionExec> will run on GPU
                !Exec <ProjectExec> cannot run on GPU because not all expressions can be replaced
                  @Expression <AttributeReference> customerID#0 could run on GPU
                  @Expression <Alias> Charge AS kind#126 could run on GPU
                    @Expression <Literal> Charge could run on GPU
                  @Expression <AttributeReference> value#129 could run on GPU
                  @Expression <Alias> add_months(2022-11-15, cast(-(cast(_we0#142 as bigint) + last_month#128L) as int)) AS date#149 could run on GPU
                    ! <AddMonths> add_months(2022-11-15, cast(-(cast(_we0#142 as bigint) + last_month#128L) as int)) cannot run on GPU because GPU does not currently support the operator class org.apache.spark.sql.catalyst.expressions.AddMonths
                      @Expression <Literal> 2022-11-15 could run on GPU
                      @Expression <Cast> cast(-(cast(_we0#142 as bigint) + last_month#128L) as int) could run on GPU
                        @Expression <UnaryMinus> -(cast(_we0#142 as bigint) + last_month#128L) could run on GPU
                          @Expression <Add> (cast(_we0#142 as bigint) + last_month#128L) could run on GPU
                            @Expression <Cast> cast(_we0#142 as bigint) could run on GPU
                              @Expression <AttributeReference> _we0#142 could run on GPU
                            @Expression <AttributeReference> last_month#128L could run on GPU