תזמור עומסי עבודה של Multislice באמצעות JobSet ו-Kueue

במדריך הזה נסביר איך לתזמן כמה עומסי עבודה של multislice ב-Google Kubernetes Engine ‏ (GKE) כדי לשפר את ניצול המשאבים. לדוגמה, אתם יכולים לפרוס עומס עבודה של Jax, להריץ אותו ב-TPU Multislice ולהטמיע תור של משימות באמצעות JobSet ו-Kueue. מערכת Kueue קובעת מתי עבודות צריכות לפעול על סמך משאבים זמינים, מכסות והיררכיה לחלוקה הוגנת בין צוותים.

המדריך הזה מיועד למהנדסי למידת מכונה (ML) ולאדמינים ולמפעילים של פלטפורמות שמתעניינים ביכולות של Kubernetes לניהול קונטיינרים לצורך אימון של מודלים גדולים של שפה (LLM). מידע נוסף על תפקידים נפוצים ומשימות לדוגמה שאנחנו מתייחסים אליהם בתוכן זמין במאמר תפקידים נפוצים של משתמשים ומשימות ב-GKE. Google Cloud

לפני שקוראים את הדף הזה, חשוב לוודא שמכירים את הנושאים הבאים:

מטרות

  1. מכינים את הסביבה עם אשכול GKE עם שלושה חלקי TPU v5e. לכל פרוסת TPU יש 2x4טופולוגיה עם 8 שבבים. לכן, סך הכול 24 שבבי TPU v5e TPU.
  2. יוצרים את משאבי Kueue כדי לוודא שהמכסות משותפות באופן הוגן בין עומסי העבודה.
  3. מריצים את עומס העבודה (workload) של Multislice.

לפני שמתחילים

לפני שמתחילים, חשוב לוודא שביצעתם את הפעולות הבאות:

  • מפעילים את ממשק Google Kubernetes Engine API.
  • הפעלת Google Kubernetes Engine API
  • אם רוצים להשתמש ב-CLI של Google Cloud למשימה הזו, צריך להתקין ואז להפעיל את ה-CLI של gcloud. אם התקנתם בעבר את ה-CLI של gcloud, מריצים את הפקודה gcloud components update כדי לקבל את הגרסה העדכנית. יכול להיות שגרסאות קודמות של ה-CLI של gcloud לא יתמכו בהרצת הפקודות שמופיעות במסמך הזה.

הכנת הסביבה

  1. במסוף Google Cloud , מפעילים מכונת Cloud Shell:
    פותחים את Cloud Shell

  2. מגדירים את משתני הסביבה שמוגדרים כברירת מחדל באמצעות הפקודה gcloud config set:

    gcloud config set project PROJECT_ID
    

    מחליפים את PROJECT_ID ב Google Cloud מזהה הפרויקט.

באשכולות Autopilot שמופעלת בהם גרסה 1.29.2-gke.1521000 ואילך, יחידות TPU מופעלות כברירת מחדל. מגדירים את ה-TPU באשכולות של Autopilot במפרט של עומס העבודה. מידע נוסף זמין בקטע הגדרת עומסי עבודה של Multislice באמצעות JobSets.

יצירת אשכול GKE

ב-Cloud Shell, יוצרים אשכול GKE:

טייס אוטומטי

gcloud container clusters create-auto multislice-cluster \
    --location=CONTROL_PLANE_LOCATION \
    --cluster-version 1.29.2-gke.1521000 \
    --release-channel rapid

בפקודה הזו:

  • הדגל --location מציין את האזור ב-Compute Engine של מישור הבקרה של האשכול.
  • הדגל --cluster-version מציין את גרסת Kubernetes של האשכול.
  • הדגל --release-channel מציין את ערוץ ההפצה של האשכול. במקרה כזה, הערוץ המהיר תומך בגרסאות העדכניות ביותר שזמינות ב-GKE.

רגילה

gcloud container clusters create multislice-cluster \
    --location=CONTROL_PLANE_LOCATION

מחליפים את CONTROL_PLANE_LOCATION במיקום שבו רוצים ליצור את האשכול. מוודאים שיש לו קיבולת לסוג המכונה ct5lp-hightpu-4t. יצירת האשכול עשויה להימשך כמה דקות.

אם אתם משתמשים במצב GKE Autopilot, דלגו אל הקטע יצירת משאבי Kueue. ב-Autopilot אשכולות שמופעלת בהם גרסה 1.29.2-gke.1521000 ואילך, מכשירי TPU מופעלים כברירת מחדל.

יצירת שלושה מאגרי צמתים של פרוסות TPU במצב רגיל

