בדיקות ביצועים עם לקוחות Compute Engine

בדף הזה מוסבר איך לבדוק את הביצועים של מופע Google Cloud Managed Lustre באמצעות לקוחות Compute Engine. במדריך מוסבר איך למדוד את הביצועים של לקוח יחיד באמצעות fio, ואיך למדוד את הביצועים המצטברים של כמה לקוחות באמצעות כלי ההשוואה של IOR.

מדידת הביצועים של לקוח יחיד

כדי לבדוק את ביצועי הקריאה והכתיבה מלקוח יחיד של Compute Engine, משתמשים בכלי fio (Flexible I/O tester) של שורת הפקודה.

  1. מתקינים את fio:

    Rocky 8

    sudo dnf install fio -y
    

    ‫Ubuntu 20.04 ו-22.04

    sudo apt update
    sudo install fio
    
  2. מריצים את הפקודה הבאה:

    fio --ioengine=libaio --filesize=32G --ramp_time=2s \
    --runtime=5m --numjobs=16 --direct=1 --verify=0 --randrepeat=0 \
    --group_reporting --directory=/lustre --buffer_compress_percentage=50 \
    --name=read --blocksize=1m --iodepth=64 --readwrite=read
    

הבדיקה נמשכת כ-5 דקות. בסיום, התוצאות מוצגות. בהתאם להגדרה, אפשר לצפות לתפוקה של עד מהירות הרשת המקסימלית של המכונה הווירטואלית, ולאלפי פעולות קלט/פלט בשנייה לכל ‎TiB.

מדידת הביצועים בחשבון מרובה לקוחות

כדי לבדוק את ביצועי הקריאה והכתיבה של Managed Lustre מכמה לקוחות של Compute Engine, אפשר להשתמש בכלי ההשוואה IOR. בהוראות הבאות מוסבר איך להפוך את הגדרת הלקוח לאוטומטית ולהשתמש ב-IOR כדי לבדוק את צבירת הקלט/פלט ממספר מכונות לקוח. ‫IOR משתמש ב-MPI – פרוטוקול להעברת הודעות – כדי לאפשר למכונות הלקוח המרובות לתאם ביניהן.

לפני שמתחילים, מוודאים שהערך של mtu ברשת מוגדר ל-8896.

הגדרת משתני סביבה ויצירת מפתח SSH

לפני שמפעילים את האשכול, צריך ליצור מפתח SSH במחשב המקומי. המפתח הזה יופץ למכונות הלקוח במהלך היצירה כדי לאפשר תקשורת ללא סיסמה עבור MPI.

export SSH_USER="lustre-user"
export CLIENT_PREFIX="lustre-client"

# Generate an SSH key for the specified user
ssh-keygen -t rsa -b 4096 -C "${SSH_USER}" -N '' -f "./id_rsa"
chmod 600 "./id_rsa"

# Create a metadata file formatted for Google Cloud
echo "${SSH_USER}:$(cat "./id_rsa.pub") ${SSH_USER}" > "./keys.txt"

יצירת סקריפט לטעינה בזמן ההפעלה

שומרים את התוכן הבא בקובץ בשם install-ior.sh במחשב המקומי. הסקריפט הזה מזהה את מערכת ההפעלה, מחכה עד שהנעילות של ההפעלה ישוחררו, מתקין בצורה בטוחה את לקוח Lustre ואת יחסי התלות, מהדר גרסה יציבה של IOR ומטמיע את מערכת הקבצים של Managed Lustre.

מחליפים את LUSTRE_IP בכתובת ה-IP של מופע Managed Lustre ואת FS_NAME בשם של מערכת הקבצים.

#!/bin/bash
source /etc/os-release

if [[ "$ID" == "ubuntu" ]]; then
    # Ubuntu
    # Wait for apt lock
    while fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; do sleep 5; done

    # Configure Artifact Registry repo for Ubuntu
    curl -fsSL https://us-apt.pkg.dev/doc/repo-signing-key.gpg | sudo gpg --dearmor -o /usr/share/keyrings/us-apt-pkg-dev.gpg

    if [[ "$VERSION_ID" == "22.04" ]]; then
        REPO_NAME="lustre-client-ubuntu-jammy"
    elif [[ "$VERSION_ID" == "24.04" ]]; then
        REPO_NAME="lustre-client-ubuntu-noble"
    fi

    echo "deb [signed-by=/usr/share/keyrings/us-apt-pkg-dev.gpg] https://us-apt.pkg.dev/projects/lustre-client-binaries $REPO_NAME main" | sudo tee /etc/apt/sources.list.d/lustre-client.list

    sudo apt-get update
    while ! sudo apt-get install -y lustre-client-modules-$(uname -r) lustre-client-utils openmpi-bin libopenmpi-dev make gcc g++ wget git automake autoconf libaio-dev; do
        sleep 5
    done
    sudo modprobe lustre
