Sobre as estratégias de compartilhamento de GPU no GKE


Nesta página, explicamos e comparamos as estratégias de compartilhamento de GPU disponíveis no Google Kubernetes Engine (GKE). Nesta página, presumimos que você conhece os conceitos do Kubernetes, como pods, nós, implantações e namespaces e os conceitos do GKE como pools de nós, escalonamento automático e provisionamento automático.

Como as solicitações de GPU funcionam no Kubernetes

O Kubernetes permite que as carga de trabalho solicitem com precisão os valores de recursos necessários para que eles funcionem. Embora seja possível solicitar unidades de CPU fracionárias para cargas de trabalho, não é possível solicitar unidades de GPU fracionárias. Os manifestos dos pods precisam solicitar recursos da GPU em números inteiros, o que significa que uma GPU física inteira é alocada para um contêiner, mesmo que ele precise de apenas uma fração dos recursos para funcionar corretamente. Isso é ineficiente e pode ser caro, especialmente quando você estiver executando várias cargas de trabalho com requisitos de GPU baixos semelhantes. Recomendamos que você use estratégias de compartilhamento de GPU para melhorar a utilização quando as cargas de trabalho não usarem todos os recursos da GPU.

O que são as estratégias de compartilhamento de GPU?

As estratégias de compartilhamento de GPU permitem que vários contêineres usem com eficiência as GPUs anexadas e economizem custos de execução. O GKE fornece as seguintes estratégias de compartilhamento de GPU:

  • GPU de várias instâncias: o GKE divide uma única GPU compatível em até sete frações. Cada fração pode ser alocada de modo independente para um contêiner no nó, com um máximo de sete contêineres por GPU. A GPU de várias instâncias fornece isolamento de hardware entre as cargas de trabalho e qualidade de serviço (QoS) consistente e previsível para todos os contêineres em execução na GPU.
  • Compartilhamento de tempo da GPU: o GKE usa a capacidade integrada de compartilhamento de tempo fornecida pela GPU NVIDIA e pela pilha de software. A partir da arquitetura Pascal (em inglês), as GPUs NVIDIA são compatíveis com preempção em nível de instrução. Ao fazer a alternância de contexto entre processos em execução em uma GPU, a preempção no nível de instrução garante que todos os processos tenham uma redução justa. O compartilhamento de tempo de GPU fornece isolamento de software entre as cargas de trabalho em termos de isolamento de memória (espaço de endereço), de desempenho e de falhas.
  • MPS da NVIDIA: o GKE usa o serviço multiprocesso (MPS, na sigla em inglês) da NVIDIA. O NVIDIA MPS é uma implementação alternativa e compatível com binários da API CUDA projetada para permitir que cargas de trabalho CUDA cooperativas de vários processos sejam executadas simultaneamente em um único dispositivo GPU. A GPU com NVIDIA MPS oferece isolamento de software em termos de limites de recursos (porcentagem de linhas de execução ativas e memória fixada do dispositivo.

Qual estratégia de compartilhamento de GPU usar

A tabela a seguir resume e compara as características das estratégias de compartilhamento de GPU disponíveis:

GPU de várias instâncias Compartilhamento de tempo de GPU MPS da NVIDIA
Geral Compartilhamento paralelo de GPU entre contêineres Troca rápida de contexto. Compartilhamento paralelo de GPU entre contêineres
Isolamento Uma GPU é dividida em até sete frações, e cada contêiner na mesma GPU física tem computação, memória e largura de banda dedicada. Portanto, um contêiner em uma partição tem uma capacidade e latência previsíveis, mesmo quando outros contêineres saturam outras partições.

Cada contêiner acessa a capacidade total da GPU física subjacente alternando o contexto entre os processos em execução em uma GPU.

No entanto, o compartilhamento de tempo não fornece isolamento de memória entre jobs compartilhados e a troca rápida de contexto para acesso compartilhado pode gerar sobrecargas.

O NVIDIA MPS tem isolamento de recursos limitado, mas ganha mais flexibilidade em outras dimensões, como tipos de GPU e número máximo de unidades compartilhadas, o que simplifica a alocação de recursos.
Adequado para estas cargas de trabalho Recomendado para cargas de trabalho executadas em paralelo e que precisam de certa resiliência e QoS. Por exemplo, ao executar cargas de trabalho de inferência de IA, a GPU de várias instâncias da GPU permite que diversas consultas de inferência sejam executadas simultaneamente para respostas rápidas, sem desacelerar umas às outras.

Recomendado para cargas de trabalho interativas e em bursts com períodos de inatividade. Essas cargas de trabalho não são econômicas com uma GPU totalmente dedicada. Com o compartilhamento de tempo, as cargas de trabalho têm acesso rápido à GPU quando estão em fases ativas.

O compartilhamento de tempo da GPU é ideal para cenários em que o isolamento total e o acesso contínuo à GPU não são necessários, por exemplo, quando vários usuários testam ou criam protótipos de cargas de trabalho sem GPUs caras inativas.

As cargas de trabalho que usam o compartilhamento de tempo precisam tolerar determinados comprometimentos de desempenho e latência.

Recomendado para o processamento em lote para jobs pequenos porque os MPS maximizam a capacidade e o uso simultâneo de uma GPU. Os MPS permitem que jobs em lote sejam processados de maneira eficiente e paralela para cargas de trabalho de pequeno e médio porte.

O NVIDIA MPS é ideal para processos cooperativos que atuam como um único aplicativo. Por exemplo, jobs de MPI com paralelismo de classificação entre MPI. Com esses jobs, cada pequeno processo CUDA (geralmente classificações MPI) pode ser executado simultaneamente na GPU para saturar totalmente a GPU.

As cargas de trabalho que usam CUDA MPS precisam tolerar as limitações de proteção de memória e contenção de erros.

Monitoramento As métricas de utilização da GPU não estão disponíveis para GPUs de várias instâncias. Use o Cloud Monitoring para monitorar o desempenho do compartilhamento de tempo da GPU. Para saber mais sobre as métricas disponíveis, consulte Monitorar o compartilhamento de tempo da GPU ou os nós do NVIDIA MPS. Use o Cloud Monitoring para monitorar o desempenho do NVIDIA MPS. Para saber mais sobre as métricas disponíveis, consulte Monitorar o compartilhamento de tempo da GPU ou os nós do NVIDIA MPS.
Solicitar GPUs compartilhadas em cargas de trabalho Executar GPUs de várias instâncias Execute GPUs com compartilhamento de tempo Execute GPUs com NVIDIA MPS

Se você quiser maximizar a utilização da GPU, combine as estratégias de compartilhamento de GPU para usar o compartilhamento de tempo ou NVIDIA MPS para cada partição de GPU de várias instâncias. Em seguida, é possível executar vários contêineres em cada partição, sendo que eles compartilham o acesso aos recursos nessa partição. Recomendamos que você use qualquer uma das seguintes combinações:

  • Compartilhamento de tempo entre GPUs e GPUs de várias instâncias.
  • GPU de várias instâncias e NVIDIA MPS.

Como funcionam as estratégias de compartilhamento de GPU

É possível especificar o número máximo de contêineres com permissão para compartilhar uma GPU física. Nos clusters do Autopilot, isso é configurado na especificação da carga de trabalho. Em clusters padrão, isso é configurado quando você cria um novo pool de nós com GPUs anexadas. Cada GPU no pool de nós é compartilhada com base na configuração especificada no nível do pool de nós.

As seções a seguir explicam o comportamento de programação e a operação de cada estratégia de compartilhamento de GPU.

GPU de várias instâncias

É possível solicitar a GPU de várias instâncias nas cargas de trabalho especificando o rótulo cloud.google.com/gke-gpu-partition-size no campo nodeSelector da especificação do pod, em spec: nodeSelector.

O GKE programa cargas de trabalho em nós disponíveis que correspondem a esses rótulos. Se não houver nós disponíveis, o GKE usará o escalonamento automático e o provisionamento automático de nós para criar novos nós ou pools de nós que correspondam ao rótulo.

Compartilhamento de tempo de GPU ou NVIDIA MPS

É possível solicitar o compartilhamento de tempo da GPU ou MPS da NVIDIA nas cargas de trabalho especificando os seguintes rótulos no campo nodeSelector da especificação do pod, em spec:nodeSelector.

  • cloud.google.com/gke-max-shared-clients-per-gpu: seleciona nós que permitem que um número específico de clientes compartilhe a GPU subjacente.
  • cloud.google.com/gke-gpu-sharing-strategy: selecione nós que usam a estratégia de compartilhamento de tempo ou NVIDIA MPS para GPUs.

A tabela a seguir descreve como o comportamento de programação muda com base na combinação dos rótulos de nós especificados nos manifestos.

Rótulos de nó
cloud.google.com/gke-max-shared-clients-per-gpu

e

cloud.google.com/gke-gpu-sharing-strategy

O GKE programa cargas de trabalho nos nós disponíveis que correspondem aos dois rótulos.

Se não houver nós disponíveis, o GKE usará o escalonamento automático e o provisionamento automático de nós para criar novos nós ou pools de nós que correspondam aos dois rótulos.

Somente cloud.google.com/gke-max-shared-clients-per-gpu

Autopilot: o GKE rejeita a carga de trabalho.

Standard: o GKE programa cargas de trabalho nos nós disponíveis que correspondem ao rótulo. Se não houver nós disponíveis, o GKE usará o escalonamento automático e o provisionamento automático de nós para criar novos nós ou pools de nós que correspondam ao rótulo. Por padrão, os nós com provisionamento automático recebem o rótulo e o valor a seguir para cada estratégia:

  • Compartilhamento de tempo da GPU: cloud.google.com/gke-gpu-sharing-strategy=TIME_SHARING
  • MPS da NVIDIA: cloud.google.com/gke-gpu-sharing-strategy=MPS
Somente cloud.google.com/gke-gpu-sharing-strategy

Autopilot: o GKE rejeita a carga de trabalho.

Padrão: o GKE programa cargas de trabalho em nós disponíveis que usam estratégias de compartilhamento específicas.

  • Se houver vários pools de nós de compartilhamento múltiplo com valores diferentes para cloud.google.com/gke-max-shared-clients-per-gpu, a carga de trabalho poderá ser programada em qualquer nó disponível.
  • Se não houver nós disponíveis em nenhum pool de nós, o escalonador automático de clusters escalonará o pool com o valor mais baixo para cloud.google.com/gke-max-shared-clients-per-gpu.
  • Se todos os pools de nós estiverem no limite da capacidade, o provisionamento automático de nós criará um novo pool com um valor padrão de cloud.google.com/gke-max-shared-clients-per-gpu=2.

O processo de solicitação de GPU que você conclui é o mesmo para o compartilhamento de tempo da GPU e a estratégia de MPS da NVIDIA. Se você está desenvolvendo aplicativos de GPU que são executados em compartilhamento de tempo de GPU ou NVIDIA MPS, é possível solicitar somente uma GPU para cada contêiner. O GKE rejeita uma solicitação de mais de uma GPU em um contêiner para evitar comportamentos inesperados. O número de compartilhamento de tempo da GPU e os MPS da NVIDIA não são uma medida da potência de computação disponível ao contêiner do Docker.

A tabela a seguir mostra o que esperar quando você solicita quantidades específicas de GPUs.

Solicitações de GPU que se aplicam a compartilhamento de tempo de GPU e NVIDIA MPS
Um compartilhamento de tempo de GPU ou NVIDIA MPS por contêiner O GKE permite a solicitação, mesmo que o nó tenha uma GPU física ou várias GPUs físicas.
Mais de um compartilhamento de tempo de GPU por contêiner

O GKE recusa a solicitação.

Esse comportamento inclui a solicitação de mais de uma instância de GPU de várias instâncias em um contêiner, porque cada instância de GPU é considerada uma GPU física discreta.

Mais de um NVIDIA MPS por contêiner

Com base no número de GPUs físicas no nó, o GKE faz o seguinte:

  • O GKE permite a solicitação quando o nó tem apenas uma GPU física.
  • O GKE rejeita a solicitação quando o nó tem várias GPUs físicas, como a solicitação de mais de uma instância de GPU de várias instâncias em um contêiner. Essa rejeição acontece porque cada instância de GPU é considerada uma GPU física discreta.

Se o GKE rejeitar a carga de trabalho, você verá uma mensagem de erro semelhante a esta:

status:
  message: 'Pod Allocate failed due to rpc error: code = Unknown desc = [invalid request
    for sharing GPU (time-sharing), at most 1 nvidia.com/gpu can be requested on GPU nodes], which is unexpected'
  phase: Failed
  reason: UnexpectedAdmissionError