בקטע הזה יוצרים מאגרי צמתים של TPU באמצעות הפקודה gcloud beta container node-pools create.

  1. יוצרים את מאגר הצמתים הראשון בשם nodepool1:

    gcloud beta container node-pools create nodepool1 \
        --location=CONTROL_PLANE_LOCATION \
        --cluster=multislice-cluster \
        --node-locations=NODE_LOCATION \
        --machine-type=ct5lp-hightpu-4t \
        --tpu-topology=2x4 \
        --project=PROJECT_ID
    

    מחליפים את NODE_LOCATION באזור אחד או יותר באזור האשכול שבו רוצים ליצור את הצמתים.

  2. יוצרים את מאגר הצמתים השני בשם nodepool2:

    gcloud beta container node-pools create nodepool2 \
        --location=CONTROL_PLANE_LOCATION \
        --cluster=multislice-cluster \
        --node-locations=NODE_LOCATION \
        --machine-type=ct5lp-hightpu-4t \
        --tpu-topology=2x4 \
        --project=PROJECT_ID
    
  3. יוצרים את מאגר הצמתים השלישי בשם nodepool3:

    gcloud beta container node-pools create nodepool3 \
        --location=CONTROL_PLANE_LOCATION \
        --cluster=multislice-cluster \
        --node-locations=NODE_LOCATION \
        --machine-type=ct5lp-hightpu-4t \
        --tpu-topology=2x4 \
        --project=PROJECT_ID
    

‫GKE יוצר שלושה מאגרי צמתים. כל מאגר צמתים הוא פרוסת TPU נפרדת.

בשלבים הקודמים השתמשתם בפקודה gcloud beta container node-pools create כדי ליצור את מאגרי הצמתים. הפקודות האלה משתמשות בדגלים הבאים:

  • --node-locations: רשימה מופרדת בפסיקים של אזור אחד או יותר שבהם GKE יוצר את מאגרי הצמתים.
  • --machine-type: סוג המכונה שבה רוצים להשתמש לצמתים. במקרה הזה, השתמשת ב-ct5lp-hightpu-4t. מידע נוסף על סוגי מכונות שתואמים ל-TPU זמין בטבלה שבמאמר בחירת גרסת ה-TPU.
  • --tpu-topology: טופולוגיית ה-TPU שבה יש להשתמש עבור מאגר הצמתים. במקרה הזה, השתמשתם ב-2x4. מידע נוסף על טופולוגיות של TPU זמין במאמר בחירת טופולוגיית TPU.

יצירת משאבי Kueue

  1. יוצרים את קובץ המניפסט kueue.yaml הבא:

    apiVersion: kueue.x-k8s.io/v1beta1
    kind: ResourceFlavor
    metadata:
      name: "vlp-24"
    spec:
      nodeLabels:
        cloud.google.com/gke-tpu-accelerator: tpu-v5-lite-podslice
        cloud.google.com/gke-tpu-topology: 2x4
    ---
    apiVersion: kueue.x-k8s.io/v1beta1
    kind: ClusterQueue
    metadata:
      name: "cluster-queue"
    spec:
      namespaceSelector: {}
      queueingStrategy: BestEffortFIFO
      resourceGroups:
      - coveredResources: ["google.com/tpu"]
        flavors:
        - name: "vlp-24"
          resources:
          - name: "google.com/tpu"
            nominalQuota: 24
    
    ---
    apiVersion: kueue.x-k8s.io/v1beta1
    kind: LocalQueue
    metadata:
      namespace: default
      name: multislice-queue
    spec:
      clusterQueue: cluster-queue
    
  2. החלת מניפסט kueue.yaml:

    kubectl apply -f kueue.yaml
    

‫GKE יוצר את משאבי Kueue הבאים:

  • ResourceFlavor: הפשטה של המשאבים באשכול. בדוגמה הזו, GKE יוצר שלושה חלקי TPU עם טופולוגיה של 2x4. לכל פרוסת TPU יש טופולוגיה של 2x4 עם 8 צ'יפים (24 צ'יפים של TPU בסך הכול).
  • ClusterQueue: תור גלובלי לניהול עומסי עבודה ומשאבי אשכול.
  • LocalQueue: קבוצות של עומסי עבודה שקשורים זה לזה, שבדרך כלל מופעלים על ידי דייר יחיד (משתמש). כל LocalQueue מצביע על ClusterQueue שממנו מוקצים משאבים להרצת עומסי העבודה שלו. עומס עבודה ב-Kueue הוא הפשטה שמייצגת עומס עבודה של אצווה. במקרה הזה, כל עומס עבודה הוא JobSet.

הגדרת עומסי עבודה של Multislice באמצעות JobSets

