Tous les produits
Search
Centre de documentation

Container Service for Kubernetes:Use the nearby memory access acceleration feature on multi-NUMA instances

Dernière mise à jour :Aug 11, 2026

Sur les instances multi-NUMA, les charges de travail colocalisées peuvent saturer la mémoire locale et repousser les pages mémoire d'une application vers des nœuds NUMA distants. L'accès entre nœuds via le bus QuickPath Interconnect (QPI) est plus lent que l'accès local, ce qui dégrade le débit et augmente la latence. La fonction d'accélération de l'accès mémoire local d'ack-koordinator détecte les pages mémoire distantes à l'exécution et les migre vers le nœud NUMA local sans interrompre les services en cours d'exécution.

Prérequis

Avant de commencer, vérifiez que vous disposez des éléments suivants :

  • Un cluster ACK Pro exécutant Kubernetes 1.18 ou une version ultérieure. Pour plus d'informations, consultez la rubrique Créer un cluster ACK managé.

  • Un client kubectl connecté au cluster. Pour plus d'informations, consultez la rubrique Obtenir le fichier kubeconfig d'un cluster et utiliser kubectl pour se connecter au cluster.

  • ack-koordinator (anciennement ack-slo-manager) version 1.2.0-ack1.2 ou ultérieure installée. Pour plus d'informations, consultez la rubrique ack-koordinator (anciennement ack-slo-manager).

    Remarque

    ack-koordinator inclut toutes les fonctionnalités de resource-controller. Si vous utilisez actuellement resource-controller, désinstallez-le avant d'installer ack-koordinator. Pour plus d'informations, consultez la rubrique Désinstaller resource-controller.

  • Des instances Elastic Compute Service (ECS) de 5e, 6e, 7e ou 8e génération appartenant aux familles d'instances ecs.ebmc, ecs.ebmg, ecs.ebmgn, ecs.ebmr, ecs.ebmhfc ou ecs.scc, déployées en tant qu'instances multi-NUMA.

    Remarque

    La fonction offre les meilleures performances sur les instances ECS de 8e génération des types ecs.ebmc8i.48xlarge, ecs.c8i.32xlarge et ecs.g8i.48xlarge. Pour plus d'informations, consultez la rubrique Familles d'instances ECS.

  • Des applications déployées sur des instances multi-NUMA avec des cœurs CPU liés à l'aide de la planification CPU consciente de la topologie. Pour plus d'informations, consultez la rubrique Activer la planification CPU consciente de la topologie.

Facturation

L'installation et l'utilisation d'ack-koordinator sont gratuites. Toutefois, les scénarios suivants peuvent engendrer des frais :

  • ack-koordinator est un composant non managé qui consomme des ressources des nœuds de calcul après l'installation. Vous pouvez spécifier la quantité de ressources demandée par chaque module lors de l'installation.

  • Par défaut, ack-koordinator expose les métriques de surveillance (telles que le profilage des ressources et les métriques de planification fine) sous forme de métriques Prometheus. Si vous activez les métriques Prometheus pour ack-koordinator et utilisez Managed Service for Prometheus, ces métriques sont comptabilisées comme des métriques personnalisées et des frais s'appliquent. Avant l'activation, lisez la rubrique Facturation relative à Managed Service for Prometheus pour comprendre le quota gratuit et les règles de facturation. Pour plus d'informations, consultez la rubrique Interroger la quantité de données observables et les factures.

Fonctionnement

Dans l'architecture multi-NUMA, les processus s'exécutant sur un vCore d'un nœud NUMA peuvent avoir besoin d'accéder à la mémoire d'un nœud NUMA distant. Cet accès entre nœuds transite par le bus QPI et prend plus de temps que l'accès à la mémoire locale. Sous de fortes charges mémoire, par exemple lorsque les charges de travail colocalisées sur le même nœud NUMA épuisent la mémoire locale, les pages mémoire d'une application peuvent être repoussées vers un nœud NUMA distant, réduisant ainsi le taux de succès des accès à la mémoire locale et dégradant les performances.

ack-koordinator remédie à cette dérive mémoire à l'exécution. Lorsque la localité mémoire est activée pour un pod, l'agent koordlet sur chaque nœud détecte quelles pages mémoire du pod résident sur des nœuds NUMA distants et les migre vers le nœud local. La migration est sûre et ne nécessite ni le redémarrage du pod ni l'interruption du trafic.

Des tests de référence effectués sur une instance ecs.ebmc8i.48xlarge exécutant Redis montrent qu'une mémoire entièrement locale offre un débit QPS supérieur de 10,52 % par rapport à une mémoire distribuée aléatoirement et un débit QPS supérieur de 26,12 % par rapport à une mémoire entièrement distante.

