יצירת פרופיל של אפליקציות Python

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

.

סוגי פרופילים ל-Python:

  • זמן CPU (מעבד)
  • זמן בפועל (thread ראשי)

גרסאות שפה נתמכות של Python:

  • ‫Python 3.6 עד 3.11.0.

גרסאות נתמכות של סוכן הפרופילים:

  • הגרסה העדכנית ביותר של הסוכן נתמכת. באופן כללי, אין תמיכה בגרסאות בנות יותר משנה. מומלץ להשתמש בגרסה העדכנית ביותר של הסוכן.

מערכות הפעלה נתמכות:

  • Linux. יש תמיכה בפרופילים של אפליקציות Python עבור ליבות Linux שהספרייה הרגילה שלהן בשפת C מיושמת באמצעות glibc או באמצעות musl. למידע על הגדרות שספציפיות לליבות של Linux Alpine, אפשר לעיין במאמר הפעלה ב-Linux Alpine.

סביבות נתמכות:

הפעלת Profiler API

לפני שמשתמשים בסוכן הפרופילים, צריך לוודא שממשק ה-Profiler API הבסיסי מופעל. אתם יכולים לבדוק את הסטטוס של ה-API ולהפעיל אותו אם צריך באמצעות Google Cloud CLI או Google Cloud המסוף:

‫CLI של gcloud

  1. אם עדיין לא התקנתם את Google Cloud CLI בתחנת העבודה, תוכלו לעיין במסמכי Google Cloud CLI.

  2. מריצים את הפקודה הבאה:

    gcloud services enable cloudprofiler.googleapis.com
    

מידע נוסף זמין במאמר gcloud services.

מסוף Google Cloud

  1. מפעילים את Cloud Profiler API.

    תפקידים שנדרשים להפעלת ממשקי API

    כדי להפעיל ממשקי API, צריך את תפקיד ה-IAM 'אדמין של Service Usage' (roles/serviceusage.serviceUsageAdmin), שכולל את ההרשאה serviceusage.services.enable. איך מקצים תפקידים

    להפעלת ה-API

  2. אם מוצג הכיתוב API enabled, סימן שממשק ה-API כבר מופעל. אם לא, לוחצים על הכפתור הפעלה.

הקצאת תפקיד IAM לחשבון שירות

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

אם אתם מבצעים אחת מהפעולות הבאות, אתם צריכים להקצות לחשבון השירות את תפקיד ה-IAM‏ Cloud Profiler Agent (roles/cloudprofiler.agent):

  1. אתם משתמשים בחשבון השירות שמוגדר כברירת מחדל, אבל שיניתם את הרשאות התפקיד שלו.
  2. אתם משתמשים בחשבון שירות שנוצר על ידי משתמש.
  3. אם אתם משתמשים ב-Workload Identity, צריך להקצות את התפקיד Cloud Profiler Agent לחשבון השירות של Kubernetes.

אפשר להקצות תפקיד IAM לחשבון שירות באמצעות מסוףGoogle Cloud או Google Cloud CLI. לדוגמה, אפשר להשתמש בפקודה gcloud projects add-iam-policy-binding:

gcloud projects add-iam-policy-binding GCP_PROJECT_ID \
    --member serviceAccount:MY_SVC_ACCT_ID@GCP_PROJECT_ID.iam.gserviceaccount.com \
    --role roles/cloudprofiler.agent

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

  • GCP_PROJECT_ID: מזהה הפרויקט.
  • MY_SVC_ACCT_ID: השם של חשבון השירות.

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

שימוש ב-Cloud Profiler

מידע על שיטות מומלצות לשימוש ב-Python מופיע במאמר הגדרת סביבת פיתוח ב-Python.

Compute Engine

ב-Compute Engine, מבצעים את הפעולות הבאות:

  1. מתקינים את הקומפיילר C/C++ ואת הכלים למפתחים:

    sudo apt-get install -y build-essential
    
  2. מתקינים את pip:

    sudo apt-get install -y python3-pip
    
  3. מתקינים את חבילת Profiler:

    pip3 install google-cloud-profiler
    
  4. מייבאים את מודול googlecloudprofiler וקוראים לפונקציה googlecloudprofiler.start מוקדם ככל האפשר בקוד האתחול:

    import googlecloudprofiler
    
    
    def main():
        # Profiler initialization. It starts a daemon thread which continuously
        # collects and uploads profiles. Best done as early as possible.
        try:
            googlecloudprofiler.start(
                service="hello-profiler",
                service_version="1.0.1",
                # verbose is the logging level. 0-error, 1-warning, 2-info,
                # 3-debug. It defaults to 0 (error) if not set.
                verbose=3,
                # project_id must be set if not running on GCP.
                # project_id='my-project-id',
            )
        except (ValueError, NotImplementedError) as exc:
            print(exc)  # Handle errors here

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

