Cuando varias aplicaciones se ejecutan en el mismo nodo, la contención de recursos de CPU y los cambios de contexto degradan las cargas de trabajo sensibles a la latencia. La programación de CPU con detección de topología fija los procesos de la aplicación a núcleos de CPU específicos. Esto elimina las variaciones de rendimiento provocadas por la migración entre núcleos y el acceso a memoria entre nodos NUMA (Non-Uniform Memory Access).
Cómo funciona
De forma predeterminada, Kubernetes utiliza el Completely Fair Scheduler (CFS) del kernel para distribuir los intervalos de tiempo de CPU entre todos los núcleos. El CFS ignora la topología física de la CPU y puede generar una latencia impredecible en aplicaciones sensibles al rendimiento.
El CPU Manager de Kubernetes (con la directiva static) permite vincular pods a núcleos de CPU exclusivos, pero presenta tres limitaciones:
Falta de detección de topología a nivel de clúster: el kube-scheduler nativo opera únicamente a nivel de nodo y no tiene visibilidad de la topología de CPU de todo el clúster.
Falta de compatibilidad con NUMA: la directiva
staticno considera la arquitectura NUMA al asignar núcleos. Esto puede forzar el acceso a memoria entre nodos NUMA e introducir latencia adicional.Guaranteed QoS only: esta directiva aplica únicamente a pods con la clase de QoS
Guaranteed. No es compatible con podsBurstableniBestEffort.
ACK resuelve estas limitaciones mediante la colaboración entre el kube-scheduler de ACK y ack-koordinator, basados en el Scheduling Framework de Kubernetes:
Reporte de topología del nodo: ack-koordinator detecta continuamente la topología física local de la CPU (sockets, nodos NUMA y cachés) y envía estos datos al centro de programación.
Programación global con detección de topología: el kube-scheduler usa los datos de topología de todo el clúster para seleccionar el nodo óptimo de cada pod y planificar la asignación de núcleos. De forma predeterminada, el programador busca el núcleo con menos aplicaciones vinculadas. El esquema de asignación resultante se escribe en la anotación del pod.
Fijación local de núcleos: cuando el pod llega al nodo de destino, ack-koordinator lee su anotación y modifica el archivo
cpuset.cpusen el cgroup del pod. Así vincula el pod a los núcleos físicos asignados.
Casos de uso
La programación de CPU con detección de topología ofrece mejores resultados en las siguientes cargas de trabajo:
Aplicaciones sensibles a la latencia: los sistemas de negociación de alta frecuencia y los pipelines de procesamiento de datos en tiempo real no toleran retrasos por cambios de contexto de CPU. Sin la fijación de CPU, el programador CFS puede migrar el proceso entre núcleos durante la ejecución. Esto resulta inofensivo en un entorno de pruebas, pero genera un impacto medible en producción bajo carga.
Aplicaciones sensibles a NUMA: las cargas de trabajo en servidores multisocket (como las instancias Elastic Bare Metal de AMD o Intel) presentan una latencia notable cuando los accesos a memoria cruzan límites NUMA. Fijar los núcleos dentro de un solo nodo NUMA elimina esta sobrecarga.
Cómputo determinista: los trabajos de cómputo científico y análisis de big data requieren un throughput de CPU estable y predecible. La fijación elimina la variabilidad que introduce compartir núcleos con otras cargas de trabajo.
Aplicaciones heredadas que ignoran los límites de CPU del contenedor: algunas aplicaciones generan hilos según el número total de núcleos físicos del host, en lugar del límite de CPU del contenedor. Estas aplicaciones se benefician de la fijación, ya que vincula el proceso a un conjunto específico de núcleos.
No habilite la programación de CPU con detección de topología en los siguientes escenarios:
Entornos con sobreasignación de CPU: la fijación de núcleos los reserva de manera exclusiva. Esto es incompatible con el modelo de recursos compartidos de la sobreasignación y provoca desperdicio de recursos.
Aplicaciones de uso general o intensivas en E/S: los servicios web, el middleware y la mayoría de las cargas de trabajo limitadas por E/S no son sensibles al cambio de núcleos de CPU, por lo que no obtienen ninguna ventaja con la fijación.
Elegir una directiva de fijación
ACK proporciona dos directivas de fijación:
|
Directiva |
Anotación |
Comportamiento de fijación |
Recomendada para |
|
General |
|
Fijación 1:1: vincula exactamente la cantidad de núcleos indicada en |
La mayoría de las cargas de trabajo sensibles a la latencia |
|
Automática |
|
Analiza la topología y el uso de recursos en tiempo real. Puede fijar más núcleos de los solicitados y prioriza un clúster completo de núcleos físicos (CCX/CCD en CPU AMD) |
Máquinas AMD de gran escala con 32 núcleos o más |
Requisitos previos
Antes de empezar, asegúrese de contar con lo siguiente:
Un clúster administrado de ACK de edición Pro
Un node pool con
cpuManagerPolicyestablecido ennone. Para obtener más información, consulte Customize kubelet configurations for a node poolack-koordinator instalado en la versión 0.2.0 o posterior. Para consultar las instrucciones de instalación, consulte ack-koordinator
Paso 2: Habilitar la programación de CPU con detección de topología
Habilite la programación de CPU con detección de topología mediante la adición de anotaciones a la especificación del pod.
No especifique nodeName directamente en un pod cuando use esta función. El kube-scheduler no participa en la programación de pods con nodeName configurado, por lo que la selección de núcleos con detección de topología no se aplica. Utilice nodeSelector o afinidad de nodo en su lugar.
Directiva de fijación general
La directiva de fijación general vincula al pod exactamente la cantidad de núcleos especificada en resources.limits.cpu y prioriza los núcleos del mismo nodo NUMA.
Configuración:
Para un pod: agregue
cpuset-scheduler: "true"enmetadata.annotations.Para una carga de trabajo como un Deployment: agregue
cpuset-scheduler: "true"enspec.template.metadata.annotations.resources.limits.cpudebe ser un número entero.
Ejemplo:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
annotations:
cpuset-scheduler: "true" # Enables CPU topology-aware scheduling
labels:
app: nginx
spec:
containers:
- name: nginx
image: alibaba-cloud-linux-3-registry.cn-hangzhou.cr.aliyuncs.com/alinux3/nginx_optimized:20240221-1.20.1-2.3.0
ports:
- containerPort: 80
command:
- "sleep"
- "infinity"
resources:
requests:
cpu: 4
memory: 8Gi
limits:
cpu: 4 # Must be an integer
memory: 8Gi
Comprobar la fijación:
Una vez que el pod esté en ejecución, compruebe que la fijación de núcleos está activa con uno de los siguientes métodos.
-
Verificación:
Puede consultarla de dos maneras.
Consultar el archivo de cgroup del nodo
Consulte el archivo de cgroup en el nodo: el resultado muestra un conjunto de ID de núcleo que coincide con
limits.cpu: 4, lo cual confirma que la fijación está activa:cgroup v1: ``
shell # Replace <POD_UID> and <CONTAINER_ID> with the actual values cat /sys/fs/cgroup/cpuset/kubepods.slice/kubepods-pod<POD_UID>.slice/cri-containerd-<CONTAINER_ID>.scope/cpuset.cpus``cgroup v2: ``
shell # Replace <POD_UID> and <CONTAINER_ID> with the actual values cat /sys/fs/cgroup/kubepods.slice/kubepods-pod<POD_UID>.slice/cri-containerd-<CONTAINER_ID>.scope/cpuset.cpus.effective``
0-3Consultar la anotación del pod
Consulte la anotación del pod:
"nginx": el contenedor llamadonginx."0": el ID del nodo NUMA. Todos los núcleos fijados están en el nodo NUMA 0, lo que evita la pérdida de rendimiento por accesos a memoria entre nodos NUMA."elems": {"0":{},"1":{},"2":{},"3":{}}: los ID de los núcleos físicos de CPU a los que se fijó el contenedor (núcleos 0 a 3), que coinciden conlimits.cpu: 4.
# Replace <your-pod-name> with the actual pod name kubectl get pod <your-pod-name> -n default -o yaml | grep "cpuset:"Resultado esperado:
cpuset: '{"nginx":{"0":{"elems":{"0":{},"1":{},"2":{},"3":{}}}}}'Significado de los campos del resultado:
Directiva de fijación automática
La directiva de fijación automática está optimizada para hardware específico. Analiza la topología de CPU y el uso de recursos del nodo en tiempo real, y prioriza vincular al pod un clúster completo de núcleos físicos (como un CCX o CCD en CPU AMD). La cantidad de núcleos fijados puede superar la solicitada para maximizar la localidad de CPU y la concurrencia.
Utilice esta directiva en tipos de máquinas AMD de gran escala con 32 núcleos o más.
Configuración:
-
Agregue dos anotaciones:
cpuset-scheduler: "true"ycpu-policy: "static-burst".Para un pod: agréguelas en
metadata.annotations.Para una carga de trabajo como un Deployment: agréguelas en
spec.template.metadata.annotations.
resources.limits.cpudebe ser un número entero.
Ejemplo:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: default
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
annotations:
cpuset-scheduler: "true" # Enables CPU topology-aware scheduling
cpu-policy: "static-burst" # Enables automatic pinning and NUMA affinity
labels:
app: nginx
spec:
containers:
- name: nginx
image: alibaba-cloud-linux-3-registry.cn-hangzhou.cr.aliyuncs.com/alinux3/nginx_optimized:20240221-1.20.1-2.3.0
ports:
- containerPort: 80
command:
- "sleep"
- "infinity"
resources:
requests:
cpu: 4
memory: 8Gi
limits:
cpu: 4 # Must be an integer
memory: 8Gi
Comprobar la fijación:
La directiva automática puede fijar más núcleos de los solicitados. Compruebe el resultado con uno de los siguientes métodos.
-
Verificación:
La directiva de fijación automática analiza la topología de CPU y el uso de recursos del nodo en tiempo real. La cantidad de núcleos fijados puede ser mayor que la solicitada explícitamente para el pod. Puede comprobar el estado de fijación de dos maneras.
Consultar el archivo de cgroup del nodo
Consulte el archivo de cgroup en el nodo: el resultado muestra los núcleos fijados específicos (más de los 4 solicitados en este ejemplo), lo cual confirma que la fijación está activa:
cgroup v1: ``
shell # Replace <POD_UID> and <CONTAINER_ID> with the actual values cat /sys/fs/cgroup/cpuset/kubepods.slice/kubepods-pod<POD_UID>.slice/cri-containerd-<CONTAINER_ID>.scope/cpuset.cpus``cgroup v2: ``
shell # Replace <POD_UID> and <CONTAINER_ID> with the actual values cat /sys/fs/cgroup/kubepods.slice/kubepods-pod<POD_UID>.slice/cri-containerd-<CONTAINER_ID>.scope/cpuset.cpus.effective``
0-7Consultar la anotación del pod
Consulte la anotación del pod:
"nginx": el contenedor llamadonginx."0": el ID del nodo NUMA. Todos los núcleos fijados están en el nodo NUMA 0, lo que evita los accesos a memoria entre nodos NUMA."elems": los ID de los núcleos físicos a los que se fijó el contenedor (núcleos 0 a 7). La directiva automática puede fijar más núcleos de los solicitados para alinearse con el límite del clúster de núcleos físicos.
# Replace <your-pod-name> with the actual pod name kubectl get pod <your-pod-name> -n default -o yaml | grep "cpuset:"Resultado esperado:
cpuset: '{"nginx":{"0":{"elems":{"0":{},"1":{},"2":{},"3":{},"4":{},"5":{},"6":{},"7":{}}}}}'Significado de los campos del resultado:
Aplicar en producción
Observability
Integre el clúster con Alibaba Cloud Prometheus monitoring antes y después de habilitar la fijación de núcleos. Supervise las siguientes métricas para observar el efecto de la fijación en sus cargas de trabajo:
Métricas de la aplicación: tiempo de respuesta (RT) y QPS
Métricas del nodo: uso de CPU y estrangulamiento de CPU
Despliegue gradual
En Deployments con varias réplicas, utilice versiones canary o actualizaciones graduales para habilitar o deshabilitar la directiva de fijación de forma progresiva. Esto reduce el riesgo de una regresión generalizada del rendimiento.
Deshabilitar la programación de CPU con detección de topología
Edite el archivo YAML de la aplicación. Elimine la anotación
cpuset-scheduler: "true"y, si existe, la anotacióncpu-policy: "static-burst"despec.template.metadata.annotations.Aplique el archivo YAML modificado fuera del horario de mayor actividad. Los cambios surten efecto después de reiniciar el pod.
Al deshabilitar la fijación de CPU, los procesos del pod dejan de estar vinculados a núcleos físicos específicos y pueden ejecutarse en cualquier núcleo disponible del nodo. Tenga en cuenta los siguientes impactos potenciales:
El uso de CPU puede aumentar ligeramente debido a los cambios de contexto entre núcleos.
En aplicaciones intensivas en cómputo, pueden reaparecer las variaciones de rendimiento causadas por la contención de recursos de CPU.
Si varios pods con alta carga comparten el mismo núcleo, se pueden generar picos de carga que activen el estrangulamiento de CPU.
Facturación
La instalación y el uso de ack-koordinator son gratuitos. Pueden aplicarse cargos adicionales en los siguientes casos:
ack-koordinator es un componente no administrado que consume recursos de los nodos worker después de la instalación. Configure las solicitudes de recursos de cada módulo durante la instalación.
Si selecciona la opción Enable Prometheus monitoring for ACK-Koordinator y utiliza Alibaba Cloud Prometheus, las métricas de monitoreo se contabilizan como métricas personalizadas y generan cargos. El costo depende del tamaño del clúster y de la cantidad de aplicaciones. Antes de habilitar esta opción, revise la información de facturación de Prometheus para conocer la cuota gratuita y los precios. Haga un seguimiento de su consumo mediante la consulta de sus datos de uso.
Pasos siguientes
GPU topology-aware scheduling: seleccione la combinación óptima de GPU en un nodo para maximizar la velocidad de entrenamiento.
Dynamic resource overcommitment: recupere los recursos del clúster asignados pero no utilizados y asígnelos a trabajos de baja prioridad.