Important

Les chiffres de référence sont théoriques. Les résultats réels varient selon l'environnement.

QPS comparison

Cas d'utilisation

La fonction d'accélération de l'accès mémoire local convient aux scénarios suivants :

  • Charges de travail intensives en mémoire — bases de données en mémoire Redis à grande échelle et charges de travail similaires où la latence d'accès à la mémoire affecte directement le débit.

  • Instances ECS compatibles DSA — les instances ECS intégrées à Intel Data Streaming Accelerator (DSA) peuvent améliorer les performances de la fonction et réduire la consommation CPU.

Limites

  • La fonction est ignorée lorsque l'instance utilise une architecture non-NUMA ou lorsque le processus s'exécute sur tous les nœuds NUMA. Dans les deux cas, il n'y a pas de nœud NUMA distant à partir duquel migrer.

  • Si un processus se termine pendant la migration, la migration de ce processus échoue. ack-koordinator enregistre l'ID du processus ayant échoué dans l'événement du pod et continue de migrer les autres processus.

  • Lors de l'utilisation de l'accélération périodique (migrateIntervalMinutes > 0), un événement est enregistré uniquement lorsque la variation du ratio de mémoire locale ou le résultat de l'accélération dépasse 10 %.

Activer l'accélération de l'accès mémoire local

Étape 1 : Activer la fonction

Deux méthodes sont disponibles. Utilisez la méthode d'annotation pour cibler des pods individuels, ou utilisez la méthode ConfigMap pour appliquer le paramètre à tous les pods d'une classe de qualité de service (QoS) donnée.

Activer pour un pod individuel

Exécutez la commande suivante pour activer l'accélération de l'accès mémoire local pour un pod :

kubectl annotate pod <pod-name> koordinator.sh/memoryLocality='{"policy": "bestEffort"}' --overwrite

Le paramètre policy accepte les valeurs suivantes :

Valeur Comportement
bestEffort Déclenche une migration immédiate des pages mémoire des nœuds NUMA distants vers le nœud NUMA local
none Désactive l'accélération de l'accès mémoire local

Activer pour tous les pods d'une classe QoS

  1. Créez un fichier nommé ml-config.yaml avec le contenu suivant :

    apiVersion: v1
    data:
      resource-qos-config: |-
        {
          "clusterStrategy": {
            "lsClass": {
               "memoryLocality": {
                 "policy": "bestEffort"
               }
             }
          }
        }
    kind: ConfigMap
    metadata:
      name: ack-slo-config
      namespace: kube-system
  2. Vérifiez si la ConfigMap ack-slo-config existe déjà dans le namespace kube-system :

    kubectl get cm ack-slo-config -n kube-system
    • Si la ConfigMap n'existe pas, créez-la :

      kubectl apply -f ml-config.yaml
    • Si la ConfigMap existe déjà, appliquez un patch pour éviter d'écraser les paramètres QoS existants :

      kubectl patch cm -n kube-system ack-slo-config --patch "$(cat ml-config.yaml)"

Étape 2 : Vérifier la fonction

Exécutez la commande suivante pour vérifier les événements du pod :

kubectl describe pod <pod-name>

Le tableau suivant décrit les types d'événements attendus et leur signification :

Type d'événement Exemple de message Signification
MemoryLocalityCompleted Container <name> completed: migrated memory from remote numa: 1 to local numa: 0 ... Total: 2 container(s) completed, 0 failed, 0 skipped; cur local memory ratio 100, rest remote memory pages 0 La migration a réussi. L'événement enregistre la direction de la migration pour chaque conteneur et le ratio de mémoire locale résultant.
MemoryLocalityCompleted (avec échecs) failed to migrate the following processes: failed pid: 111111, error: No such process, from remote numa: 0 to local numa: 1 Un ou plusieurs processus se sont terminés pendant la migration. L'événement enregistre le PID de chaque processus ayant échoué. Les autres conteneurs ont été migrés avec succès.
MemoryLocalitySkipped no target numa Aucun nœud NUMA distant n'a été trouvé. Cela se produit sur les instances non-NUMA ou lorsque le processus s'exécute sur tous les nœuds NUMA. Aucune action n'est requise.
MemoryLocalityFailed Le message d'erreur varie Une erreur inattendue s'est produite. Consultez le message d'erreur pour plus de détails.

Étape 3 (Facultative) : Configurer l'accélération périodique

Par défaut, l'annotation déclenche une seule migration. Pour exécuter des migrations de manière répétée selon une planification, ajoutez le paramètre migrateIntervalMinutes.