בקטע הזה יוצרים שלושה JobSets. ‫Jobset הוא API של עומס עבודה שמאפשר לכם לנהל קבוצה של משימות Kubernetes כיחידה אחת. התרחיש הנפוץ ביותר לשימוש ב-JobSet הוא אימון מבוזר, אבל אפשר להשתמש בו גם להרצת עומסי עבודה של אצווה.

ה-JobSet הבא מריץ עומס עבודה של Jax שמפיק את המספר הכולל של שבבי TPU בפלח, ואז נכנס למצב שינה למשך 60 שניות כדי לדמות זמן אימון של מודל, ואז יוצא.

  1. מתקינים את JobSet API באשכול:

    VERSION=v0.8.1
    kubectl apply --server-side -f https://github.com/kubernetes-sigs/jobset/releases/download/$VERSION/manifests.yaml
    
  2. יוצרים את קובץ המניפסט jobsets-multislice.yaml הבא:

    טייס אוטומטי

    apiVersion: jobset.x-k8s.io/v1alpha2
    kind: JobSet
    metadata:
      name: multislice-1slice
      labels:
        kueue.x-k8s.io/queue-name: multislice-queue
      annotations:
        alpha.jobset.sigs.k8s.io/exclusive-topology: cloud.google.com/gke-nodepool
    spec:
      failurePolicy:
        maxRestarts: 4
      replicatedJobs:
        - name: slice
          replicas: 1
          template:
            spec:
              parallelism: 2
              completions: 2
              backoffLimit: 0
              template:
                spec:
                  nodeSelector:
                    cloud.google.com/gke-tpu-accelerator: tpu-v5-lite-podslice
                    cloud.google.com/gke-tpu-topology: 2x4
                  containers:
                  - name: jax-tpu
                    image: python:3.8
                    ports:
                    - containerPort: 8471
                    - containerPort: 8080
                    command:
                    - bash
                    - -c
                    - |
                      pip install "jax[tpu]" -f https://storage.googleapis.com/jax-releases/libtpu_releases.html
                      python -c 'import jax; print("Global device count:", jax.device_count())'
                    resources:
                      limits:
                        google.com/tpu: 4
    
    ---
    apiVersion: jobset.x-k8s.io/v1alpha2
    kind: JobSet
    metadata:
      name: multislice-2slice
      labels:
        kueue.x-k8s.io/queue-name: multislice-queue
      annotations:
        alpha.jobset.sigs.k8s.io/exclusive-topology: cloud.google.com/gke-nodepool
    spec:
      failurePolicy:
        maxRestarts: 4
      replicatedJobs:
        - name: slice
          replicas: 2
          template:
            spec:
              parallelism: 2
              completions: 2
              backoffLimit: 0
              template:
                spec:
                  nodeSelector:
                    cloud.google.com/gke-tpu-accelerator: tpu-v5-lite-podslice
                    cloud.google.com/gke-tpu-topology: 2x4
                  containers:
                  - name: jax-tpu
                    image: python:3.8
                    ports:
                    - containerPort: 8471
                    - containerPort: 8080
                    command:
                    - bash
                    - -c
                    - |
                      pip install "jax[tpu]" -f https://storage.googleapis.com/jax-releases/libtpu_releases.html
                      python -c 'import jax; print("Global device count:", jax.device_count())'
                      sleep 60
                    resources:
                      limits:
                        google.com/tpu: 4
    ---
    apiVersion: jobset.x-k8s.io/v1alpha2
    kind: JobSet
    metadata:
      name: multislice-3slice
      labels:
        kueue.x-k8s.io/queue-name: multislice-queue
      annotations:
        alpha.jobset.sigs.k8s.io/exclusive-topology: cloud.google.com/gke-nodepool
    spec:
      failurePolicy:
        maxRestarts: 4
      replicatedJobs:
        - name: slice
          replicas: 3
          template:
            spec:
              parallelism: 2
              completions: 2
              backoffLimit: 0
              template:
                spec:
                  nodeSelector:
                    cloud.google.com/gke-tpu-accelerator: tpu-v5-lite-podslice
                    cloud.google.com/gke-tpu-topology: 2x4
                  containers:
                  - name: jax-tpu
                    image: python:3.8
                    ports:
                    - containerPort: 8471
                    - containerPort: 8080
                    command:
                    - bash
                    - -c
                    - |
                      sleep 60
                    resources:
                      limits:
                        google.com/tpu: 4
    

    רגילה

    apiVersion: jobset.x-k8s.io/v1alpha2
    kind: JobSet
    metadata:
      name: multislice-1slice
      labels:
        kueue.x-k8s.io/queue-name: multislice-queue
      annotations:
        alpha.jobset.sigs.k8s.io/exclusive-topology: cloud.google.com/gke-nodepool
    spec:
      failurePolicy:
        maxRestarts: 4
      replicatedJobs:
        - name: slice
          replicas: 1
          template:
            spec:
              parallelism: 2
              completions: 2
              backoffLimit: 0
              template:
                spec:
                  hostNetwork: true
                  dnsPolicy: ClusterFirstWithHostNet
                  nodeSelector:
                    cloud.google.com/gke-tpu-accelerator: tpu-v5-lite-podslice
                    cloud.google.com/gke-tpu-topology: 2x4
                  containers:
                  - name: jax-tpu
                    image: python:3.8
                    ports:
                    - containerPort: 8471
                    - containerPort: 8080
                    securityContext:
                      privileged: true
                    command:
                    - bash
                    - -c
                    - |
                      pip install "jax[tpu]" -f https://storage.googleapis.com/jax-releases/libtpu_releases.html
                      python -c 'import jax; print("Global device count:", jax.device_count())'
                    resources:
                      limits:
                        google.com/tpu: 4
    
    ---
    apiVersion: jobset.x-k8s.io/v1alpha2
    kind: JobSet
    metadata:
      name: multislice-2slice
      labels:
        kueue.x-k8s.io/queue-name: multislice-queue
      annotations:
        alpha.jobset.sigs.k8s.io/exclusive-topology: cloud.google.com/gke-nodepool
    spec:
      failurePolicy:
        maxRestarts: 4
      replicatedJobs:
        - name: slice
          replicas: 2
          template:
            spec:
              parallelism: 2
              completions: 2
              backoffLimit: 0
              template:
                spec:
                  hostNetwork: true
                  dnsPolicy: ClusterFirstWithHostNet
                  nodeSelector:
                    cloud.google.com/gke-tpu-accelerator: tpu-v5-lite-podslice
                    cloud.google.com/gke-tpu-topology: 2x4
                  containers:
                  - name: jax-tpu
                    image: python:3.8
                    ports:
                    - containerPort: 8471
                    - containerPort: 8080
                    securityContext:
                      privileged: true
                    command:
                    - bash
                    - -c
                    - |
                      pip install "jax[tpu]" -f https://storage.googleapis.com/jax-releases/libtpu_releases.html
                      python -c 'import jax; print("Global device count:", jax.device_count())'
                      sleep 60
                    resources:
                      limits:
                        google.com/tpu: 4
    ---
    apiVersion: jobset.x-k8s.io/v1alpha2
    kind: JobSet
    metadata:
      name: multislice-3slice
      labels:
        kueue.x-k8s.io/queue-name: multislice-queue
      annotations:
        alpha.jobset.sigs.k8s.io/exclusive-topology: cloud.google.com/gke-nodepool
    spec:
      failurePolicy:
        maxRestarts: 4
      replicatedJobs:
        - name: slice
          replicas: 3
          template:
            spec:
              parallelism: 2
              completions: 2
              backoffLimit: 0
              template:
                spec:
                  hostNetwork: true
                  dnsPolicy: ClusterFirstWithHostNet
                  nodeSelector:
                    cloud.google.com/gke-tpu-accelerator: tpu-v5-lite-podslice
                    cloud.google.com/gke-tpu-topology: 2x4
                  containers:
                  - name: jax-tpu
                    image: python:3.8
                    ports:
                    - containerPort: 8471
                    - containerPort: 8080
                    securityContext:
                      privileged: true
                    command:
                    - bash
                    - -c
                    - |
                      sleep 60
                    resources:
                      limits:
                        google.com/tpu: 4
    
  3. החלת מניפסט jobsets-multislice.yaml:

    kubectl apply -f jobsets-multislice.yaml
    

