Este documento descreve as ferramentas e as práticas recomendadas para maximizar a utilização de recursos e minimizar o tempo de inatividade das cargas de trabalho de IA/ML heterogéneas no Google Kubernetes Engine (GKE), especialmente quando não existe capacidade nas reservas ou através de recursos a pedido. As cargas de trabalho heterogéneas referem-se a diferentes tipos de cargas de trabalho de IA/ML que são executadas em simultâneo no mesmo cluster do GKE. Por exemplo, pode executar um serviço de inferência online sensível à latência juntamente com uma série de tarefas de preparação em lote interrompíveis.
Este guia oferece recomendações para administradores e operadores da plataforma, bem como especialistas em dados e IA.
Vantagens da priorização da carga de trabalho de IA/ML
As cargas de trabalho heterogéneas têm prioridades diferentes e partilham capacidade e recursos limitados. As práticas recomendadas nesta página descrevem como configurar o GKE e as ferramentas de código aberto para ajudar a obter as seguintes vantagens:
- Minimize o tempo de inatividade para cargas de trabalho de alta prioridade.
- Executar rapidamente cargas de trabalho de alta prioridade.
- Otimize o consumo de recursos.
Contexto
O GKE suporta as seguintes ferramentas de código aberto para otimizar a utilização de recursos.
Kueue: um sistema de filas de cargas de trabalho nativo do Kubernetes concebido para cargas de trabalho de lotes, IA e computação de elevado desempenho. O Kueue pode ser expandido para gerir outros tipos de cargas de trabalho, como os definidos por definições de recursos personalizados, como
leaderworkerset. O Kueue gere as quotas e a forma como as cargas de trabalho as consomem num cluster do Kubernetes. O Kueue toma decisões sobre quando uma carga de trabalho espera, quando uma carga de trabalho começa (por exemplo, criando o pod) e quando um pod pertencente a uma carga de trabalho é anulado.Para mais informações sobre o Kueue, consulte a documentação de conceitos do Kueue.
Hotswap: uma técnica que reduz o tempo médio de recuperação (MTTR). A troca a quente permite a preempção com base na prioridade da carga de trabalho quando os recursos do cluster são totalmente utilizados e não está disponível capacidade adicional, quer seja de instâncias a pedido ou de reservas existentes.
- Quando um nó que aloja uma carga de trabalho fica em mau estado, a carga de trabalho é reagendada em nós sobresselentes elegíveis. Se não estiverem disponíveis nós adicionais, a troca a quente pode substituir uma carga de trabalho de prioridade inferior para dar lugar à carga de trabalho a ser recuperada.
- Se configurar os seus pods com
PriorityClass, a carga de trabalho configurada com uma prioridade mais elevada desalojará uma carga de trabalho de baixa prioridade em execução para adquirir os respetivos recursos. Este processo de despejo é conhecido como preemptiva.
Exemplos de utilização
Use a tabela seguinte para compreender as práticas recomendadas para cada exemplo de utilização:
| Exemplo de utilização | Prática recomendada | Descrição |
|---|---|---|
| Várias cargas de trabalho com prioridades diferentes | Use o Kueue para definir filas e atribuir prioridades a cargas de trabalho com base na respetiva importância. O Kueue pode gerir a quota para que determinadas equipas ou projetos tenham acesso a uma determinada quantidade de recursos. |
O Kueue permite-lhe aplicar as seguintes configurações:
Para testar a configuração de práticas recomendadas, consulte o exemplo do Kueue neste documento. |
| Tem de reduzir o MTTR atual. | Use a troca a quente para reagendar cargas de trabalho em recursos saudáveis quando ocorre uma interrupção e para antecipar cargas de trabalho de baixa prioridade em favor de cargas de trabalho de alta prioridade. |
A troca a quente permite-lhe aplicar as seguintes configurações:
Para testar a configuração de práticas recomendadas, consulte o exemplo de troca a quente neste documento. |
| Várias cargas de trabalho de IA a competir por recursos limitados | Combine o Kueue e o Hotswap. Esta combinação oferece um sistema robusto que dá prioridade às cargas de trabalho críticas durante o agendamento inicial e durante o tempo de execução. |
O Kueue e o Hotswap permitem-lhe aplicar as seguintes configurações:
Para testar a configuração das práticas recomendadas, consulte o exemplo de Kueue e Hotswap neste documento. |
Exemplos de implementações de práticas recomendadas
Os exemplos seguintes demonstram como implementar o Kueue e o Hotswap, e como combiná-los para as práticas recomendadas descritas na secção anterior.
Kueue
O exemplo de manifesto seguinte mostra uma configuração do Kueue:
apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
name: tpu-v6e-slice
spec:
nodeLabels:
cloud.google.com/gke-tpu-accelerator: tpu-v6e-slice
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
name: tpu-training-cq
spec:
resourceGroups:
- flavors:
- name: tpu-v6e-slice
resources:
- name: google.com/tpu
nominalQuota: 32
queueingStrategy: BestEffortFIFO
preemption:
reclaimWithinCohort: Never
reclaimOutOfCohort:
enable: true
reclaimMoreThanNominalQuota: false
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
name: default-queue
namespace: default
spec:
clusterQueue: tpu-training-cq
Este manifesto faz o seguinte:
- Define um
ResourceFlavordenominadotpu-v6e-sliceque especifica as etiquetas dos nós para fatias de TPU v6e. - Define um
ClusterQueuedenominadotpu-training-cqque gere a quota para recursos de TPU. - Define um
LocalQueuedenominadodefault-queueque permite que as cargas de trabalho no espaço de nomesdefaultusem a fila do clustertpu-training-cq.
Hotswap
O exemplo seguinte mostra uma configuração de troca a quente que define duas classes de prioridade, low-priority-job e high-priority-job. Esta configuração de troca a quente cria uma carga de trabalho JobSet de alta prioridade e usa MaxText.
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: low-priority-job
value: 1000000
globalDefault: false
description: "This priority class should be used for low priority pods only."
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority-job
value: 2000000
globalDefault: false
description: "This priority class should be used for critical pods only."
---
apiVersion: jobset.x-k8s.io/v1alpha2
kind: JobSet
metadata:
name: high-jax-trillium
annotations:
alpha.jobset.sigs.k8s.io/exclusive-topology: cloud.google.com/gke-nodepool
spec:
failurePolicy:
maxRestarts: 10
restartStrategy: BlockingRecreate
replicatedJobs:
- name: slice
replicas: 2
template:
spec:
backoffLimit: 0
completions: 4
parallelism: 4
template:
spec:
nodeSelector:
cloud.google.com/gke-tpu-accelerator: tpu-v6e-slice
cloud.google.com/gke-tpu-topology: 4x4
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
priorityClassName: high-priority-job
containers:
- name: jax-program
image: <IMAGE LOCATION>
command:
- python3
- MaxText/train.py
- MaxText/configs/base.yml
- model_name=llama2-7b
- run_name=<UNIQUE RUN NAME>
- steps=300
- base_output_directory=gs://<OUTPUT BUCKET>
- dataset_path=gs://max-datasets-rogue
- max_target_length=4096
- dataset_type=synthetic
- enable_checkpointing=False
resources:
limits:
google.com/tpu: 4
Com base nesta configuração, o Hotswap realiza as seguintes ações:
- Se uma falha de infraestrutura interromper a carga de trabalho de alta prioridade, o JobSet reinicia-a. A troca a quente antecipa a carga de trabalho de baixa prioridade para reagendar a carga de trabalho de alta prioridade antes de a infraestrutura recuperar. A carga de trabalho de baixa prioridade permanece com o estado de falha. Este processo reduz significativamente o tempo de inatividade da carga de trabalho.
- Quando a infraestrutura é recuperada, o Hotswap reagenda a carga de trabalho de baixa prioridade no conjunto de nós recuperado.
Kueue e Hotswap
Combine o Kueue e o Hotswap quando operar num ambiente complexo com recursos limitados. Esta combinação oferece um sistema robusto que prioriza cargas de trabalho críticas durante o agendamento inicial e durante o tempo de execução.
O exemplo seguinte mostra uma configuração combinada do Kueue e do Hotswap. Este exemplo usa MaxText:
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: low-priority-job
value: 1000000
globalDefault: false
description: "This priority class should be used for low priority pods only."
---
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority-job
value: 2000000
globalDefault: false
description: "This priority class should be used for critical pods only."
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ResourceFlavor
metadata:
name: tpu-v6e-slice
spec:
nodeLabels:
cloud.google.com/gke-tpu-accelerator: tpu-v6e-slice
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: ClusterQueue
metadata:
name: tpu-training-cq
spec:
resourceGroups:
- flavors:
- name: tpu-v6e-slice
resources:
- name: google.com/tpu
nominalQuota: 32
queueingStrategy: BestEffortFIFO
preemption:
reclaimWithinCohort: Never
reclaimOutOfCohort:
enable: true
reclaimMoreThanNominalQuota: false
---
apiVersion: kueue.x-k8s.io/v1beta1
kind: LocalQueue
metadata:
name: default-queue
namespace: default
spec:
clusterQueue: tpu-training-cq
---
apiVersion: jobset.x-k8s.io/v1alpha2
kind: JobSet
metadata:
name: low-jax-trillium
annotations:
kueue.x-k8s.io/queue-name: default-queue
alpha.jobset.sigs.k8s.io/exclusive-topology: cloud.google.com/gke-nodepool
spec:
failurePolicy:
maxRestarts: 10
restartStrategy: BlockingRecreate
replicatedJobs:
- name: slice
replicas: 2
template:
spec:
backoffLimit: 0
completions: 4
parallelism: 4
template:
metadata:
labels:
kueue.x-k8s.io/managed-by: kueue
kueue.x-k8s.io/priority-class: low-priority-job
spec:
nodeSelector:
cloud.google.com/gke-tpu-accelerator: tpu-v6e-slice
cloud.google.com/gke-tpu-topology: 4x4
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
priorityClassName: low-priority-job
containers:
- name: jax-program
image: <IMAGE LOCATION>
command:
- python3
- MaxText/train.py
- MaxText/configs/base.yml
- model_name=llama2-7b
- run_name=low-priority-run
- steps=30000
- base_output_directory=gs://<OUTPUT BUCKET>
- dataset_path=gs://max-datasets-rogue
- max_target_length=4096
- dataset_type=synthetic
- enable_checkpointing=False
resources:
limits:
google.com/tpu: 4
---
apiVersion: jobset.x-k8s.io/v1alpha2
kind: JobSet
metadata:
name: high-jax-trillium
annotations:
kueue.x-k8s.io/queue-name: default-queue
alpha.jobset.sigs.k8s.io/exclusive-topology: cloud.google.com/gke-nodepool
spec:
failurePolicy:
maxRestarts: 10
restartStrategy: BlockingRecreate
replicatedJobs:
- name: slice
replicas: 2
template:
spec:
backoffLimit: 0
completions: 4
parallelism: 4
template:
metadata:
labels:
kueue.x-k8s.io/managed-by: kueue
kueue.x-k8s.io/priority-class: high-priority-job
spec:
nodeSelector:
cloud.google.com/gke-tpu-accelerator: tpu-v6e-slice
cloud.google.com/gke-tpu-topology: 4x4
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
priorityClassName: high-priority-job
containers:
- name: jax-program
image: <IMAGE LOCATION>
command:
- python3
- MaxText/train.py
- MaxText/configs/base.yml
- model_name=llama2-7b
- run_name=high-priority-run
- steps=300
- base_output_directory=gs://<OUTPUT BUCKET>
- dataset_path=gs://max-datasets-rogue
- max_target_length=4096
- dataset_type=synthetic
- enable_checkpointing=False
resources:
limits:
google.com/tpu: 4
Com base nesta configuração, o Kueue é combinado com o Hotswap e realiza as seguintes ações:
- O Kueue gere a admissão de
low-jax-trilliumehigh-jax-trilliumJobSets na fila do cluster com base nas respetivas prioridades definidas e recursos disponíveis. - Se o
high-jax-trilliumJobSet for interrompido por uma falha de infraestrutura, o Hotswap antecipa olow-jax-trilliumJobSet para reagendar o JobSet de alta prioridade. - A troca a quente garante que o JobSet de alta prioridade é reiniciado rapidamente, minimizando o respetivo tempo de inatividade.
- Quando a infraestrutura é recuperada, a troca a quente reagenda o JobSet de baixa prioridade no conjunto de nós recuperado.
O que se segue?
- Saiba como implementar cargas de trabalho de GPU no GKE.
- Saiba como implementar cargas de trabalho de TPU no GKE.