else
    # Red Hat / Rocky Linux
    while systemctl is-active --quiet dnf-makecache.service; do sleep 5; done

    if [[ "$ID" == "rocky" && "$VERSION_ID" == 8* ]]; then
        REPO="lustre-client-rocky-8"
    elif [[ "$ID" == "rocky" && "$VERSION_ID" == 9* ]]; then
        REPO="lustre-client-rocky-9"
    elif [[ "$ID" == "rhel" && "$VERSION_ID" == 9* ]]; then
        REPO="lustre-client-rocky-9"
    fi

    gcloud beta artifacts print-settings yum --repository=$REPO --location=us --project=lustre-client-binaries | sudo bash

    while ! sudo dnf -y --enablerepo=$REPO install kmod-lustre-client lustre-client; do sleep 5; done
    sudo modprobe lustre

    while ! sudo dnf install -y openmpi openmpi-devel make gcc gcc-c++ wget git automake autoconf libaio-devel; do sleep 5; done

    export PATH=$PATH:/usr/lib64/openmpi/bin
fi

# Build IOR from source
echo "Cloning repo: https://github.com/hpc/ior.git and building IOR"
pushd /tmp
git clone -b 4.0.0 https://github.com/hpc/ior
cd ior
./bootstrap
./configure --disable-dependency-tracking --with-aio
make clean
make -j"$(nproc)"
sudo make install
popd
echo "Finished building IOR"

# Mount the Managed Lustre file system
mkdir -p /lustre

if ! grep -q "/lustre" /etc/fstab; then
    echo "LUSTRE_IP@tcp:/FS_NAME /lustre lustre defaults,_netdev 0 0" >> /etc/fstab
fi

mount -a

פריסת מכונות הלקוח

מריצים את הפקודה הבאה כדי ליצור בכמות גדולה את מכונות הלקוח של Compute Engine.

gcloud compute instances bulk create \
  --name-pattern="${CLIENT_PREFIX}-####" \
  --zone="ZONE" \
  --machine-type="MACHINE_TYPE" \
  --scopes="https://www.googleapis.com/auth/cloud-platform" \
  --network-interface=subnet=SUBNET,nic-type=GVNIC \
  --network-performance-configs=total-egress-bandwidth-tier=TIER_1 \
  --metadata-from-file=ssh-keys=./keys.txt,startup-script=install-ior.sh \
  --create-disk=auto-delete=yes,boot=yes,\
image-family=IMAGE_FAMILY,\
image-project=IMAGE_PROJECT,\
mode=rw,size=100,type=DISK_TYPE \
  --count NUM_NODES
  • מחליפים את ZONE ו-SUBNET בערכים הספציפיים של הפריסה.

  • בוחרים MACHINE_TYPE. הביצועים הכוללים של ההשוואה לשוק תלויים בסוגי המכונות של הלקוח. במאמר שיקולים לגבי ביצועים יש מידע על בחירת סוגי מכונות כדי להשיג את התפוקה הטובה ביותר.

  • אם סוג המכונה לא תומך ברשת TIER_1, צריך למחוק את השורה --network-performance-configs מהפקודה.

  • מגדירים את DISK_TYPE לאחד מהערכים הבאים: hyperdisk-balanced (לסוג מכונה עם 4 בשם הגנרציה, כמו c4a או n4) או pd-balanced.

  • מציינים את IMAGE_FAMILY ואת IMAGE_PROJECT. הערכים הנתמכים הם:

    מערכת הפעלה משפחת תמונות (x86) משפחת תמונות (ARM) פרויקט תמונות
    HPC Rocky Linux 8 hpc-rocky-linux-8 לא נתמך cloud-hpc-image-public
    Rocky Linux 9 rocky-linux-9 rocky-linux-9-arm64 rocky-linux-cloud
    RHEL 9 rhel-9 rhel-9-arm64 rhel-cloud
    ‫Ubuntu 22.04 LTS ubuntu-2204-lts ubuntu-2204-lts-arm64 ubuntu-os-cloud
    Ubuntu 24.04 LTS לא נתמך ubuntu-2404-lts-arm64 ubuntu-os-cloud
  • מציינים את NUM_NODES. כדי להגיע לרוויה במערכת הקבצים, קיבולת הרשת הכוללת של האשכול צריכה להיות גדולה ב-20% בערך מהתפוקה שהוקצתה למערכת הקבצים.

    במכונות שמופעל בהן Tier 1 networking, מכונה אחת יכולה להעביר נתונים במהירות של ‎25 Gbps עד ‎200 Gbps (בערך ‎3,000 MBps עד ‎25,000 MBps), בהתאם לסוג המכונה הווירטואלית ולמספר ליבות ה-CPU. במכונות רגילות, תעבורת נתונים יוצאת (egress) מוגבלת בדרך כלל ל-2Gbps לכל vCPU.

    לדוגמה, אם הקיבולת של מופע Managed Lustre שלכם מניבה 100,000MBps של תפוקה תיאורטית, אתם צריכים תעבורת נתונים יוצאת מצטברת של לקוח של 120,000MBps (100,000 * 1.2) כדי להגיע לניצול מלא:

    • עם מכונות רגילות: אם לכל מכונת לקוח יש תעבורת נתונים יוצאת (egress) שפורסמה של 2,000MBps, צריך להקצות לפחות 60 לקוחות (120,000 / 2,000).
    • עם רשת ברמה 1: אם לכל מכונת לקוח יש תעבורת נתונים יוצאת שפורסמה של 10,000 מגה-בייט לשנייה (MBps) (בערך 80 גיגה-בייט לשנייה (Gbps)), צריך להקצות לפחות 12 לקוחות (120,000 / 10,000).