Remarque

Avant de définir un intervalle récurrent, assurez-vous que la migration la plus récente est terminée. Un événement est enregistré uniquement lorsque le ratio de mémoire locale ou le résultat de l'accélération change de plus de 10 %.

kubectl annotate pod <pod-name> koordinator.sh/memoryLocality='{"policy": "bestEffort","migrateIntervalMinutes":10}' --overwrite

Le paramètre migrateIntervalMinutes spécifie l'intervalle minimum entre les migrations, en minutes :

Valeur Comportement
0 Déclenche une seule migration immédiate (identique à l'omission du paramètre)
> 0 Déclenche une migration immédiate, puis répète l'opération à l'intervalle spécifié
none Désactive la fonction d'accélération de l'accès mémoire local

Test de référence : impact sur les performances de Redis

Cette section décrit les résultats des tests de référence pour les types d'instances ecs.ebmc8i.48xlarge et ecs.ebmg7a.64xlarge.

Important

Les résultats dépendent de l'outil de test de charge et de l'environnement. Les résultats suivants sont spécifiques à ces deux types d'instances.

Environnement de test

  • Machines testées : instances ecs.ebmc8i.48xlarge et ecs.ebmg7a.64xlarge exécutant une application Redis

  • Application Redis : multithread, 4 vCores, 32 Go de mémoire (image : redis:6.0.5)

  • Machine de test de charge : une machine distincte qui envoie des requêtes à la machine testée

    Remarque

    Pour les machines de test aux spécifications inférieures, déployez une instance Redis monothread et réduisez les demandes de CPU et de mémoire en conséquence.

Procédure de test

Test procedure

  1. Déployez une application Redis à l'aide du YAML suivant. Ajustez redis-config pour correspondre aux spécifications de votre machine de test.

    ---
    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: example-redis-config
    data:
      redis-config: |
        maxmemory 32G
        maxmemory-policy allkeys-lru
        io-threads-do-reads yes
        io-threads 4
    ---
    kind: Service
    apiVersion: v1
    metadata:
      name: redis
    spec:
      type: NodePort
      ports:
        - port: 6379
          targetPort: 6379
          nodePort: 32379
      selector:
        app: redis
    ---
    apiVersion: v1
    kind: Pod
    metadata:
      name: redis
      annotations:
        cpuset-scheduler: "true"        # Bind vCores using topology-aware CPU scheduling
      labels:
        app: redis
    spec:
      containers:
      - name: redis
        image: redis:6.0.5
        command: ["bash", "-c", "redis-server /redis-master/redis.conf"]
        ports:
        - containerPort: 6379
        resources:
          limits:
            cpu: "4"                    # Adjust based on test machine specifications
        volumeMounts:
        - mountPath: /redis-master-data
          name: data
        - mountPath: /redis-master
          name: config
      volumes:
        - name: data
          emptyDir: {}
        - name: config
          configMap:
            name: example-redis-config
            items:
            - key: redis-config
              path: redis.conf
  2. Augmentez les charges mémoire pour simuler la dérive mémoire vers les NUMA distants.

    1. Écrivez des données métier dans Redis à l'aide du script shell suivant. Le script écrit les données par lots via des pipelines. Remplacez <max-out-cir> et <max-in-cir> par les valeurs appropriées pour votre configuration. Pour une instance Redis de 4 vCores et 32 Go, utilisez max-out-cir=300 et max-in-cir=1000000.

      Remarque

      L'écriture de grands volumes de données prend du temps. Exécutez le script sur la machine testée pour maximiser la vitesse d'écriture.

      for((j=1;j<=<max-out-cir>;j++))
      do
              echo "set k$j-0 v$j-0" > data.txt
              for((i=1;i<=<max-in-cir>;i++))
              do
                      echo "set k$j-$i v$j-$i" >> data.txt
              done
              echo "$j"
              unix2dos data.txt  # Pipeline writes require DOS format
              cat data.txt | redis-cli --pipe -h <redis-server-IP> -p <redis-server-port>
      done

      Pendant l'écriture des données, augmentez les charges mémoire des charges de travail colocalisées sur le même nœud NUMA pour simuler la dérive mémoire. Utilisez numactl --membind pour lier les charges de travail à un nœud NUMA spécifique.

    2. Exécutez la commande suivante pour augmenter la pression mémoire. Remplacez <workers-num> par le nombre de processus de stress et <malloc-size-per-workers> par la mémoire allouée par processus.

      Remarque

      Étant donné que les vCores sont liés au pod Redis, la mémoire NUMA locale lui est attribuée en priorité jusqu'à ce que la mémoire locale soit épuisée et que le débordement se produise vers les nœuds NUMA distants. Exécutez numactl -H pour vérifier l'utilisation de la mémoire par nœud NUMA et définissez les paramètres en conséquence.

      numactl --membind=<numa-id> stress -m <workers-num> --vm-bytes <malloc-size-per-workers>
  3. Exécutez des tests de charge avec l'accélération désactivée puis activée.

    1. Test de charge avec accélération désactivée

      Envoyez des requêtes depuis la machine de test de charge pour générer des charges moyennes et élevées sur redis-server.

      • 500 requêtes concurrentes (charge moyenne) :

        redis-benchmark -t GET -c 500 -d 4096 -n 2000000 -h <redis-server-IP> -p <redis-server-port>
      • 10 000 requêtes concurrentes (charge élevée) :

        redis-benchmark -t GET -c 10000 -d 4096 -n 2000000 -h <redis-server-IP> -p <redis-server-port>
    2. Activer l'accélération de l'accès mémoire local

      Exécutez la commande suivante pour activer l'accélération pour le pod Redis :

      kubectl annotate pod redis koordinator.sh/memoryLocality='{"policy": "BestEffort"}' --overwrite

      Vérifiez que la migration est terminée :

      kubectl describe pod redis

      Sortie attendue (le transfert de grands volumes de mémoire distante peut prendre du temps) :

        Normal  MemoryLocalitySuccess  0s   koordlet-resmanager  migrated memory from remote numa: 0 to local numa: 1, cur local memory ratio 98, rest remote memory pages 28586
    3. Test de charge avec accélération activée

      Répétez les tests de charge de l'étape a pour générer des charges moyennes et élevées.

Résultats pour ecs.ebmc8i.48xlarge

Distribution de la mémoire : 43 % locale avant l'accélération, 98 % locale après l'accélération.

Memory distribution comparison (ecs.ebmc8i.48xlarge)

  • 500 requêtes concurrentes

    |
    **Scénario**
    |
    **P99 ms**
    |
    **P99,99 ms**
    |
    **QPS**
    | | --- | --- | --- | --- | |
    Avant l'accélération
    |
    3
    |
    9,6
    |
    122 139,91
    | |
    Après l'accélération
    |
    3
    |
    8,2
    |
    129 367,11
    |

    La latence P99 reste inchangée. La latence P99,99 est réduite de 14,58 %. Le débit QPS augmente de 5,917 %.

























  • 10 000 requêtes concurrentes

    |
    **Scénario**
    |
    **P99 ms**
    |
    **P99,99 ms**
    |
    **QPS**
    | | --- | --- | --- | --- | |
    Avant l'accélération
    |
    115
    |
    152,6
    |
    119 895,56
    | |
    Après l'accélération
    |
    101
    |
    145,2
    |
    125 401,44
    |

    La latence P99 est réduite de 12,17 %. La latence P99,99 est réduite de 4,85 %. Le débit QPS augmente de 4,59 %.

























Résultats pour ecs.ebmg7a.64xlarge

Distribution de la mémoire : 47 % locale avant l'accélération, 88 % locale après l'accélération.

Memory distribution comparison (ecs.ebmg7a.64xlarge)

  • 500 requêtes concurrentes

    |
    **Scénario**
    |
    **P99 ms**
    |
    **P99,99 ms**
    |
    **QPS**
    | | --- | --- | --- | --- | |
    Avant l'accélération
    |
    2,4
    |
    4,4
    |
    135 180,99
    | |
    Après l'accélération
    |
    2,2
    |
    4,4
    |
    136 296,37
    |

    La latence P99 est réduite de 8,33 %. La latence P99,99 reste inchangée. Le débit QPS augmente de 0,83 %.

























  • 10 000 requêtes concurrentes

    |
    **Scénario**
    |
    **P99 ms**
    |
    **P99,99 ms**
    |
    **QPS**
    | | --- | --- | --- | --- | |
    Avant l'accélération
    |
    58,2
    |
    80,4
    |
    95 757,10
    | |
    Après l'accélération
    |
    56,6
    |
    76,8
    |
    97 015,50
    |

    La latence P99 est réduite de 2,7 %. La latence P99,99 est réduite de 4,4 %. Le débit QPS augmente de 1,3 %.

























Conclusion : Sous de fortes charges mémoire où les données de l'application ont dérivé vers des nœuds NUMA distants, la liaison des vCores et l'activation de l'accélération de l'accès mémoire local réduisent la latence d'accès et augmentent le débit de Redis, tant pour une concurrence moyenne que élevée.