GKE

ב-GKE, מבצעים את הפעולות הבאות:

  1. משנים את קובץ ה-Dockerfile כדי להתקין את חבילת Profiler:

    FROM python:3
    ...
    RUN apt-get update && apt-get install -y build-essential python3-pip
    RUN pip3 install google-cloud-profiler
    
  2. מייבאים את מודול googlecloudprofiler וקוראים לפונקציה googlecloudprofiler.start מוקדם ככל האפשר בקוד האתחול:

    import googlecloudprofiler
    
    
    def main():
        # Profiler initialization. It starts a daemon thread which continuously
        # collects and uploads profiles. Best done as early as possible.
        try:
            googlecloudprofiler.start(
                service="hello-profiler",
                service_version="1.0.1",
                # verbose is the logging level. 0-error, 1-warning, 2-info,
                # 3-debug. It defaults to 0 (error) if not set.
                verbose=3,
                # project_id must be set if not running on GCP.
                # project_id='my-project-id',
            )
        except (ValueError, NotImplementedError) as exc:
            print(exc)  # Handle errors here

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

סביבה גמישה

בסביבה גמישה של App Engine:

  1. מוסיפים את google-cloud-profiler לקובץ requirements.txt.

  2. מייבאים את מודול googlecloudprofiler ומפעילים את הפונקציה googlecloudprofiler.start מוקדם ככל האפשר בקוד האתחול.

ב-App Engine, ההיקפים service ו-service_version נגזרים מסביבת ההפעלה. מידע על פתרון בעיות וחריגים מופיע במאמר פתרון בעיות.

סביבה רגילה

בסביבה הרגילה של App Engine, שבה צריך להשתמש בסביבת זמן הריצה של Python 3, מבצעים את הפעולות הבאות:

  1. מוסיפים את google-cloud-profiler לקובץ requirements.txt.

  2. מייבאים את מודול googlecloudprofiler ומפעילים את הפונקציה googlecloudprofiler.start מוקדם ככל האפשר בקוד האתחול.

ב-App Engine, ההיקפים service ו-service_version נגזרים מסביבת ההפעלה. מידע על פתרון בעיות וחריגים מופיע במאמר פתרון בעיות.

פונקציית start

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

פרמטר תיאור
service1 (חובה) השם של השירות שיוצרים לו פרופיל. מידע על ההגבלות על שם השירות זמין במאמר ארגומנטים של שם השירות והגרסה.
service_version1 (אופציונלי) גרסת השירות שנוצר לה פרופיל. מידע על הגבלות לגבי גרסת השירות זמין במאמר ארגומנטים של שם השירות והגרסה.
verbose (אופציונלי) רמת הרישום ביומן. פרטים על רמות הרישום ביומן זמינים במאמר בנושא רישום ביומן של סוכנים.

ערך ברירת המחדל הוא 0 (שגיאה).
project_id2 (אופציונלי) מזהה הפרויקט Google Cloud .
disable_cpu_profiling (אופציונלי) כדי להשבית את התאמה לפרופיל של זמן השימוש ביחידת העיבוד המרכזית (CPU), מגדירים את הערך disable_cpu_profiling=True.

הפרמטר הזה נתמך בגרסאות Python 3.2 עד 3.11.0. בכל שאר הגרסאות של Python, אין תמיכה בפרופיל של זמן מעבד, והמערכת מתעלמת מהפרמטר הזה.

ערך ברירת המחדל הוא False.
disable_wall_profiling (אופציונלי) כדי להשבית את יצירת הפרופיל של הקיר, מגדירים את הערך disable_wall_profiling=True.

הפרמטר הזה נתמך בגרסאות Python 3.6 עד 3.11.0. בכל שאר הגרסאות של Python, לא נתמכת יצירת פרופיל של Wall, והמערכת מתעלמת מהפרמטר הזה.

מידע על הגבלות בפונקציה start כשפרופיל הקיר מופעל מופיע במאמר בנושא מגבלות.

ערך ברירת המחדל הוא False.