העתקת מפתחות וקבצים

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

  1. שומרים את כתובות ה-IP הפרטיות של מכונות הלקוח בקובץ המארח של MPI, ואת כתובות ה-IP הציבוריות לגישת SSH ו-SCP למכונות הלקוח:

    gcloud compute instances list --filter="name ~ '^${CLIENT_PREFIX}*'" --format="csv[no-heading](INTERNAL_IP)" > hosts.txt
    gcloud compute instances list --filter="name ~ '^${CLIENT_PREFIX}*'" --format="csv[no-heading](EXTERNAL_IP)" > external_ips.txt
    
  2. מעתיקים את המפתח הפרטי לכל הלקוחות. כך צמתי העובדים יכולים לתקשר אחד עם השני בצורה מאובטחת במהלך ההשוואה:

    while IFS= read -r IP || [[ -n "$IP" ]]
    do
      [[ -z "$IP" ]] && continue
      echo "Preparing and copying to ${SSH_USER}@${IP}..."
      # Ensure the .ssh directory exists
      ssh -i ./id_rsa -o StrictHostKeyChecking=no "${SSH_USER}@${IP}" "mkdir -p ~/.ssh && chmod 700 ~/.ssh"
      # Copy the file
      scp -i ./id_rsa -o StrictHostKeyChecking=no ./id_rsa "${SSH_USER}@${IP}:~/.ssh/id_rsa"
    done < "./external_ips.txt"
    
  3. מגדירים את הצומת הראשי ומעתיקים אליו את קובץ המארח. זו תהיה המכונה שממנה מריצים את הבדיקה.

    export HEAD_NODE=$(head -n 1 ./external_ips.txt)
    scp -i ./id_rsa -o "StrictHostKeyChecking=no" -o UserKnownHostsFile=/dev/null ./hosts.txt ${SSH_USER}@${HEAD_NODE}:~/hostfile
    

חיבור ואימות

  1. מתחברים לצומת הראשי:

    ssh -i ./id_rsa -o "StrictHostKeyChecking=no" -o UserKnownHostsFile=/dev/null ${SSH_USER}@${HEAD_NODE}
    
  2. ודא שסקריפט לטעינה בזמן ההפעלה הסתיים ומערכת הקבצים נטענה בהצלחה לפני שמריצים את הערכת הביצועים.

    כדי לבדוק את היומנים של סקריפט לטעינה בזמן ההפעלה:

    sudo journalctl -u google-startup-scripts.service -f
    

    כדי לוודא שמערכת הקבצים נטענה:

    df -h | grep lustre
    

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

