הגדרת מכונות וירטואליות עם מודעות ל-NUMA

במאמר הזה מוסבר איך להגדיר אשכולות ומכונות וירטואליות כדי לתמוך בעומסי עבודה עם ביצועים גבוהים וזמן אחזור נמוך, באמצעות יעילות החישוב של גישה לזיכרון לא אחיד (NUMA). יש הוראות להתאמת הגדרות Kubernetes לצמתים באשכול. במסמך הזה יש גם הוראות להגדרת מכונות וירטואליות (VM) עם זיקה ל-NUMA, כדי שהן יתוזמנו וינצלו את צמתי ה-NUMA.

ב-VM עם מודעות ל-NUMA, כל התקשורת בתוך ה-VM היא מקומית לצומת NUMA. מכונה וירטואלית עם מודעות ל-NUMA נמנעת מעסקאות נתונים אל משאבים מרוחקים וממשאבים מרוחקים, שיכולות לפגוע בביצועים של המכונה הווירטואלית.

הגדרת צמתים לשימוש ב-NUMA

בקטעים הבאים מוסבר איך להגדיר את רכיבי Kubernetes הקריטיים כדי לכוון את הצומת ולוודא שאפשר לתזמן קונטיינרים שמודעים ל-NUMA. הצמתים האלה של NUMA מותאמים כדי לשפר את הביצועים של המעבד והזיכרון. פועלים לפי ההוראות לכל צומת שרוצים להריץ בו מכונות וירטואליות עם מודעות ל-NUMA.

עדכון ההגדרה של kubelet

כחלק מהגדרת הצומת לתמיכה בהצמדה של צומת NUMA, צריך לבצע את השינויים הבאים בהגדרת ה-kubelet:

  • הפעלת CPU Manager עם מדיניות static
  • הפעלת מנהל הזיכרון באמצעות מדיניות Static
  • הפעלת הכלי לניהול טופולוגיה עם restricted טופולוגיה

כדי להגדיר את kubelet בצומת העובד:

  1. מאתרים את קובץ kubelet בצומת העובד ופותחים אותו לעריכה:

    edit /etc/default/kubelet
    

    אם הקובץ kubelet לא מופיע, יוצרים אותו באמצעות הפקודה הבאה:

    echo "KUBELET_EXTRA_ARGS=\"\"" >> /etc/default/kubelet
    

    הפקודה הזו יוצרת את הקובץ kubelet עם קטע KUBELET_EXTRA_ARGS="" ריק.

  2. כדי להפעיל את CPU Manager עם מדיניות static, מוסיפים את הדגל --cpu-manager-policy=static לקטע KUBELET_EXTRA_ARGS="" בקובץ:

    KUBELET_EXTRA_ARGS="--cpu-manager-policy=static"
    
  3. כדי להפעיל את הכלי לניהול זיכרון באמצעות מדיניות Static, מוסיפים את הדגל --memory-manager-policy=Static לקטע KUBELET_EXTRA_ARGS="" בקובץ:

    KUBELET_EXTRA_ARGS="--cpu-manager-policy=static --memory-manager-policy=Static"
    
  4. כדי להפעיל את Topology Manager עם מדיניות restricted, מוסיפים את הדגל --topology-manager-policy=restricted לקטע KUBELET_EXTRA_ARGS="" בקובץ:

    KUBELET_EXTRA_ARGS="--cpu-manager-policy=static --memory-manager-policy=Static --topology-manager-policy=restricted"
    
  5. בודקים את כמות הזיכרון הנוכחית שהוקצתה על ידי Google Distributed Cloud:

    cat /var/lib/kubelet/kubeadm-flags.env
    

    הפלט אמור להיראות כך:

    KUBELET_KUBEADM_ARGS="--anonymous-auth=false --authentication-token-webhook=true --authorization-mode=Webhook --container-runtime=remote --container-runtime-endpoint=unix:///run/containerd/containerd.sock --feature-gates=SeccompDefault=true --kube-reserved=cpu=100m,memory=3470Mi --max-pods=110 --node-ip=192.168.1.190 --node-labels=baremetal.cluster.gke.io/k8s-ip=192.168.1.190,baremetal.cluster.gke.io/namespace=cluster-user001,baremetal.cluster.gke.io/node-pool=node-pool-1,cloud.google.com/gke-nodepool=node-pool-1 --pod-infra-container-image=gcr.io/anthos-baremetal-release/pause-amd64:3.1-gke.5 --provider-id=baremetal://192.168.1.190 --read-only-port=10255 --rotate-server-certificates=true --seccomp-default=true"

    ההגדרה --kube-reserved=cpu=100m,memory=3470Mi מציינת ש-Google Distributed Cloud שמר 3,470 מביבייט של זיכרון בצומת.

  6. מגדירים את הדגל --reserved-memory בקטע KUBELET_EXTRA_ARGS בקובץ kubelet ל-100 מביבייט יותר מהזיכרון השמור הנוכחי, כדי להתחשב בסף ההוצאה מהמטמון. אם אין זיכרון שמור, אפשר לדלג על השלב הזה.

    לדוגמה, אם הזיכרון השמור הוא 3470Mi מהדוגמה בשלב הקודם, שומרים 3570Mi זיכרון בקובץ kubelet:

    KUBELET_EXTRA_ARGS="--cpu-manager-policy=static --memory-manager-policy=Static --topology-manager-policy=restricted --reserved-memory=0:memory=3570Mi"
    
  7. מסירים את קובצי המצב של ה-CPU והזיכרון מהספרייה /var/lib:

    rm /var/lib/cpu_manager_state
    rm /var/lib/memory_manager_state
    
  8. מפעילים מחדש את kubelet:

    systemctl start kubelet
    