‫GKE יוצר את המשימות עם בקשות המשאבים הבאות:

  • multislice-1slice JobSet יוצר Job אחד שנדרש לו פרוסת TPU אחת בסך הכול.
  • ה-JobSet‏ multislice-2slice יוצר שני Jobs שדורשים בסך הכול שני חלקי TPU.
  • ה-JobSet multislice-3slice יוצר שלושה ג'ובים שדורשים בסך הכול שלוש פרוסות TPU.

מכיוון שיש באשכול רק 3 חלקי TPU, לא כל קבוצות המשימות יכולות לפעול בו-זמנית. כש-Kueue מוסיף לתור את כל שלושת ה-JobSets של multislice-3slice, משימות ה-Jobs שלו פועלות לבד עד לסיום. האירועים multislice-1slice ו-multislice-2slice יחכו ויפעלו יחד לאחר מכן.

אימות של עומסי העבודה שהתקבלו על ידי Kueue

  1. בודקים את עומסי העבודה שהוכנסו לתור ב-Kueue:

    kubectl get workloads
    

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

    NAME                             QUEUE              ADMITTED BY     AGE
    jobset-multislice-1slice-2530a   multislice-queue                   3s
    jobset-multislice-2slice-ffb02   multislice-queue                   4s
    jobset-multislice-3slice-8c695   multislice-queue   cluster-queue   10s
    