‫1 רק ל-Compute Engine ול-GKE. ב-App Engine, הערך נגזר מהסביבה.
2 עבור Google Cloud, הערך נגזר מהסביבה. בסביבות שאינןGoogle Cloud , חובה לספק ערך. מידע נוסף זמין במאמר בנושא יצירת פרופילים של אפליקציות שפועלות מחוץ ל- Google Cloud.

מנתח נתונים

אחרי ש-Profiler אוסף נתונים, אפשר להציג ולנתח את הנתונים האלה באמצעות הממשק של Profiler.

נכנסים לדף Profiler במסוף Google Cloud :

עוברים אל Profiler

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

ארגומנטים של שם השירות והגרסה

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

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

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

אם משתמשים בשמות שירות שונים עבור העותקים, השירות ינותח בתדירות גבוהה מהנדרש, עם תקורה גבוהה יותר בהתאם.

כשבוחרים שם שירות:

  • בוחרים שם שמייצג בבירור את השירות בארכיטקטורת האפליקציה. בחירת שם השירות פחות חשובה אם מריצים רק שירות או אפליקציה אחת. היא חשובה יותר אם האפליקציה שלכם פועלת כקבוצה של מיקרו-שירותים, למשל.

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

  • מחרוזת service-name חייבת להתאים לביטוי הרגולרי הזה:

    ^[a-z0-9]([-a-z0-9_.]{0,253}[a-z0-9])?$

הנחיה טובה היא להשתמש במחרוזת סטטית כמו imageproc-service בתור שם השירות.

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

הערך של הארגומנט service-version הוא מחרוזת חופשית, אבל הערכים של הארגומנט הזה בדרך כלל נראים כמו מספרי גרסאות, למשל, 1.0.0 או 2.1.2.

רישום ביומן של סוכנים

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

  • 0 : שגיאה
  • 1 : אזהרה
  • 2 : לידיעה
  • 3 : ניפוי באגים

אם מגדירים את הפרמטר verbose לערך 1 בקריאה ל-start, ההודעות עם רמת חומרה Warning או Error נרשמות ביומן, והמערכת מתעלמת מהודעות Informational ו-Debug.

כדי לרשום ביומן את כל ההודעות, צריך להגדיר את הפרמטר verbose לערך 3 כשמפעילים את הנציג:

googlecloudprofiler.start(service='service_name', verbose=3)

פתרון בעיות

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

מגבלות

סוג הפרופיל הגבלות ומגבלות
זמן בפועל
  • פרופיל של ה-thread הראשי בלבד.
  • צריך להפעיל את הפונקציה start של הפרופיל מה-thread הראשי.
  • ה-handler של האותות של Profiler מופעל רק ב-thread הראשי. אם ה-main thread לא יכול לפעול, לא מתבצעת לכידה של נתוני פרופיל.

חריגים

שגיאה מטרה פתרון
NotImplementedError שנזרק במהלך start האפליקציה הופעלה בסביבה שאינה Linux.
  • מריצים את האפליקציה בסביבת Linux.
ValueError שנזרק במהלך start הארגומנטים של הפונקציה start לא תקפים, לא ניתן לקבוע את המידע הדרוש ממשתני הסביבה והארגומנטים, או שפרופיל זמן CPU (מעבד) ופרופיל זמן בפועל מושבתים.
  • מוודאים ששם השירות והגרסה עומדים בדרישות שמוגדרות במאמר ארגומנטים של שם השירות והגרסה.
  • אם הפרופיל של Wall מופעל, צריך לוודא שהפונקציה start מופעלת מה-thread הראשי.
  • מוודאים שאתם משתמשים בגרסה נתמכת של Python ושהפרופיל של זמן CPU (מעבד) או זמן בפועל מופעל. מידע נוסף זמין במאמר בנושא הפונקציה start.
  • אם אתם מפעילים את התכונה מחוץ ל- Google Cloud, צריך לוודא שציינתם את הפרמטר project_id כ-start. מידע נוסף זמין במאמר בנושא הפונקציה start.

בעיות מוכרות

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

כש-uWSGI משתמש בכמה תהליכי עבודה כדי לטפל בבקשות, התנהגות ברירת המחדל היא לבצע אתחול של האפליקציה רק בתהליך הראשי (master). התהליכים המפוצלים לא מבצעים את רצף האתחול.

אם מגדירים את סוכן הפרופילים ברצף האתחול של האפליקציה, למשל ב-AppConfig.ready() באפליקציית Django, סוכן הפרופילים לא מוגדר לתהליכים המפוצלים.