הפעלת נקודת ההשוואה של IOR

  1. ב-Rocky Linux וב-RHEL בלבד: טוענים את מודול OpenMPI מצומת הראש.

    if [ -f /etc/profile.d/modules.sh ]; then
        source /etc/profile.d/modules.sh
        module load mpi/openmpi-$(arch)
    fi
    
  2. יוצרים ספריית בדיקה ומגדירים בעלות:

    sudo mkdir -p /lustre/test
    sudo chown -R $USER:$USER /lustre/test
    
  3. מגדירים את משתני הבדיקה:

    export NUM_NODES="NUM_NODES"
    export PROCESSES_PER_NODE="PROCESSES_PER_NODE"
    export NUM_PROCESSES=$(( NUM_NODES * PROCESSES_PER_NODE ))
    

    כאשר:

    • NUM_NODES: המספר הכולל של מכונות הלקוח שמשתתפות בבדיקה.
    • PROCESSES_PER_NODE: מספר דרגות ה-MPI להרצה בכל מכונת לקוח. מומלץ להתחיל בהגדרה שתתאים למספר הליבות הפיזיות (או למחצית ממספר יחידות ה-vCPU) במכונות הלקוח. במכונות עם ביצועים גבוהים, הגדרה של הערך הזה בין 8 ל-16 בדרך כלל מניבה את התפוקה הכי טובה ברשת. הגדרת ערך גבוה מדי עלולה לגרום לתקורה של החלפת הקשר ולהפחית את ביצועי ההשוואה.
  4. מריצים את הפקודה כדי להתחיל את נקודת ההשוואה:

    ‫Rocky Linux ו-RHEL

    קצב העברת נתונים לכתיבה

    הפקודה הזו כותבת ברציפות במשך 60 שניות כדי לבדוק את קצב העברת הנתונים המקסימלי במצב יציב. גודל הקובץ לכל משימה מוגדר ל-50TiB, שהוא גודל גדול באופן שרירותי, כדי שהמשימות ימשיכו לכתוב עד שתם הזמן של 60 שניות.

    mpirun \
      --allow-run-as-root \
      --mca plm_rsh_no_tree_spawn 1 \
      --mca opal_set_max_sys_limits 1 \
      --mca plm_rsh_num_concurrent ${NUM_NODES} \
      --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
      --prefix /usr/lib64/openmpi \
      --npernode ${PROCESSES_PER_NODE} \
      --np ${NUM_PROCESSES} \
      --hostfile ~/hostfile \
      /usr/local/bin/ior \
      -a AIO \
      --posix.odirect \
      -F -g -v -w -k \
      -t 4m -b 50t \
      -D 60 \
      -O stoneWallingWearOut=1 \
      -O stoneWallingStatusFile=/lustre/test/ior-easy.stonewall \
      -o /lustre/test/ior_file

    קצב העברת נתונים לקריאה

    בשלב הזה, המערכת קוראת בחזרה בדיוק את כמות הנתונים שנכתבה בהצלחה במהלך בדיקת קצב העברת הנתונים של הכתיבה שנמשכת 60 שניות. למרות שגודל הקובץ לכל משימה (-b) מוגדר ל-50TiB כדי להתאים לגיאומטריה של שלב הכתיבה, הדגל -O stoneWallingWearOut=1 מורה ל-IOR להפסיק לקרוא ברגע שהוא מגיע לגבול הנתונים המדויק שמתועד בקובץ הסטטוס של חומת האבן.

    mpirun \
      --allow-run-as-root \
      --mca plm_rsh_no_tree_spawn 1 \
      --mca opal_set_max_sys_limits 1 \
      --mca plm_rsh_num_concurrent ${NUM_NODES} \
      --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
      --prefix /usr/lib64/openmpi \
      --npernode ${PROCESSES_PER_NODE} \
      --np ${NUM_PROCESSES} \
      --hostfile ~/hostfile \
      /usr/local/bin/ior \
      -a AIO \
      --posix.odirect \
      -F -g -v -r -k \
      -t 4m -b 50t \
      -D 60 \
      -O stoneWallingWearOut=1 \
      -O stoneWallingStatusFile=/lustre/test/ior-easy.stonewall \
      -o /lustre/test/ior_file

    פעולות קלט/פלט בשנייה (IOPS) של כתיבה

    בבדיקה הזו נעשה שימוש בגדלי העברה קטנים של 4KiB ובגדלי קבצים של 8GiB לכל משימה כדי למדוד את מספר פעולות הקלט/פלט המקסימלי לשנייה (IOPS) שמערכת הקבצים יכולה לטפל בהן.

    mpirun \
      --allow-run-as-root \
      --mca plm_rsh_no_tree_spawn 1 \
      --mca opal_set_max_sys_limits 1 \
      --mca plm_rsh_num_concurrent ${NUM_NODES} \
      --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
      --prefix /usr/lib64/openmpi \
      --np ${NUM_PROCESSES} \
      --oversubscribe \
      --map-by node \
      --bind-to socket \
      --hostfile ~/hostfile \
      /usr/local/bin/ior \
      -e \
      -t 4k \
      -b 8g \
      -s 1 \
      -a AIO \
      --posix.odirect \
      --aio.max-pending=256 \
      -w \
      -F \
      -z \
      -Q 1 \
      -G 1745405099 \
      -D 45 \
      -O stoneWallingWearOut=1 \
      -o /lustre/test/ior-random

    קריאת IOPS

    כדי למנוע קריאה מקובץ דליל, הבדיקה הזו משתמשת בשתי פקודות: פקודת כתיבה ליצירת קובץ מוצק בגודל העברה של 4MiB וגודל קובץ של 8GiB לכל משימה, ואחריה בדיקת IOPS של קריאה אקראית בגודל 4KiB.

    1. יוצרים את הקובץ לקריאה:

      mpirun \
        --allow-run-as-root \
        --mca plm_rsh_no_tree_spawn 1 \
        --mca opal_set_max_sys_limits 1 \
        --mca plm_rsh_num_concurrent ${NUM_NODES} \
        --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
        --prefix /usr/lib64/openmpi \
        --npernode ${PROCESSES_PER_NODE} \
        --np ${NUM_PROCESSES} \
        --oversubscribe \
        --map-by node \
        --bind-to socket \
        --hostfile ~/hostfile \
        /usr/local/bin/ior \
        -a AIO \
        --posix.odirect \
        -w \
        -F \
        -k \
        -t 4m \
        -b 8g \
        -s 1 \
        -Q 1 \
        -G 1745405099 \
        -o /lustre/test/ior_rand_read
    2. מריצים את בדיקת הקריאה של IOR:

      mpirun \
        --allow-run-as-root \
        --mca plm_rsh_no_tree_spawn 1 \
        --mca opal_set_max_sys_limits 1 \
        --mca plm_rsh_num_concurrent ${NUM_NODES} \
        --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
        --prefix /usr/lib64/openmpi \
        --oversubscribe \
        --map-by node \
        --bind-to socket \
        --npernode ${PROCESSES_PER_NODE} \
        --np ${NUM_PROCESSES} \
        --hostfile ~/hostfile \
        /usr/local/bin/ior \
        -a AIO \
        --posix.odirect \
        --aio.max-pending 256 \
        -r \
        -F \
        -z \
        -t 4k \
        -b 8g \
        -s 1 \
        -Q 1 \
        -G 1745405099 \
        -D 45 \
        -O stoneWallingWearOut=1 \
        -o /lustre/test/ior_rand_read

    Ubuntu

    קצב העברת נתונים לכתיבה

    הפקודה הזו כותבת ברציפות במשך 60 שניות כדי לבדוק את קצב העברת הנתונים המקסימלי במצב יציב. גודל הקובץ לכל משימה מוגדר ל-50TiB, שהוא גודל גדול באופן שרירותי, כדי שהמשימות ימשיכו לכתוב עד שתם הזמן של 60 שניות.

    mpirun \
      --allow-run-as-root \
      --mca plm_rsh_no_tree_spawn 1 \
      --mca opal_set_max_sys_limits 1 \
      --mca plm_rsh_num_concurrent ${NUM_NODES} \
      --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
      --npernode ${PROCESSES_PER_NODE} \
      --np ${NUM_PROCESSES} \
      --hostfile ~/hostfile \
      /usr/local/bin/ior \
      -a AIO \
      --posix.odirect \
      -F -g -v -w -k \
      -t 4m -b 50t \
      -D 60 \
      -O stoneWallingWearOut=1 \
      -O stoneWallingStatusFile=/lustre/test/ior-easy.stonewall \
      -o /lustre/test/ior_file

    קצב העברת נתונים לקריאה

    בשלב הזה, המערכת קוראת בחזרה בדיוק את כמות הנתונים שנכתבה בהצלחה במהלך בדיקת קצב העברת הנתונים של הכתיבה שנמשכת 60 שניות. למרות שגודל הקובץ לכל משימה (-b) מוגדר ל-50TiB כדי להתאים לגיאומטריה של שלב הכתיבה, הדגל -O stoneWallingWearOut=1 מורה ל-IOR להפסיק לקרוא ברגע שהוא מגיע לגבול הנתונים המדויק שמתועד בקובץ הסטטוס של חומת האבן.

    mpirun \
      --allow-run-as-root \
      --mca plm_rsh_no_tree_spawn 1 \
      --mca opal_set_max_sys_limits 1 \
      --mca plm_rsh_num_concurrent ${NUM_NODES} \
      --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
      --npernode ${PROCESSES_PER_NODE} \
      --np ${NUM_PROCESSES} \
      --hostfile ~/hostfile \
      /usr/local/bin/ior \
      -a AIO \
      --posix.odirect \
      -F -g -v -r -k \
      -t 4m -b 50t \
      -D 60 \
      -O stoneWallingWearOut=1 \
      -O stoneWallingStatusFile=/lustre/test/ior-easy.stonewall \
      -o /lustre/test/ior_file

    פעולות קלט/פלט בשנייה (IOPS) של כתיבה

    בבדיקה הזו נעשה שימוש בגדלי העברה קטנים של 4KiB ובגדלי קבצים של 8GiB לכל משימה כדי למדוד את מספר פעולות הקלט/פלט המקסימלי לשנייה (IOPS) שמערכת הקבצים יכולה לטפל בהן.

    mpirun \
      --allow-run-as-root \
      --mca plm_rsh_no_tree_spawn 1 \
      --mca opal_set_max_sys_limits 1 \
      --mca plm_rsh_num_concurrent ${NUM_NODES} \
      --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
      --np ${NUM_PROCESSES} \
      --oversubscribe \
      --map-by node \
      --bind-to socket \
      --hostfile ~/hostfile \
      /usr/local/bin/ior \
      -e \
      -t 4k \
      -b 8g \
      -s 1 \
      -a AIO \
      --posix.odirect \
      --aio.max-pending=256 \
      -w \
      -F \
      -z \
      -Q 1 \
      -G 1745405099 \
      -D 45 \
      -O stoneWallingWearOut=1 \
      -o /lustre/test/ior-random

    קריאת IOPS

    כדי למנוע קריאה מקובץ דליל, הבדיקה הזו משתמשת בשתי פקודות: פקודת כתיבה ליצירת קובץ מוצק בגודל העברה של 4MiB וגודל קובץ של 8GiB לכל משימה, ואחריה בדיקת IOPS של קריאה אקראית בגודל 4KiB.

    1. יוצרים את הקובץ לקריאה:

      mpirun \
        --allow-run-as-root \
        --mca plm_rsh_no_tree_spawn 1 \
        --mca opal_set_max_sys_limits 1 \
        --mca plm_rsh_num_concurrent ${NUM_NODES} \
        --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
        --npernode ${PROCESSES_PER_NODE} \
        --np ${NUM_PROCESSES} \
        --oversubscribe \
        --map-by node \
        --bind-to socket \
        --hostfile ~/hostfile \
        /usr/local/bin/ior \
        -a AIO \
        --posix.odirect \
        -w \
        -F \
        -k \
        -t 4m \
        -b 8g \
        -s 1 \
        -Q 1 \
        -G 1745405099 \
        -o /lustre/test/ior_rand_read
    2. מריצים את בדיקת הקריאה של IOR:

      mpirun \
        --allow-run-as-root \
        --mca plm_rsh_no_tree_spawn 1 \
        --mca opal_set_max_sys_limits 1 \
        --mca plm_rsh_num_concurrent ${NUM_NODES} \
        --mca plm_rsh_args "-o StrictHostKeyChecking=no" \
        --oversubscribe \
        --map-by node \
        --bind-to socket \
        --npernode ${PROCESSES_PER_NODE} \
        --np ${NUM_PROCESSES} \
        --hostfile ~/hostfile \
        /usr/local/bin/ior \
        -a AIO \
        --posix.odirect \
        --aio.max-pending 256 \
        -r \
        -F \
        -z \
        -t 4k \
        -b 8g \
        -s 1 \
        -Q 1 \
        -G 1745405099 \
        -D 45 \
        -O stoneWallingWearOut=1 \
        -o /lustre/test/ior_rand_read

    התכונות הניסיוניות של mpirun הן:

    • --mca plm_rsh_no_tree_spawn 1: משבית את יצירת הדמונים על בסיס עץ כדי לשפר את אמינות ההפעלה בצמתים.
    • --mca opal_set_max_sys_limits 1: המערכת מנסה להגדיר באופן אוטומטי את המגבלות שלה (למשל, מספר הקבצים המקסימלי שאפשר לפתוח) לערכים המקסימליים המותרים.
    • --mca plm_rsh_num_concurrent: מגדיר את המספר המקסימלי של חיבורי SSH בו-זמניים ש-mpirun ישתמש בהם כשהוא מפעיל דימונים של עובדים.
    • --mca plm_rsh_args ...: עוקף את הבדיקה המחמירה של מפתח המארח כדי למנוע מצבים שבהם הנחיות אינטראקטיביות של SSH גורמות להשבתה של הפעלת תהליך MPI.
    • --prefix ...: מגדיר באופן מפורש את נתיב ההתקנה של OpenMPI עבור Rocky Linux ו-RHEL, כדי שצמתי העבודה יוכלו למצוא את הדמון הנדרש (orted).
    • --allow-run-as-root: מאפשר ל-mpirun לפעול כמשתמש root.
    • --oversubscribe: מאפשר ל-MPI לתזמן יותר תהליכים בצומת מאשר מספר הליבות הפיזיות הזמינות.
    • --map-by node: מפזר את תהליכי ה-MPI באופן שווה בין הצמתים הזמינים בשיטת round-robin.
    • --bind-to socket: קושר תהליכי MPI לשקעי CPU פיזיים כדי לייעל את הגישה לזיכרון ואת הביצועים של המטמון.
    • --npernode: מספר התהליכים לכל צומת.
    • --np: המספר הכולל של תהליכי MPI להפעלה.
    • --hostfile: מציין את הקובץ שמכיל את רשימת המארחים שבהם יופעל הסקריפט.

    התכונות הניסיוניות של ior הן:

    • -a AIO --posix.odirect: משתמש במנוע קלט/פלט אסינכרוני (AIO) בשילוב עם קלט/פלט ישיר של POSIX. הפעולה הזו מדלגת על מטמון הדפים ב-RAM בצד הלקוח ומכריחה כתיבות לא חוסמות בו-זמניות ישירות לשרתי האחסון, וכך מבטיחה שהמדד ימדוד את הביצועים האמיתיים של אחסון הרשת ולא את מאגרי הזיכרון.
    • --aio.max-pending=256: קובעת את המספר המקסימלי של פעולות קלט/פלט (I/O) אסינכרוניות בו-זמניות בתהליך.
    • -C: שינוי הסדר של המשימות כדי לשפר את ביצועי הקריאה.
    • -F: מצב קובץ לכל תהליך.
    • -g: שימוש במחסומים כדי להפריד בין שלבי הכתיבה והקריאה של הבדיקה.
    • -v: רישום מפורט ביומן הפלט.
    • -w / -r: מנחה את IOR להריץ את בדיקת הביצועים של כתיבה (-w) או קריאה (-r).
    • -k: מונע מ-IOR למחוק את קובץ הבדיקה אחרי הכתיבה, וכך הוא זמין לבדיקת הקריאה.
    • -e: מבצע fsync אחרי שלב הכתיבה כדי להבטיח שהנתונים יועברו לכונני האחסון.
    • -z: מורה ל-IOR לבצע קלט/פלט של גישה אקראית במקום גישה רציפה.
    • -s 1: מגדיר את מספר הפלחים ל-1.
    • -Q 1: מגדיר את ההיסט של המשימה לכל צומת, כך שהמשימות מיושרות ונקודת ההשוואה מתואמת בצורה נכונה בכל הצמתים.
    • -G 1745405099: מקודד את חותמת הזמן של הזרע האקראי כך שבשלב הקריאה ייווצרו בדיוק אותם היסטים אקראיים של קבצים ששימשו בשלב הכתיבה.
    • -t: הגדרת גודל ההעברה לכל פעולת קלט/פלט (לדוגמה, 4m לרוחב פס, 4k ל-IOPS).
    • -b: הגדרת גודל הבלוק המקסימלי לכל תהליך (לדוגמה, 50t לתפוקה, 8g ל-IOPS) כדי לוודא שבמהלך ההרצה המתוזמנת לא ייגמרו נתוני המטען הייעודי של הבדיקה.
    • -D: מגביל את משך זמן הריצה של הבדיקה למספר מסוים של שניות (למשל, 60 או 45). ההגבלה הזו מפסיקה את ההשוואה באופן שווה כדי לתעד מדידה אמיתית של מצב יציב.
    • -O stoneWallingWearOut=1: מאלץ את כל השרשורים המקבילים להמשיך ליצור עומס כתיבה רציף למשך כל משך הבדיקה, ומונע משרשורים מהירים יותר להשלים את הבדיקה מוקדם יותר ולהפחית את העומס הכולל על הרשת.
    • -O stoneWallingStatusFile=<path>: כותב קובץ לאימות המצב בסוף שלב הכתיבה. בשלב הקריאה הבא, המערכת משתמשת בקובץ הזה כדי לקרוא רק את הבלוקים שהועברו בהצלחה, וכך נמנעות שגיאות של מצביע null במהלך הקריאות.
    • -o: הנתיב לקובץ הבדיקה במערכת הקבצים של Managed Lustre.

