יצירת פרופילים של אפליקציות Go

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

.

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

  • זמן CPU (מעבד)
  • Heap
  • זיכרון בערימה שהוקצה
  • התנגשות (Go mutex)
  • שרשורים (Go goroutine)

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

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

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

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

  • Linux. יש תמיכה בפרופילים של אפליקציות Go בקרנלים של לינוקס שספריית ה-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

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

כדי להפעיל את פרופיל המתח של Mutex (האפשרות Contention בממשק), מגדירים את אפשרות ההגדרה MutexProfiling לערך true.

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

Compute Engine

ב-Compute Engine, ב-profiler.Config מגדירים את Service עם שם לשירות שמבצעים לו פרופיל, ואפשר גם להגדיר את ServiceVersion עם גרסת השירות:


// snippets is an example of starting cloud.google.com/go/profiler.
package main

import (
	"cloud.google.com/go/profiler"
)

func main() {
	cfg := profiler.Config{
		Service:        "myservice",
		ServiceVersion: "1.0.0",
		// ProjectID must be set if not running on GCP.
		// ProjectID: "my-project",

		// For OpenCensus users:
		// To see Profiler agent spans in APM backend,
		// set EnableOCTelemetry to true
		// EnableOCTelemetry: true,
	}

	// Profiler initialization, best done as early as possible.
	if err := profiler.Start(cfg); err != nil {
		// TODO: Handle error.
	}
}

אם יש לכם יחסי תלות בקוד המקור שמאוחזרים באופן ידני, יכול להיות שתצטרכו להוסיף את השורה הבאה לסקריפט הבנייה או לקובץ ה-Dockerfile:

go get cloud.google.com/go/profiler

GKE

ב-GKE, ב-profiler.Config מגדירים את Service עם שם לשירות שיוצרים לו פרופיל, ואפשר גם להגדיר את ServiceVersion עם גרסת השירות:


// snippets is an example of starting cloud.google.com/go/profiler.
package main

import (
	"cloud.google.com/go/profiler"
)

func main() {
	cfg := profiler.Config{
		Service:        "myservice",
		ServiceVersion: "1.0.0",
		// ProjectID must be set if not running on GCP.
		// ProjectID: "my-project",

		// For OpenCensus users:
		// To see Profiler agent spans in APM backend,
		// set EnableOCTelemetry to true
		// EnableOCTelemetry: true,
	}

	// Profiler initialization, best done as early as possible.
	if err := profiler.Start(cfg); err != nil {
		// TODO: Handle error.
	}
}

אם יש לכם יחסי תלות בקוד המקור שמאוחזרים באופן ידני, יכול להיות שתצטרכו להוסיף את השורה הבאה לסקריפט הבנייה או לקובץ ה-Dockerfile:

go get cloud.google.com/go/profiler

App Engine

בסביבה הגמישה של App Engine ובסביבה הרגילה של App Engine, התוספות לקוד כמעט זהות לאלה של Compute Engine ו-GKE. יש יוצא מן הכלל אחד. בשתי סביבות App Engine, הפרמטרים Service ו-ServiceVersion נגזרים מהסביבה, כך שלא צריך לציין אותם.


// appengine is an example of starting cloud.google.com/go/profiler on
// App Engine.
package main

import (
	"cloud.google.com/go/profiler"
)

func main() {
	// Profiler initialization, best done as early as possible.
	if err := profiler.Start(profiler.Config{
		// Service and ServiceVersion can be automatically inferred when running
		// on App Engine.
		// ProjectID must be set if not running on GCP.
		// ProjectID: "my-project",
	}); err != nil {
		// TODO: Handle error.
	}
}

כשמריצים את האפליקציה באופן מקומי, צריך להגדיר את הפרמטרים ProjectID (המזהה של הפרויקט) ו-Service ב-profiler.Config, כי אי אפשר להפיק אותם מסביבה מקומית.Google Cloud לא צריך להגדיר את ServiceVersion.

אם אתם משתמשים בסביבה הרגילה של App Engine, תוכלו לקרוא את המאמר העברת האפליקציה אל Go 1.11 כדי לקבל מידע מפורט על השינויים שאולי תצטרכו לבצע באפליקציה. בנוסף, אתם צריכים להשתמש ב-Google Cloud CLI בגרסה 226.0.0 ואילך. כדי לעדכן את Google Cloud CLI, מריצים את הפקודה הבאה:

gcloud components update

כדי להריץ את האפליקציה:

  1. מעדכנים את יחסי התלות:

    go get cloud.google.com/go/profiler
    
  2. פורסים את האפליקציה בסביבה הגמישה של App Engine או בסביבה הרגילה של App Engine:

    gcloud app deploy [DEPLOYMENT]
    

    DEPLOYMENT הוא הנתיב לקובץ התצורה. לדוגמה, DEPLOYMENT יכול להיות main/app.yaml.

מנתח נתונים

אחרי ש-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.

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

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

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

profiler.Start(profiler.Config{..., DebugLogging: true});

פתרון בעיות

בקטע הזה מפורטות בעיות שספציפיות ליצירת פרופילים של אפליקציות Go. אפשר לקבל עזרה בפתרון בעיות נפוצות במאמר בנושא פתרון בעיות.

התנהגות מטרה פתרון
לא נאספים פרופילים של זמן CPU לאפליקציות שנוצרו באמצעות -buildmode=c-archive. מתבצע איסוף של פרופילים של Heap,‏ contention ו-thread. בעיה ב-GitHub כברירת מחדל, פרופיל ה-CPU לא מופעל באפליקציות Go כשהדגל -buildmode הוא c-archive או c-shared. מוסיפים שיחה ל-
signal.Notify(make(
chan os.Signal), syscall.SIGPROF)
לפני שמתקשרים ל-profiler.Start.
תגובה לבעיה ב-GitHub.

הפעלה עם Linux Alpine

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

שגיאת אימות

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

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

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

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

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

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

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