‫Kueue מוסיף לתור עומסי עבודה אחד או יותר, בהתאם למשאבי ה-TPU שנדרשים להם.

מעקב אחרי עומסי העבודה

מדדים ולוחות בקרה של JobSet ושל מאגר צמתים זמינים לכלל המשתמשים במסוףGoogle Cloud .

מדדי ניראות (observability) ולוחות בקרה של תפוקה טובה (goodput) של אימון ושל Cloud ML בGoogle Cloud מסוף נמצאים בתצוגה מקדימה. מידע נוסף על goodput זמין במאמר הצגת מדד goodput של פרודוקטיביות ML: מדד למדידת היעילות של מערכת AI.

מרכזי שליטה

כדי לראות את הסטטוס של מאגרי הצמתים של TPU מרובי-מארחים ב-GKE, עוברים אל לוח הבקרה GKE TPU Node Pool Status שמופיע ב-Cloud Monitoring:

מעבר אל GKE TPU Node Pool Status

מידע נוסף זמין במאמר מעקב אחרי מדדי תקינות של צמתי TPU ומאגרי צמתים.

כדי לראות מידע מקיף על התקינות והביצועים של JobSet, עוברים אל מרכז הבקרה JobSet monitoring במסוף Google Cloud :

מעבר ללוח הבקרה של מעקב אחר JobSet

לוח הבקרה למעקב אחרי JobSet כולל שלוש כרטיסיות:

  • סקירה כללית: בכרטיסייה הזו מוצגת התשתית הבסיסית של JobSet, כמו סטטוס JobSet, מוכנות של רפליקה ומצב רפליקה. הכרטיסייה כוללת גם מדדי תפוקה ומדדי תשתית מסוימים, כולל מדדי מעבד (CPU), מעבד גרפי (GPU), מעבד TPU, זיכרון ואחסון. מידע נוסף זמין במאמר מעקב אחרי תקינות JobSet באמצעות מדדים.
  • קצב העברת נתונים יעיל לאימון (גרסת Preview): בכרטיסייה הזו מוצגת תמונה מקיפה של היעילות התפעולית מקצה לקצה של JobSet, כמו תקינות המאגרים הבסיסיים של הצמתים והביצוע בפועל של עומס העבודה. הוא מספק ציוני תפוקה כדי לעקוב אחרי הביצועים של JobSet, כולל תפוקת תזמון ותפוקת זמן ריצה של שרת proxy . מידע נוסף זמין במאמר בנושא מעקב אחרי קצב העברת נתונים יעיל של JobSet.
  • Cloud ML Goodput (תצוגה מקדימה): בכרטיסייה הזו מוצג תובנה מפורטת לגבי ה-goodput של JobSet, כולל פירוט של ה-badput בשכבת האפליקציה.

    כדי להשתמש בלוח הבקרה הזה, צריך לשלב את Goodput Measurement API ולבצע אינסטרומנטציה באפליקציה כדי לשלוח מדדי תפוקה. פרטים נוספים זמינים בהוראות שבספריית ML Goodput Measurement.

מעקב אחרי הפעלת ה-Pods

kubectl get pods

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

NAME                                READY   STATUS      RESTARTS   AGE
multislice-1slice-slice-0-0-pf2ll   1/1     Running     0          1s
multislice-1slice-slice-0-1-55g62   1/1     Running     0          1s
multislice-2slice-slice-0-0-f4hf7   1/1     Running     0          3s
multislice-2slice-slice-0-1-c8kv7   1/1     Running     0          3s
multislice-2slice-slice-1-0-7h46t   1/1     Running     0          3s
multislice-2slice-slice-1-1-lj9hb   1/1     Running     0          3s
multislice-3slice-slice-0-0-wzq9t   0/1     Completed   0          2m31s
multislice-3slice-slice-0-1-zf4dp   0/1     Completed   0          2m30s
multislice-3slice-slice-1-0-hbfn5   0/1     Completed   0          2m31s
multislice-3slice-slice-1-1-45fgl   0/1     Completed   0          2m30s
multislice-3slice-slice-2-0-wjbp4   0/1     Completed   0          2m30s
multislice-3slice-slice-2-1-lwnvs   0/1     Completed   0          2m30s