צפייה בתוצאות

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

מדדים מרכזיים

  • aggregate filesize: הכמות הכוללת של הנתונים שנכתבו או נקראו במהלך הבדיקה בכל הלקוחות המשתתפים.

  • bw(MiB/s) / Max Write / Max Read: המדד הכי חשוב לבדיקות רציפות. הערך הזה מייצג את רוחב הפס המצטבר שהושג על ידי מערכת הקבצים Managed Lustre.

  • IOPS: המדד הכי חשוב לבדיקות קלט/פלט אקראיות. העמודה הזו מציגה את מספר פעולות הקלט/פלט המקסימלי לשנייה.

ייצוא התוצאות לקובץ

אם רוצים לנתח את התוצאות באופן פרוגרמטי, להזין אותן למסד נתונים או לשמור אותן לניתוח מאוחר יותר, אפשר להגדיר ל-IOR לייצא את נתוני הסיכום בפורמטים JSON ו-CSV במקום רק להדפיס אותם על המסך.

כדי לעשות את זה, מוסיפים את הדגלים -O לסוף מחרוזת הפקודה ior:

-O summaryFormat=JSON \
-O summaryFile=/lustre/test/perf-results/summary.json \
-O saveRankPerformanceDetailsCSV=/lustre/test/perf-results/details.csv

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