Monitore o compartilhamento de tempo da GPU ou os nós do NVIDIA MPS

Use o Cloud Monitoring para monitorar o desempenho dos nós de compartilhamento de tempo da GPU ou dos nós NVIDIA MPS. O GKE envia métricas para cada nó da GPU para o Cloud Monitoring. Essas métricas são diferentes das métricas de GPUs regulares que não são compartilhadas por tempo ou nós de MPS do NVIDA.

É possível verificar as seguintes métricas para cada nó de compartilhamento de tempo de GPU ou nó de MPS da NVIDIA no Cloud Monitoring:

  • Ciclo de trabalho (node/accelerator/duty_cycle): porcentagem de tempo no último período de amostra (10 segundos) em que o nó da GPU estava processando ativamente. Varia de 1 a 100%.
  • Uso da memória (node/accelerator/memory_used): quantidade de memória do acelerador alocada em bytes para cada nó da GPU.
  • Capacidade de memória (node/accelerator/memory_total): memória total do acelerador em bytes para cada nó da GPU.

Essas métricas de nó de compartilhamento de tempo da GPU ou de nó MPS da NVIDIA são aplicadas no nível do nó. (node/accelerator/) e as métricas de GPUs físicas regulares aplicar no nível do contêiner (container/accelerator). As métricas das GPUs físicas regulares não são coletados para contêineres programados em uma GPU que usa compartilhamento de tempo de GPU ou NVIDIA MPS.

A seguir