בודקים ש-GKE תזמן, תיצור ותפעיל את ה-Pods עבור multislice-3slice קודם. לאחר מכן, GKE מריץ את ה-Pods מ-multislice-1slice ו-multislice-2slice JobSets.

מעקב אחרי תקינות של JobSet באמצעות מדדים

כדי להבין אם JobSet פועל כמצופה, או כדי להסיק אם הוא הופסק, אפשר להשתמש במדדים של Prometheus מחבילת המדדים של JobSet, כמו kube_jobset_succeeded_replicas.

שימו לב שמדדי תקינות של Jobset נתמכים רק ב-GKE מגרסה 1.32.1-gke.135700 ואילך. מדדי תקינות של JobSet מופעלים כברירת מחדל באשכולות חדשים עם גרסאות נתמכות. במקרה של אשכולות קיימים שמשודרגים לגרסאות נתמכות, הלקוחות צריכים להפעיל באופן ידני את חבילת המדדים JobSet. מידע נוסף מופיע במאמרי העזרה.

כדי לבדוק את השלמת JobSet במדריך הזה, מריצים את שאילתת PromQL הבאה:

kube_jobset_succeeded_replicas{
  cluster="multislice-cluster",
  jobset_name=~"mulitslice-.*"}

מעקב אחרי תזמון של JobSet

כדי לעקוב אחרי התזמון של JobSet, משתמשים במדדים הבאים:

  • kubernetes.io/jobset/assigned_node_pools: מאגרי צמתים של GKE שבהם תרמילי Pod מתוזמנים על ידי Kubernetes JobSet.
  • kubernetes.io/node_pool/assigned_jobsets: Kubernetes JobSets שתזמנו Pods במאגר צמתים של GKE.
  • kubernetes.io/jobset/assigned_nodes: צומתי GKE שבהם מתוזמנים פודים של Kubernetes JobSet.
  • kubernetes.io/node/assigned_jobsets: Kubernetes JobSets שקבעו תזמון של Pods בצומת GKE.

כדי לראות את מאגרי הצמתים שבהם מתוזמנים פודים של כל JobSet באשכול ספציפי, מריצים את שאילתת PromQL הבאה:

avg_over_time(
  kubernetes_io:jobset_assigned_node_pools{
    monitored_resource="k8s_entity",
    cluster_name="multislice-cluster"}[${__interval}])

כדי לזהות את מאגרי הצמתים שבהם נקבעה תזמון של Jobset ספציפי, מריצים את שאילתת PromQL הבאה:

avg_over_time(
  kubernetes_io:jobset_assigned_node_pools{
    monitored_resource="k8s_entity",
    cluster_name="multislice-cluster",
    entity_name=~"multislice-.*"}[${__interval}])

כדי לזהות את קבוצות העבודות שתוזמנו במאגר צמתים ספציפי, מריצים את שאילתת PromQL הבאה:

avg_over_time(
  kubernetes_io:node_pool_assigned_jobsets{
    monitored_resource="k8s_node_pool",
    cluster_name="multislice-cluster",
    node_pool_name="multislice-np"}[${__interval}])

מעקב אחרי זמן הפעולה של JobSet, הזמן עד לשחזור (TTR) והזמן בין הפרעות (TBI)

המדדים הבאים שימושיים למעקב אחר הזמינות של JobSet:

  • kubernetes.io/jobset/uptime: הזמן הכולל שבו JobSet היה זמין.
  • kubernetes.io/jobset/times_to_recover: התפלגות תקופת ההתאוששות של JobSet. כל דוגמה מציינת אירוע שחזור יחיד מתוך תקופת השבתה של JobSet.
  • kubernetes.io/jobset/times_between_interruptions: התפלגות של משך הזמן בין סוף ההפרעה הקודמת לתחילת ההפרעה הנוכחית עבור JobSet. כל דגימה מציינת משך זמן יחיד בין ההפרעה הקודמת להפרעה הנוכחית.

המדדים האלה רלוונטיים ל-JobSets שיש בהם בדיוק עבודה אחת של שכפול GPU או TPU. חישוב המדדים מבוסס רק על הזמינות של העבודה המשוכפלת הבודדת הזו. המדדים נתמכים בכל הגרסאות של GKE.

כדי לראות את זמן הפעולה של JobSets שבהם השתמשתם במדריך הזה, מריצים את שאילתת PromQL הבאה:

avg_over_time(
  kubernetes_io:jobset_uptime{
    monitored_resource="k8s_entity", entity_type="jobset",
    entity_name=~"multislice-.*",cluster_name="multislice-cluster"}[${__interval}])