הביצועים הצפויים לעומת הביצועים בפועל

אתם יכולים לחשב את התפוקה המקסימלית המתמטית של מערכת הקבצים על סמך הקיבולת שהוקצתה לה ורמת הביצועים שלה. נפח האחסון מוקצה בגיביבייט (GiB) והרמות מדורגות בטביבייט (TiB), ולכן צריך קודם להמיר את הנפח:

(Capacity GiB / 1024) * Tier MBps = Theoretical Max MBps

לדוגמה, מופע של 216,000 GiB ברמה של 500 MBps לכל TiB מספק תפוקה של 105,469 MBps ((216000 / 1024) * 500).

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

סיבות נפוצות לכך שמהירויות ההשוואה לא מגיעות למהירויות התיאורטיות:

  • תקורה של TCP/IP: הכמסה סטנדרטית של רשת וראשי חבילות צורכים בערך 5-10% מרוחב הפס הגולמי. הערך המקסימלי המתמטי כולל את התקורה הזו, אבל מדד ה-IOR בודק רק את המטען הייעודי (payload) הגולמי שנכתב בדיסק.

  • מגבלות ברשת הלקוח: למחשבי הלקוח יש מגבלות חמורות על רוחב הפס של התעבורה היוצאת. אם משתמשים במספר קטן של לקוחות או צמתים, או בסוגי מכונות בלי שהופעלה רשת Tier 1, הלקוחות יגבילו את הביצועים של הבדיקה לפני שמערכת הקבצים המנוהלת של Lustre תגיע למגבלה שלה.

  • החלפת הקשר של MPI: אם הערך של PROCESSES_PER_NODE גבוה ממספר הליבות הפיזיות במכונות הלקוח, התחרות על משאבי ה-CPU והתקורה של החלפת ההקשר יפגעו באופן מלאכותי בביצועי הקלט/פלט של הבדיקה.

  • חסר Direct I/O: אם לא מציינים את הדגל --posix.odirect, הנתונים עוברים דרך מטמון הדפים ב-RAM של הלקוח. הדבר יוצר צווארי בקבוק בזיכרון ותקורת מעבד שמסתירים את הביצועים האמיתיים של אחסון הרשת.