מידע נוסף על הגדרות המדיניות האלה זמין במסמכי Kubernetes הבאים:

הגדרת הצומת לשימוש ב-hugepages

אחרי שמפעילים את Memory Manager עם מדיניות Static, אפשר להוסיף hugepages כדי לשפר עוד יותר את הביצועים של עומסי העבודה של הקונטיינרים בצמתי ה-NUMA. כמו שאפשר להבין מהשם, hugepages מאפשר לכם לציין דפי זיכרון גדולים יותר מהגודל הרגיל של 4 קיביבייט (KiB). ‫VM Runtime ב-GDC תומך בדפי זיכרון גדולים של 2 מביבייט (MiB) ו-1 גיביבייט (GiB). אפשר להגדיר hugepages לצומת בזמן הריצה או בזמן האתחול של מכונת הצומת. מומלץ להגדיר hugepages בכל צומת שרוצים להריץ בו מכונות וירטואליות עם מודעות ל-NUMA.

  1. כדי להגדיר את מספר דפי הזיכרון הגדולים בגודל מסוים בצומת NUMA בזמן הריצה, משתמשים בפקודה הבאה:

    echo HUGEPAGE_QTY > \
        /sys/devices/system/node/NUMA_NODE/hugepages/hugepages-HUGEPAGE_SIZEkB/nr_hugepages
    

    מחליפים את מה שכתוב בשדות הבאים:

    • HUGEPAGE_QTY: מספר דפי הזיכרון הענקיים להקצאה בגודל שצוין.

    • NUMA_NODE: צומת ה-NUMA, כמו node0, שאליו מקצים את דפי הזיכרון הגדולים.

    • HUGEPAGE_SIZE: הגודל של דפי הזיכרון הגדולים ב-kibibytes, ‏ 2048 (2 MiB) או 1048576 (1 GiB).

הגדרת מכונה וירטואלית לשימוש בצומת NUMA

אחרי שמכווננים את צמתי האשכול ל-NUMA, אפשר ליצור מכונות וירטואליות עם תמיכה ב-NUMA. מכונות וירטואליות עם מודעות ל-NUMA מתוזמנות בצמתי NUMA.

כדי ליצור מכונה וירטואלית עם מודעות ל-NUMA:

  1. פועלים לפי ההוראות ליצירת מכונה וירטואלית ממניפסט.

    כדי להגדיר את מכונת ה-VM כך שתהיה מודעת ל-NUMA, משתמשים בהגדרות הבאות של compute:

    • spec.compute.guaranteed: הגדרת guaranteed לערך true. בהגדרה הזו, ה-Pod של virt-launcher מוגדר להצבה ב-Kubernetes Guaranteed Quality of Service (QoS) class.

    • spec.compute.advancedCompute:

      • dedicatedCPUPlacement: הגדרת dedicatedCPUPlacement לערך true. ההגדרה הזו מצמידה מעבדים וירטואליים למעבדים הפיזיים של הצומת.
      • hugePageSize: מגדירים את hugePageSize ל-2Mi או ל-1Gi כדי לציין את גודל ה-hugepages שבו ה-VM ישתמש, 2 מביבייט או 1 גיביבייט.
      • numaGuestMappingPassthrough: כוללים מבנה ריק ({}) להגדרה הזו. ההגדרה הזו קובעת זיקה ל-NUMA, כך שהמכונה הווירטואלית מתוזמנת רק בצמתי NUMA.

    בדוגמה הבאה של מניפסט VirtualMachine אפשר לראות איך יכולה להיראות הגדרה של מכונה וירטואלית עם מודעות ל-NUMA:

    apiVersion: vm.cluster.gke.io/v1
    kind: VirtualMachine
    metadata:
      name: vm1
    spec:
      compute:
        cpu:
          vcpus: 2
        guaranteed: true
        advancedCompute:
          dedicatedCPUPlacement: true
          hugePageSize: 2Mi
          numaGuestMappingPassthrough: {}
        memory:
          capacity: 256Mi
      interfaces:
      - name: eth0
        networkName: pod-network
        default: true
      disks:
      - virtualMachineDiskName: disk-from-gcs
        boot: true
        readOnly: true