כדי להציג את התפלגויות ה-TBI של JobSets מהמדריך הזה, מריצים את שאילתת PromQL הבאה:

histogram_quantile(0.50,
  sum_over_time(
    kubernetes_io:jobset_times_between_interruptions_bucket{
      monitored_resource="k8s_entity",entity_type="jobset",
      entity_name=~"multislice-.*",cluster_name="multislice-cluster"}[${__interval}]))

אפשר להאריך את טווח הזמן של השאילתה, למשל ל-7 ימים, ולחשב את הזמן הממוצע בין הפרעות (MTBI) במהלך התקופה הזו:

sum(sum_over_time(
  kubernetes_io:jobset_times_between_interruptions_sum{
    monitored_resource="k8s_entity",entity_type="jobset",
    entity_name=~"multislice-.*",cluster_name="multislice-cluster"}[${__interval}]))
/
sum(sum_over_time(
  kubernetes_io:jobset_times_between_interruptions_count{
    monitored_resource="k8s_entity",entity_type="jobset",
    entity_name=~"multislice-.*",cluster_name="multislice-cluster"}[${__interval}]))

כדי להציג את התפלגויות ה-TTR, אפשר להריץ את שאילתות ה-PromQL הבאות:

histogram_quantile(0.50,
  sum_over_time(
    kubernetes_io:jobset_times_to_recover_bucket{
      monitored_resource="k8s_entity",entity_type="jobset",
      entity_name=~"multislice-.*",cluster_name="multislice-cluster"}[${__interval}]))

אחרי שמגדילים את מרווח השאילתות לטווח זמן ארוך יותר, למשל 7 ימים, אפשר לחשב את הזמן הממוצע לשחזור (MTTR) במהלך התקופה הזו:

sum(sum_over_time(
  kubernetes_io:jobset_times_to_recover_sum{
    monitored_resource="k8s_entity",entity_type="jobset",
    entity_name=~"multislice-.*",cluster_name="multislice-cluster"}[${__interval}]))
/
sum(sum_over_time(
  kubernetes_io:jobset_times_to_recover_count{
    monitored_resource="k8s_entity",entity_type="jobset",
    entity_name=~"multislice-.*",cluster_name="multislice-cluster"}[${__interval}]))

מעקב אחרי התפוקה של JobSet

המדדים הבאים שימושיים למעקב אחרי הביצועים של JobSet:

  • kubernetes.io/jobset/scheduling_goodput: חלקיק הזמן שבו כל המשאבים שנדרשים להרצת ה-JobSet של האימון זמינים.
  • kubernetes.io/jobset/proxy_runtime_goodput: חלקיק הזמן שבו כל המאיצים הנדרשים פועלים. המדד הזה מספק אומדן של קצב העברת הנתונים בפועל בזמן הריצה.

    אם אתם צריכים מדידה מדויקת יותר של קצב העברת נתונים יעיל בזמן ריצה, אתם יכולים להטמיע אינסטרומנטציה באפליקציה שלכם ולבצע אינטגרציה עם Goodput Measurement API. פרטים נוספים זמינים בהוראות שבספריית המדידה של ML Goodput.

כדי לראות את קצב העברת הנתונים המתוזמן של JobSet שבו השתמשתם במדריך הזה, מריצים את שאילתת PromQL הבאה:

avg_over_time(
  kubernetes_io:jobset_scheduling_goodput{
    monitored_resource="k8s_entity", entity_type="jobset",
    entity_name=~"multislice-.*",
    cluster_name="multislice-cluster"}[${__interval}])

כדי לראות את קצב העברת הנתונים של ה-proxy בזמן הריצה עבור JobSets מהמדריך הזה, מריצים את שאילתת PromQL הבאה:

avg_over_time(
  kubernetes_io:jobset_proxy_runtime_goodput{
    monitored_resource="k8s_entity", entity_type="jobset",
    entity_name=~"multislice-.*",
    cluster_name="multislice-cluster"}[${__interval}])

הפעלה של עדיפויות ודחיקה של עומסי עבודה ב-Kueue

