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
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
-
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-nameNODEGROUP_NAME
\ --scaling-config minSize=0,maxSize=5,desiredSize=2CHOOSE_APPROPRIATELY
\ --ami-type AL2_x86_64_GPU \ --node-roleNODE_ROLE
\ --subnetsSUBNETS_SPACE_DELIMITED
\ --remote-access ec2SshKey=SSH_KEY
\ --instance-typesGPU_INSTANCE_TYPE
\ --disk-sizeDISK_SIZE
\ --regionAWS_REGION
-
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
-
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
-
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-arnJOB_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
"}}}' -
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.
-
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-arnJOB_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
-