הסרת המשאבים

כדי לא לצבור חיובים בחשבון Google Cloud על המשאבים שבהם השתמשתם בדף הזה:

  1. מוחקים את קובצי הבדיקה מהנפח המנוהל של Lustre:

    ssh -i ./id_rsa -o "StrictHostKeyChecking=no" -o UserKnownHostsFile=/dev/null ${SSH_USER}@${HEAD_NODE} "rm -rf /lustre/test"
    
  2. מחיקת מכונות לקוח ב-Compute Engine שנוצרו בכמות גדולה:

    gcloud compute instances delete $(gcloud compute instances list \
      --filter="name~'^${CLIENT_PREFIX}-'" --format="value(name)" --zones="ZONE") \
      --zone="ZONE"
    

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

    gcloud compute instances delete CLIENT_PREFIX-0001 CLIENT_PREFIX-0002 ... --zone=ZONE
    
  3. אם יצרתם תמונה בהתאמה אישית, אתם יכולים למחוק אותה:

    gcloud compute images delete CUSTOM_IMAGE_NAME
    
  4. אם יצרתם את מכונת Managed Lustre במיוחד לבדיקה הזו וכבר אין לכם צורך בה, אתם יכולים למחוק אותה:

    gcloud lustre instances delete INSTANCE_ID --location=LOCATION
    

פתרון בעיות נפוצות שקשורות לצווארי בקבוק בהשוואה לשוק

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