אפשר גם להקצות לעומסי עבודה ב-Kueue עדיפויות שקובעות את הסדר שבו Kueue מאשר את עומסי העבודה שהוכנסו לתור.

  1. כדי לעדכן את ClusterQueue כך שתהיה לו מדיניות הפסקה זמנית:

    apiVersion: kueue.x-k8s.io/v1beta1
    kind: ResourceFlavor
    metadata:
      name: "vlp-24"
    spec:
      nodeLabels:
        cloud.google.com/gke-tpu-accelerator: tpu-v5-lite-podslice
        cloud.google.com/gke-tpu-topology: 2x4
    ---
    apiVersion: kueue.x-k8s.io/v1beta1
    kind: ClusterQueue
    metadata:
      name: "cluster-queue"
    spec:
      namespaceSelector: {}
      resourceGroups:
      - coveredResources: ["google.com/tpu"]
        flavors:
        - name: "vlp-24"
          resources:
          - name: "google.com/tpu"
            nominalQuota: 24
      preemption:
        reclaimWithinCohort: Any
        withinClusterQueue: LowerPriority
    ---
    apiVersion: kueue.x-k8s.io/v1beta1
    kind: LocalQueue
    metadata:
      namespace: default
      name: multislice-queue
    spec:
      clusterQueue: cluster-queue
    
  2. יוצרים PriorityClass לכל רמת עדיפות שרוצים להקצות לעומסי עבודה:

    apiVersion: scheduling.k8s.io/v1
    kind: PriorityClass
    metadata:
      name: low-priority
    value: 100
    globalDefault: false
    description: "This low priority class should be used for some Pods only."
    
  3. מקצים את priorityClassName ל-JobSet:

    טייס אוטומטי

    apiVersion: jobset.x-k8s.io/v1alpha2
    kind: JobSet
    metadata:
      name: low-priority
      labels:
        kueue.x-k8s.io/queue-name: multislice-queue
      annotations:
        alpha.jobset.sigs.k8s.io/exclusive-topology: cloud.google.com/gke-nodepool
    spec:
      failurePolicy:
        maxRestarts: 4
      replicatedJobs:
        - name: slice
          replicas: 1
          template:
            spec:
              parallelism: 2
              completions: 2
              backoffLimit: 0
              template:
                spec:
                  nodeSelector:
                    cloud.google.com/gke-tpu-accelerator: tpu-v5-lite-podslice
                    cloud.google.com/gke-tpu-topology: 2x4
                  priorityClassName: low-priority
                  containers:
                  - name: jax-tpu
                    image: python:3.8
                    ports:
                    - containerPort: 8471
                    - containerPort: 8080
                    command:
                    - bash
                    - -c
                    - |
                      sleep 60
                    resources:
                      limits:
                        google.com/tpu: 4 # Number of TPU chips per worker
    

    רגילה

    apiVersion: jobset.x-k8s.io/v1alpha2
    kind: JobSet
    metadata:
      name: low-priority
      labels:
        kueue.x-k8s.io/queue-name: multislice-queue
      annotations:
        alpha.jobset.sigs.k8s.io/exclusive-topology: cloud.google.com/gke-nodepool
    spec:
      failurePolicy:
        maxRestarts: 4
      replicatedJobs:
        - name: slice
          replicas: 1
          template:
            spec:
              parallelism: 2
              completions: 2
              backoffLimit: 0
              template:
                spec:
                  hostNetwork: true
                  dnsPolicy: ClusterFirstWithHostNet
                  nodeSelector:
                    cloud.google.com/gke-tpu-accelerator: tpu-v5-lite-podslice
                    cloud.google.com/gke-tpu-topology: 2x4
                  priorityClassName: low-priority
                  containers:
                  - name: jax-tpu
                    image: python:3.8
                    ports:
                    - containerPort: 8471
                    - containerPort: 8080
                    securityContext:
                      privileged: true
                    command:
                    - bash
                    - -c
                    - |
                      sleep 60
                    resources:
                      limits:
                        google.com/tpu: 4 # Number of TPU chips per worker
    

‫GKE כולל מדיניות הפסקה זמנית שקובעת איך Kueue מקצה את המשאבים הזמינים. המדיניות קובעת שאפשר לבצע הפסקה בעומס עבודה אם עומס עבודה בעדיפות גבוהה יותר צריך את המשאבים. יש סיכוי גבוה יותר שעומסי עבודה עם ערך עדיפות נמוך יותר יידחקו על ידי עומסי עבודה עם עדיפות גבוהה יותר.

הסרת המשאבים

כדי לא לצבור חיובים לחשבון Google Cloud על המשאבים שבהם השתמשתם במדריך הזה, אתם יכולים למחוק את הפרויקט שמכיל את המשאבים או להשאיר את הפרויקט ולמחוק את המשאבים בנפרד.

מחיקת הפרויקט

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

מחיקת המשאב הספציפי

  1. מוחקים את משאבי Kueue:

    kubectl delete -f jobsets-multislice.yaml
    kubectl delete -f kueue.yaml
    
  2. מחיקת האשכול:

    gcloud container clusters delete multislice-cluster --location=CONTROL_PLANE_LOCATION
    

המאמרים הבאים