כדי לבצע אתחול של האפליקציה בכל תהליכי העובד, צריך להגדיר את הדגל lazy-apps לערך true.

בנושא הבא בטבלה מפורטת בעיה קשורה.

אתם משתמשים ב-uWSGI ואין לכם נתוני פרופיל של Wall, אבל יש לכם נתוני פרופיל של זמן CPU.

הכלי Wall profiler מסתמך על מודול האותות של Python. כשמהדרים את מתורגמן Python עם תמיכה בשרשור, ההגדרה שמוגדרת כברירת מחדל משביתה את הטיפול באותות מותאמים אישית לתהליכים מסועפים.

באפליקציות uWSGI, כדי להפעיל את הטיפול המותאם אישית באותות, צריך להגדיר את הדגל py-call-osafterfork לערך true.

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

אחרי שמפעילים את הכלי ליצירת פרופילים, יומן השגיאות מכיל רשומות חדשות:

BlockingIOError: [Errno 11] Resource temporarily unavailable Exception ignored when trying to write to the signal wakeup fd

GitHub issue

האפליקציה שלך נרשמה עם מתאר קובץ להוצאה ממצב שינה של האות, signal.set_wakeup_fd. כברירת מחדל, אם המאגר של מתאר הקובץ מתמלא, אזהרה נרשמת ב-stderr.

כש-Cloud Profiler אוסף פרופילים, הוא מפעיל אותות בתדירות גבוהה. התנהגות כזו עלולה לגרום למאגר של מתאר הקובץ להתמלא.

אם האפליקציה יכולה לפעול בצורה בטוחה כשהאותות לא מתקבלים, אפשר להשתמש ב-Cloud Profiler. אם אתם משתמשים ב-Python 3.7 ואילך ורוצים להשבית את הודעות האזהרה, צריך להעביר את warn_on_full_buffer=False כפרמטר אל signal.set_wakeup_fd.

אם האפליקציה לא יכולה לפעול בצורה בטוחה כשהאותות לא מתקבלים, מומלץ להפסיק להשתמש ב-Cloud Profiler. שימוש ממושך עלול לגרום לאובדן של מספרי האותות ולרישומים רבים מדי ביומן השגיאות.

הפעלה עם Linux Alpine

הסוכן של Python לפרופילים ב-Linux Alpine נתמך רק בהגדרות של Google Kubernetes Engine.

כדי ליצור את סוכן הפרופילים של Python, צריך להתקין את החבילה build-base. כדי להשתמש בסוכן ליצירת פרופילים של Python ב-Alpine בלי להתקין תלות נוספת בתמונת ה-Alpine הסופית, אפשר להשתמש בבנייה דו-שלבית ולהדר את הסוכן ליצירת פרופילים של Python בשלב הראשון. לדוגמה, קובץ האימג' הבא של Docker משתמש ב-build רב-שלבי כדי להדר ולהתקין את סוכן פרופיל Python:

FROM python:3.7-alpine as builder

# Install build-base to allow for compilation of the profiling agent.
RUN apk add --update --no-cache build-base

# Compile the profiling agent, generating wheels for it.
RUN pip3 wheel --wheel-dir=/tmp/wheels google-cloud-profiler

FROM python:3.7-alpine

# Copy over the directory containing wheels for the profiling agent.
COPY --from=builder /tmp/wheels /tmp/wheels

# Install the profiling agent.
RUN pip3 install --no-index --find-links=/tmp/wheels google-cloud-profiler

# Install any other required modules or dependencies, and copy an app which
# enables the profiler as described in "Enable the profiler in your
# application".
COPY ./bench.py .

# Run the application when the docker image is run, using either CMD (as is done
# here) or ENTRYPOINT.
CMD python3 -u bench.py

שגיאת אימות

אם אתם משתמשים בתמונות Docker שפועלות עם Linux Alpine (כמו golang:alpine או רק alpine), יכול להיות שתופיע שגיאת האימות הבאה:

connection error: desc = "transport: authentication handshake failed: x509: failed to load system roots and no roots provided"

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

השגיאה מציינת שבתמונות Docker עם Linux Alpine לא מותקנים אישורי ה-SSL של הבסיס כברירת מחדל. האישורים האלה נחוצים כדי שהסוכן ליצירת פרופילים יוכל לתקשר עם ה-API של הכלי ליצירת פרופילים. כדי לפתור את השגיאה, מוסיפים את הפקודה apk הבאה לקובץ Dockerfile:

FROM alpine
...
RUN apk add --no-cache ca-certificates

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

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