ابزاری برای عملکرد بهتر در برنامه شما در Go (قسمت 2: نمایه ساز)

1. مقدمه

e0509e8a07ad5537.png

آخرین به روز رسانی: 2022-07-14

قابلیت مشاهده برنامه

مشاهده‌پذیری و نمایه‌ساز پیوسته

مشاهده پذیری اصطلاحی است که برای توصیف یک ویژگی از یک سیستم استفاده می شود. یک سیستم با قابلیت مشاهده به تیم ها اجازه می دهد تا به طور فعال سیستم خود را اشکال زدایی کنند. در آن زمینه، سه رکن مشاهده پذیری; گزارش‌ها، متریک‌ها و ردیابی‌ها ابزار اساسی سیستم برای به دست آوردن قابلیت مشاهده هستند.

همچنین علاوه بر سه رکن مشاهده‌پذیری، نمایه‌سازی پیوسته یکی دیگر از مؤلفه‌های کلیدی برای مشاهده‌پذیری است و پایگاه کاربران را در صنعت گسترش می‌دهد . Cloud Profiler یکی از مبتکران است و یک رابط کاربری آسان برای بررسی معیارهای عملکرد در پشته های تماس برنامه ارائه می دهد.

این کد لبه قسمت 2 از سری است و ابزار دقیق یک عامل پروفایلر پیوسته را پوشش می دهد. قسمت 1 ردیابی توزیع شده را با OpenTelemetry و Cloud Trace پوشش می دهد و با قسمت 1 درباره شناسایی بهتر گلوگاه میکروسرویس ها بیشتر خواهید آموخت.

چیزی که خواهی ساخت

در این لبه کد، می‌خواهید عامل پروفایل‌ساز پیوسته را در سرویس سرور «برنامه Shakespeare» (معروف به Shakesapp) که روی خوشه Google Kubernetes Engine اجرا می‌شود، ابزار کنید. معماری Shakesapp به شرح زیر است:

44e243182ced442f.png

  • Loadgen یک رشته پرس و جو را در HTTP برای مشتری ارسال می کند
  • کلاینت ها از طریق پرس و جو از بارگذار به سرور در gRPC عبور می کنند
  • سرور درخواست مشتری را می‌پذیرد، همه آثار Shakespare را در قالب متن از Google Cloud Storage واکشی می‌کند، خطوطی را که حاوی پرس و جو هستند جستجو می‌کند و شماره خطی را که مطابقت دارد به مشتری برمی‌گرداند.

در قسمت 1، متوجه شدید که گلوگاه در جایی در سرویس سرور وجود دارد، اما نتوانستید علت دقیق آن را شناسایی کنید.

چیزی که یاد خواهید گرفت

  • نحوه تعبیه عامل پروفایلر
  • نحوه بررسی گردن بطری در Cloud Profiler

این کد لبه توضیح می‌دهد که چگونه یک عامل نمایه‌ساز پیوسته را در برنامه خود ابزارسازی کنید.

آنچه شما نیاز دارید

  • دانش اولیه Go
  • دانش اولیه Kubernetes

2. راه اندازی و الزامات

تنظیم محیط خود به خود

اگر قبلاً یک حساب Google (Gmail یا Google Apps) ندارید، باید یک حساب ایجاد کنید . به کنسول Google Cloud Platform ( consol.cloud.google.com ) وارد شوید و یک پروژه جدید ایجاد کنید.

اگر قبلاً پروژه ای دارید، روی منوی کشویی انتخاب پروژه در سمت چپ بالای کنسول کلیک کنید:

7a32e5469db69e9.png

و روی دکمه "پروژه جدید" در گفتگوی حاصل کلیک کنید تا یک پروژه جدید ایجاد کنید:

7136b3ee36ebaf89.png

اگر قبلاً پروژه ای ندارید، باید یک دیالوگ مانند این را ببینید تا اولین پروژه خود را ایجاد کنید:

870a3cbd6541ee86.png

گفتگوی بعدی ایجاد پروژه به شما امکان می دهد جزئیات پروژه جدید خود را وارد کنید:

affdc444517ba805.png

شناسه پروژه را به خاطر بسپارید، که یک نام منحصر به فرد در تمام پروژه های Google Cloud است (نام بالا قبلاً گرفته شده است و برای شما کار نخواهد کرد، متأسفیم!). بعداً در این آزمایشگاه کد به عنوان PROJECT_ID نامیده خواهد شد.

در مرحله بعد، اگر قبلاً این کار را انجام نداده اید، برای استفاده از منابع Google Cloud و فعال کردن Cloud Trace API، باید صورتحساب را در Developers Console فعال کنید .

15d0ef27a8fbab27.png

گذراندن این کد نباید بیش از چند دلار هزینه داشته باشد، اما اگر تصمیم به استفاده از منابع بیشتری داشته باشید یا آنها را در حال اجرا رها کنید، ممکن است بیشتر باشد (به بخش "پاکسازی" در انتهای این سند مراجعه کنید). قیمت‌های Google Cloud Trace، Google Kubernetes Engine و Google Artifact Registry در اسناد رسمی ذکر شده است.

کاربران جدید Google Cloud Platform واجد شرایط استفاده آزمایشی رایگان 300 دلاری هستند که باید این نرم افزار کد را کاملاً رایگان کند.

Google Cloud Shell Setup

در حالی که Google Cloud و Google Cloud Trace می‌توانند از راه دور از لپ‌تاپ شما کار کنند، در این نرم‌افزار از Google Cloud Shell استفاده می‌کنیم، یک محیط خط فرمان که در Cloud اجرا می‌شود.

این ماشین مجازی مبتنی بر دبیان با تمام ابزارهای توسعه که شما نیاز دارید بارگذاری شده است. این دایرکتوری اصلی 5 گیگابایتی دائمی را ارائه می دهد و در Google Cloud اجرا می شود و عملکرد شبکه و احراز هویت را بسیار افزایش می دهد. این بدان معنی است که تمام چیزی که برای این کد لبه نیاز دارید یک مرورگر است (بله، روی کروم بوک کار می کند).

برای فعال کردن Cloud Shell از Cloud Console، کافی است روی Activate Cloud Shell کلیک کنید. gcLMt5IuEcJJNnMId-Bcz3sxCd0rZn7IzT_r95C8UZeqML68Y1efBG_B0VRp7hc7qiZTLAF-TXD7SsOadxn8uadgHhaLeASnVS3ZHK_OgjogdOgdOg3ZHK39gdOg 2A (تهیه و اتصال به محیط فقط چند لحظه طول می کشد).

JjEuRXGg0AYYIY6QZ8d-66gx_Mtc-_jDE9ijmbXLJSAXFvJt-qUpNtsBsYjNpv2W6BQSrDc1D-ARINNQ-1EkwUhz-iUK-FUCZhJ-NtjkWkWE2C w

Screen Shot 2017-06-14 at 10.13.43 PM.png

پس از اتصال به Cloud Shell، باید ببینید که قبلاً احراز هویت شده اید و پروژه قبلاً روی PROJECT_ID شما تنظیم شده است.

gcloud auth list

خروجی فرمان

Credentialed accounts:
 - <myaccount>@<mydomain>.com (active)
gcloud config list project

خروجی فرمان

[core]
project = <PROJECT_ID>

اگر به دلایلی پروژه تنظیم نشد، به سادگی دستور زیر را صادر کنید:

gcloud config set project <PROJECT_ID>

به دنبال PROJECT_ID خود هستید؟ بررسی کنید از چه شناسه ای در مراحل راه اندازی استفاده کرده اید یا آن را در داشبورد Cloud Console جستجو کنید:

158fNPfwSxsFqz9YbtJVZes8viTS3d1bV4CVhij3XPxuzVFOtTObnwsphlm6lYGmgdMFwBJtc-FaLrZU7XHAg_ZYoCrgombMRR3h-eolLPcvOZwZw51

Cloud Shell همچنین برخی از متغیرهای محیطی را به صورت پیش‌فرض تنظیم می‌کند که ممکن است هنگام اجرای دستورات آینده مفید باشند.

echo $GOOGLE_CLOUD_PROJECT

خروجی فرمان

<PROJECT_ID>

در نهایت، منطقه پیش فرض و پیکربندی پروژه را تنظیم کنید.

gcloud config set compute/zone us-central1-f

شما می توانید مناطق مختلفی را انتخاب کنید. برای اطلاعات بیشتر، به مناطق و مناطق مراجعه کنید.

به تنظیمات زبان بروید

در این لبه کد از Go برای همه کدهای منبع استفاده می کنیم. دستور زیر را در Cloud Shell اجرا کنید و تأیید کنید که نسخه Go 1.17+ است یا خیر

go version

خروجی فرمان

go version go1.18.3 linux/amd64

یک خوشه Google Kubernetes راه اندازی کنید

در این کد لبه، شما مجموعه‌ای از ریزسرویس‌ها را در موتور Google Kubernetes (GKE) اجرا خواهید کرد. فرآیند این کد لبه به شرح زیر است:

  1. پروژه پایه را در Cloud Shell دانلود کنید
  2. میکروسرویس ها را در ظروف بسازید
  3. بارگذاری کانتینرها در Google Artifact Registry (GAR)
  4. کانتینرها را روی GKE مستقر کنید
  5. کد منبع خدمات را برای ابزار دقیق ردیابی تغییر دهید
  6. به مرحله 2 بروید

موتور Kubernetes را فعال کنید

ابتدا، ما یک خوشه Kubernetes را راه اندازی می کنیم که در آن Shakesapp روی GKE اجرا می شود، بنابراین باید GKE را فعال کنیم. به منوی "Kubernetes Engine" بروید و دکمه ENABLE را فشار دهید.

548cfd95bc6d344d.png

اکنون شما آماده ایجاد یک خوشه Kubernetes هستید.

خوشه Kubernetes را ایجاد کنید

در Cloud Shell، دستور زیر را برای ایجاد یک خوشه Kubernetes اجرا کنید. لطفاً تأیید کنید که مقدار منطقه زیر ناحیه ای است که برای ایجاد مخزن رجیستری مصنوع استفاده خواهید کرد. اگر منطقه مخزن شما منطقه را پوشش نمی دهد، مقدار منطقه us-central1-f را تغییر دهید.

gcloud container clusters create otel-trace-codelab2 \
--zone us-central1-f \
--release-channel rapid \
--preemptible \
--enable-autoscaling \
--max-nodes 8 \
--no-enable-ip-alias \
--scopes cloud-platform

خروجی فرمان

Note: Your Pod address range (`--cluster-ipv4-cidr`) can accommodate at most 1008 node(s).
Creating cluster otel-trace-codelab2 in us-central1-f... Cluster is being health-checked (master is healthy)...done.     
Created [https://container.googleapis.com/v1/projects/development-215403/zones/us-central1-f/clusters/otel-trace-codelab2].
To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-central1-f/otel-trace-codelab2?project=development-215403
kubeconfig entry generated for otel-trace-codelab2.
NAME: otel-trace-codelab2
LOCATION: us-central1-f
MASTER_VERSION: 1.23.6-gke.1501
MASTER_IP: 104.154.76.89
MACHINE_TYPE: e2-medium
NODE_VERSION: 1.23.6-gke.1501
NUM_NODES: 3
STATUS: RUNNING

رجیستری مصنوعات و راه اندازی اسکافولد

اکنون ما یک خوشه Kubernetes آماده برای استقرار داریم. در مرحله بعد ما برای یک رجیستری کانتینر برای کانتینرهای فشار و استقرار آماده می کنیم. برای این مراحل، باید یک Artifact Registry (GAR) و skaffold برای استفاده از آن راه اندازی کنیم.

راه اندازی رجیستری مصنوع

به منوی "Artifact Registry" بروید و دکمه ENABLE را فشار دهید.

45e384b87f7cf0db.png

پس از چند لحظه، مرورگر مخزن GAR را مشاهده خواهید کرد. روی دکمه "ایجاد مخزن" کلیک کنید و نام مخزن را وارد کنید.

d6a70f4cb4ebcbe3.png

در این codelab، من مخزن جدید trace-codelab را نام می‌برم. فرمت این مصنوع "Docker" و نوع مکان "Region" است. منطقه ای نزدیک به منطقه ای را که برای منطقه پیش فرض موتور محاسباتی Google تنظیم کرده اید، انتخاب کنید. به عنوان مثال، این مثال در بالا "us-central1-f" را انتخاب کرد، بنابراین در اینجا "us-central1 (آیووا)" را انتخاب می کنیم. سپس روی دکمه "CREATE" کلیک کنید.

9c2d1ce65258ef70.png

اکنون "trace-codelab" را در مرورگر مخزن مشاهده می کنید.

7a3c1f47346bea15.png

ما بعداً به اینجا باز خواهیم گشت تا مسیر رجیستری را بررسی کنیم.

راه اندازی داربست

Skaffold ابزاری مفید برای ساختن میکروسرویس هایی است که روی Kubernetes اجرا می شوند. گردش کار ساخت، هل دادن و استقرار کانتینرهای برنامه ها را با مجموعه کوچکی از دستورات کنترل می کند. Skaffold به طور پیش‌فرض از Docker Registry به‌عنوان رجیستری کانتینر استفاده می‌کند، بنابراین باید skaffold را برای شناسایی GAR در هنگام هل دادن کانتینرها پیکربندی کنید.

دوباره Cloud Shell را باز کنید و تأیید کنید که skaffold نصب شده است. (Cloud Shell به طور پیش فرض skaffold را در محیط نصب می کند.) دستور زیر را اجرا کنید و نسخه skaffold را ببینید.

skaffold version

خروجی فرمان

v1.38.0

اکنون، می توانید مخزن پیش فرض را برای استفاده از skaffold ثبت کنید. برای به دست آوردن مسیر رجیستری، خود را به داشبورد رجیستری Artifact بروید و روی نام مخزنی که در مرحله قبل راه اندازی کرده اید کلیک کنید.

7a3c1f47346bea15.png

سپس مسیرهای پودر سوخاری را در بالای صفحه خواهید دید. کلیک کنید e157b1359c3edc06.png برای کپی کردن مسیر رجیستری در کلیپ بورد.

e0f2ae2144880b8b.png

با کلیک بر روی دکمه کپی، گفتگو را در پایین مرورگر با پیامی مانند:

"us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab" کپی شده است

به پوسته ابر برگردید. دستور skaffold config set default-repo را با مقداری که به تازگی از داشبورد کپی کرده اید اجرا کنید.

skaffold config set default-repo us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab

خروجی فرمان

set value default-repo to us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab for context gke_stackdriver-sandbox-3438851889_us-central1-b_stackdriver-sandbox

همچنین، باید رجیستری را روی پیکربندی Docker پیکربندی کنید. دستور زیر را اجرا کنید:

gcloud auth configure-docker us-central1-docker.pkg.dev --quiet

خروجی فرمان

{
  "credHelpers": {
    "gcr.io": "gcloud",
    "us.gcr.io": "gcloud",
    "eu.gcr.io": "gcloud",
    "asia.gcr.io": "gcloud",
    "staging-k8s.gcr.io": "gcloud",
    "marketplace.gcr.io": "gcloud",
    "us-central1-docker.pkg.dev": "gcloud"
  }
}
Adding credentials for: us-central1-docker.pkg.dev

اکنون می‌توانید مرحله بعدی را برای راه‌اندازی یک ظرف Kubernetes در GKE انجام دهید.

خلاصه

در این مرحله، محیط Codelab خود را تنظیم می کنید:

  • Cloud Shell را راه اندازی کنید
  • یک مخزن رجیستری Artifact برای رجیستری کانتینر ایجاد کرد
  • برای استفاده از رجیستری کانتینر، skaffold را تنظیم کنید
  • یک خوشه Kubernetes ایجاد کرد که در آن میکروسرویس های Codelab اجرا می شوند

بعدی

در مرحله بعد عامل پروفایل پیوسته را در سرویس سرور ابزار می کنید.

3. ساخت، فشار دادن و استقرار میکروسرویس ها

مطالب Codelab را دانلود کنید

در مرحله قبل تمام پیش نیازهای این کد لبه را تنظیم کرده ایم. اکنون شما آماده هستید تا کل میکروسرویس ها را روی آنها اجرا کنید. مواد Codelab در GitHub میزبانی می شوند، بنابراین آنها را با دستور git زیر در محیط Cloud Shell دانلود کنید.

cd ~
git clone https://github.com/ymotongpoo/opentelemetry-trace-codelab-go.git
cd opentelemetry-trace-codelab-go

ساختار دایرکتوری پروژه به صورت زیر است:

.
├── README.md
├── step0
│   ├── manifests
│   ├── proto
│   ├── skaffold.yaml
│   └── src
├── step1
│   ├── manifests
│   ├── proto
│   ├── skaffold.yaml
│   └── src
├── step2
│   ├── manifests
│   ├── proto
│   ├── skaffold.yaml
│   └── src
├── step3
│   ├── manifests
│   ├── proto
│   ├── skaffold.yaml
│   └── src
├── step4
│   ├── manifests
│   ├── proto
│   ├── skaffold.yaml
│   └── src
├── step5
│   ├── manifests
│   ├── proto
│   ├── skaffold.yaml
│   └── src
└── step6
    ├── manifests
    ├── proto
    ├── skaffold.yaml
    └── src
  • manifests: فایل های مانیفست Kubernetes
  • proto: تعریف پروتو برای ارتباط بین مشتری و سرور
  • src: دایرکتوری برای کد منبع هر سرویس
  • skaffold.yaml: فایل پیکربندی برای skaffold

در این لبه کد، کد منبع واقع در پوشه step4 را به روز می کنید. همچنین می توانید برای تغییرات از ابتدا به کد منبع در پوشه های step[1-6] مراجعه کنید. (قسمت 1 مرحله 0 تا 4 را پوشش می دهد و قسمت 2 مرحله 5 و 6 را پوشش می دهد)

دستور skaffold را اجرا کنید

در نهایت شما آماده ساخت، فشار دادن و استقرار کل محتوا در خوشه Kubernetes هستید که به تازگی ایجاد کرده اید. به نظر می رسد که شامل چندین مرحله است، اما واقعیت این است که skaffold همه چیز را برای شما انجام می دهد. بیایید آن را با دستور زیر امتحان کنیم:

cd step4
skaffold dev

به محض اجرای دستور، خروجی لاگ docker build را مشاهده می کنید و می توانید تأیید کنید که آنها با موفقیت به رجیستری منتقل شده اند.

خروجی فرمان

...
---> Running in c39b3ea8692b
 ---> 90932a583ab6
Successfully built 90932a583ab6
Successfully tagged us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice:step1
The push refers to repository [us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice]
cc8f5a05df4a: Preparing
5bf719419ee2: Preparing
2901929ad341: Preparing
88d9943798ba: Preparing
b0fdf826a39a: Preparing
3c9c1e0b1647: Preparing
f3427ce9393d: Preparing
14a1ca976738: Preparing
f3427ce9393d: Waiting
14a1ca976738: Waiting
3c9c1e0b1647: Waiting
b0fdf826a39a: Layer already exists
88d9943798ba: Layer already exists
f3427ce9393d: Layer already exists
3c9c1e0b1647: Layer already exists
14a1ca976738: Layer already exists
2901929ad341: Pushed
5bf719419ee2: Pushed
cc8f5a05df4a: Pushed
step1: digest: sha256:8acdbe3a453001f120fb22c11c4f6d64c2451347732f4f271d746c2e4d193bbe size: 2001

پس از فشار دادن تمام کانتینرهای سرویس، استقرار Kubernetes به طور خودکار شروع می شود.

خروجی فرمان

sha256:b71fce0a96cea08075dc20758ae561cf78c83ff656b04d211ffa00cedb77edf8 size: 1997
Tags used in deployment:
 - serverservice -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/serverservice:step4@sha256:8acdbe3a453001f120fb22c11c4f6d64c2451347732f4f271d746c2e4d193bbe
 - clientservice -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/clientservice:step4@sha256:b71fce0a96cea08075dc20758ae561cf78c83ff656b04d211ffa00cedb77edf8
 - loadgen -> us-central1-docker.pkg.dev/psychic-order-307806/trace-codelab/loadgen:step4@sha256:eea2e5bc8463ecf886f958a86906cab896e9e2e380a0eb143deaeaca40f7888a
Starting deploy...
 - deployment.apps/clientservice created
 - service/clientservice created
 - deployment.apps/loadgen created
 - deployment.apps/serverservice created
 - service/serverservice created

پس از استقرار، گزارش‌های واقعی برنامه را خواهید دید که به stdout در هر کانتینر ارسال می‌شوند:

خروجی فرمان

[client] 2022/07/14 06:33:15 {"match_count":3040}
[loadgen] 2022/07/14 06:33:15 query 'love': matched 3040
[client] 2022/07/14 06:33:15 {"match_count":3040}
[loadgen] 2022/07/14 06:33:15 query 'love': matched 3040
[client] 2022/07/14 06:33:16 {"match_count":3040}
[loadgen] 2022/07/14 06:33:16 query 'love': matched 3040
[client] 2022/07/14 06:33:19 {"match_count":463}
[loadgen] 2022/07/14 06:33:19 query 'tear': matched 463
[loadgen] 2022/07/14 06:33:20 query 'world': matched 728
[client] 2022/07/14 06:33:20 {"match_count":728}
[client] 2022/07/14 06:33:22 {"match_count":463}
[loadgen] 2022/07/14 06:33:22 query 'tear': matched 463

توجه داشته باشید که در این مرحله، می خواهید هر پیامی را از سرور مشاهده کنید. خوب، در نهایت شما آماده اید تا برنامه خود را با OpenTelemetry برای ردیابی توزیع شده سرویس ها شروع کنید.

قبل از شروع ابزار دقیق سرویس، لطفاً کلاستر خود را با Ctrl-C خاموش کنید.

خروجی فرمان

...
[client] 2022/07/14 06:34:57 {"match_count":1}
[loadgen] 2022/07/14 06:34:57 query 'what's past is prologue': matched 1
^CCleaning up...
 - W0714 06:34:58.464305   28078 gcp.go:120] WARNING: the gcp auth plugin is deprecated in v1.22+, unavailable in v1.25+; use gcloud instead.
 - To learn more, consult https://cloud.google.com/blog/products/containers-kubernetes/kubectl-auth-changes-in-gke
 - deployment.apps "clientservice" deleted
 - service "clientservice" deleted
 - deployment.apps "loadgen" deleted
 - deployment.apps "serverservice" deleted
 - service "serverservice" deleted

خلاصه

در این مرحله، مواد Codelab را در محیط خود آماده کرده اید و طبق انتظار اجراهای skaffold را تأیید کرده اید.

بعدی

در مرحله بعد، کد منبع سرویس loadgen را برای ابزار دقیق اطلاعات ردیابی تغییر می دهید.

4. ابزار دقیق عامل Cloud Profiler

مفهوم پروفایل سازی مداوم

قبل از توضیح مفهوم پروفایل پیوسته، ابتدا باید مفهوم پروفایل سازی را درک کنیم. پروفایل سازی یکی از روش های تحلیل پویا برنامه (تحلیل برنامه پویا) است و معمولاً در حین توسعه برنامه در فرآیند تست بار و غیره انجام می شود. این یک فعالیت تک شات برای اندازه گیری معیارهای سیستم، مانند استفاده از CPU و حافظه، در طول دوره خاص است. پس از جمع آوری داده های نمایه، توسعه دهندگان آنها را از روی کد تجزیه و تحلیل می کنند.

نمایه سازی پیوسته رویکرد توسعه یافته نمایه سازی معمولی است: نمایه های پنجره کوتاه را به صورت دوره ای در برابر برنامه طولانی اجرا می کند و مجموعه ای از داده های نمایه را جمع آوری می کند. سپس به طور خودکار تجزیه و تحلیل آماری را بر اساس ویژگی خاصی از برنامه، مانند شماره نسخه، منطقه استقرار، زمان اندازه گیری و غیره تولید می کند. جزئیات بیشتر این مفهوم را در مستندات ما خواهید یافت.

از آنجایی که هدف یک برنامه کاربردی در حال اجرا است، راهی برای جمع‌آوری دوره‌ای داده‌های نمایه و ارسال آن‌ها به پشتیبان‌هایی که داده‌های آماری را پس از پردازش می‌کنند، وجود دارد. این عامل Cloud Profiler است و شما به زودی آن را در سرویس سرور جاسازی خواهید کرد.

جاسازی عامل Cloud Profiler

Cloud Shell Editor را با فشار دادن دکمه باز کنید 776a11bfb2122549.png در سمت راست بالای Cloud Shell. step4/src/server/main.go را از اکسپلورر در سمت چپ باز کنید و تابع اصلی را پیدا کنید.

step4/src/server/main.go

func main() {
        ...
        // step2. setup OpenTelemetry
        tp, err := initTracer()
        if err != nil {
                log.Fatalf("failed to initialize TracerProvider: %v", err)
        }
        defer func() {
                if err := tp.Shutdown(context.Background()); err != nil {
                        log.Fatalf("error shutting down TracerProvider: %v", err)
                }
        }()
        // step2. end setup

        svc := NewServerService()
        // step2: add interceptor
        interceptorOpt := otelgrpc.WithTracerProvider(otel.GetTracerProvider())
        srv := grpc.NewServer(
                grpc.UnaryInterceptor(otelgrpc.UnaryServerInterceptor(interceptorOpt)),
                grpc.StreamInterceptor(otelgrpc.StreamServerInterceptor(interceptorOpt)),
        )
        // step2: end adding interceptor
        shakesapp.RegisterShakespeareServiceServer(srv, svc)
        healthpb.RegisterHealthServer(srv, svc)
        if err := srv.Serve(lis); err != nil {
                log.Fatalf("error serving server: %v", err)
        }
}

در تابع main ، مقداری کد راه‌اندازی برای OpenTelemetry و gRPC را مشاهده می‌کنید، که در قسمت 1 Codelab انجام شده است. اکنون ابزار دقیق برای عامل Cloud Profiler را در اینجا اضافه خواهید کرد. مانند کاری که برای initTracer() انجام دادیم، می توانید تابعی به نام initProfiler() برای خوانایی بنویسید.

step4/src/server/main.go

import (
        ...
        "cloud.google.com/go/profiler" // step5. add profiler package
        "cloud.google.com/go/storage"
        ...
)

// step5: add Profiler initializer
func initProfiler() {
        cfg := profiler.Config{
                Service:              "server",
                ServiceVersion:       "1.0.0",
                NoHeapProfiling:      true,
                NoAllocProfiling:     true,
                NoGoroutineProfiling: true,
                NoCPUProfiling:       false,
        }
        if err := profiler.Start(cfg); err != nil {
                log.Fatalf("failed to launch profiler agent: %v", err)
        }
}

بیایید نگاهی دقیق به گزینه های مشخص شده در شی profiler.Config{} بیاندازیم.

  • Service : نام سرویسی که می توانید انتخاب کنید و داشبورد پروفایلر را روشن کنید
  • ServiceVersion : نام نسخه سرویس. می توانید مجموعه داده های نمایه را بر اساس این مقدار مقایسه کنید.
  • NoHeapProfiling : غیرفعال کردن پروفایل مصرف حافظه
  • NoAllocProfiling : غیرفعال کردن پروفایل تخصیص حافظه
  • NoGoroutineProfiling : غیرفعال کردن پروفایل گوروتین
  • NoCPUProfiling : غیرفعال کردن پروفایل CPU

در این کد لبه، ما فقط پروفایل CPU را فعال می کنیم.

اکنون کاری که باید انجام دهید این است که فقط این تابع را در تابع main فراخوانی کنید. مطمئن شوید که بسته Cloud Profiler را در بلوک واردات وارد کرده اید.

step4/src/server/main.go

func main() {
        ...
        defer func() {
                if err := tp.Shutdown(context.Background()); err != nil {
                        log.Fatalf("error shutting down TracerProvider: %v", err)
                }
        }()
        // step2. end setup

        // step5. start profiler
        go initProfiler()
        // step5. end

        svc := NewServerService()
        // step2: add interceptor
        ...
}

توجه داشته باشید که تابع initProfiler() را با کلمه کلیدی go فراخوانی می کنید. از آنجایی که profiler.Start() را مسدود می کند، بنابراین باید آن را در گوروتین دیگری اجرا کنید. اکنون آماده ساخت است. حتماً قبل از استقرار go mod tidy اجرا کنید.

go mod tidy

اکنون کلاستر خود را با سرویس سرور جدید خود مستقر کنید.

skaffold dev

معمولاً چند دقیقه طول می کشد تا نمودار شعله را در Cloud Profiler ببینید. در کادر جستجو در بالا، "profiler" را تایپ کنید و روی نماد Profiler کلیک کنید.

3d8ca8a64b267a40.png

سپس نمودار شعله زیر را خواهید دید.

7f80797dddc0128d.png

خلاصه

در این مرحله، عامل Cloud Profiler را در سرویس سرور جاسازی کردید و تأیید کردید که نمودار شعله ایجاد می کند.

بعدی

در مرحله بعد علت گلوگاه در اپلیکیشن را با نمودار شعله بررسی می کنید.

5. نمودار شعله Cloud Profiler را تجزیه و تحلیل کنید

Flame Graph چیست؟

Flame Graph یکی از راه های تجسم داده های پروفایل است. برای توضیح دقیق، لطفاً به سند ما مراجعه کنید، اما خلاصه کوتاه این است:

  • هر نوار فراخوانی روش/تابع را در برنامه بیان می کند
  • جهت عمودی پشته تماس است. پشته تماس از بالا به پایین رشد می کند
  • جهت افقی استفاده از منابع است. هر چه طولانی تر، بدتر

با توجه به آن، بیایید به نمودار شعله به دست آمده نگاه کنیم.

7f80797dddc0128d.png

تجزیه و تحلیل نمودار شعله

در بخش قبل، یاد گرفتید که هر نوار در نمودار شعله، فراخوانی تابع/روش را بیان می‌کند و طول آن به معنای استفاده از منابع در تابع/روش است. نمودار شعله Cloud Profiler نوار را به ترتیب نزولی یا طول را از چپ به راست مرتب می کند، می توانید ابتدا به سمت چپ بالای نمودار نگاه کنید.

6d90760c6c1183cd.png

در مورد ما، واضح است که grpc.(*Server).serveStreams.func1.2 بیشترین زمان CPU را مصرف می کند، و با نگاه کردن به پشته تماس از بالا به پایین، بیشتر زمان صرف می شود. main.(*serverService).GetMatchCount که کنترل کننده سرور gRPC در سرویس سرور است.

در زیر GetMatchCount، یک سری توابع regexp را مشاهده می کنید: regexp.MatchString و regexp.Compile . آنها از بسته استاندارد هستند: یعنی باید از بسیاری از دیدگاه ها، از جمله عملکرد، به خوبی آزمایش شوند. اما نتیجه اینجا نشان می دهد که استفاده از منابع زمانی CPU در regexp.MatchString و regexp.Compile زیاد است. با توجه به این حقایق، فرض در اینجا این است که استفاده از regexp.MatchString ارتباطی با مشکلات عملکرد دارد. بنابراین بیایید کد منبع را که در آن تابع استفاده می شود، بخوانیم.

step4/src/server/main.go

func (s *serverService) GetMatchCount(ctx context.Context, req *shakesapp.ShakespeareRequest) (*shakesapp.ShakespeareResponse, error) {
        resp := &shakesapp.ShakespeareResponse{}
        texts, err := readFiles(ctx, bucketName, bucketPrefix)
        if err != nil {
                return resp, fmt.Errorf("fails to read files: %s", err)
        }
        for _, text := range texts {
                for _, line := range strings.Split(text, "\n") {
                        line, query := strings.ToLower(line), strings.ToLower(req.Query)
                        isMatch, err := regexp.MatchString(query, line)
                        if err != nil {
                                return resp, err
                        }
                        if isMatch {
                                resp.MatchCount++
                        }
                }
        }
        return resp, nil
}

این جایی است که regexp.MatchString فراخوانی می شود. با خواندن کد منبع، ممکن است متوجه شوید که تابع در داخل حلقه for تو در تو فراخوانی می شود. بنابراین استفاده از این تابع ممکن است نادرست باشد. بیایید GoDoc regexp را جستجو کنیم.

80b8a4ba1931ff7b.png

طبق این سند، regexp.MatchString الگوی عبارت منظم را در هر فراخوانی کامپایل می کند. بنابراین دلیل مصرف زیاد منابع اینگونه به نظر می رسد.

خلاصه

در این مرحله شما با تجزیه و تحلیل نمودار شعله، علت مصرف منابع را فرض کردید.

بعدی

در مرحله بعد سورس کد سرویس سرور را به روز کرده و تغییر از نسخه 1.0.0 را تایید می کنید.

6. کد منبع را به روز کنید و نمودارهای شعله را متفاوت کنید

کد منبع را به روز کنید

در مرحله قبل، شما این فرض را داشتید که استفاده از regexp.MatchString ارتباطی با مصرف زیاد منابع دارد. پس بیایید این را حل کنیم. کد را باز کنید و آن قسمت را کمی تغییر دهید.

step4/src/server/main.go

func (s *serverService) GetMatchCount(ctx context.Context, req *shakesapp.ShakespeareRequest) (*shakesapp.ShakespeareResponse, error) {
        resp := &shakesapp.ShakespeareResponse{}
        texts, err := readFiles(ctx, bucketName, bucketPrefix)
        if err != nil {
                return resp, fmt.Errorf("fails to read files: %s", err)
        }

        // step6. considered the process carefully and naively tuned up by extracting
        // regexp pattern compile process out of for loop.
        query := strings.ToLower(req.Query)
        re := regexp.MustCompile(query)
        for _, text := range texts {
                for _, line := range strings.Split(text, "\n") {
                        line = strings.ToLower(line)
                        isMatch := re.MatchString(line)
                        // step6. done replacing regexp with strings
                        if isMatch {
                                resp.MatchCount++
                        }
                }
        }
        return resp, nil
}

همانطور که می بینید، اکنون فرآیند کامپایل الگوی regexp از regexp.MatchString استخراج می شود و از حلقه for تو در تو خارج می شود.

قبل از استقرار این کد، مطمئن شوید که رشته نسخه را در تابع initProfiler() به روز کنید.

step4/src/server/main.go

func initProfiler() {
        cfg := profiler.Config{
                Service:              "server",
                ServiceVersion:       "1.1.0", // step6. update version
                NoHeapProfiling:      true,
                NoAllocProfiling:     true,
                NoGoroutineProfiling: true,
                NoCPUProfiling:       false,
        }
        if err := profiler.Start(cfg); err != nil {
                log.Fatalf("failed to launch profiler agent: %v", err)
        }
}

حالا بیایید ببینیم چگونه کار می کند. کلاستر را با دستور skaffold مستقر کنید.

skaffold dev

و بعد از مدتی داشبورد Cloud Profiler را دوباره بارگذاری کنید و ببینید که چگونه است.

283cfcd4c13716ad.png

مطمئن شوید که نسخه را به "1.1.0" تغییر دهید تا فقط پروفایل های نسخه 1.1.0 را ببینید. همانطور که می توانید بگویید، طول نوار GetMatchCount کاهش یافت و نسبت استفاده از زمان CPU (یعنی نوار کوتاه تر شد).

e3a1456b4aada9a5.png

نه تنها با نگاه کردن به نمودار شعله یک نسخه، بلکه می توانید تفاوت های بین دو نسخه را نیز مقایسه کنید.

841dec77d8ba5595.png

مقدار لیست کشویی "Compare to" را به "Version" تغییر دهید و مقدار "Compared version" را به "1.0.0"، نسخه اصلی تغییر دهید.

5553844292d6a537.png

این نوع نمودار شعله را خواهید دید. شکل نمودار مانند 1.1.0 است اما رنگ آمیزی آن متفاوت است. در حالت مقایسه ، معنی رنگ این است:

  • آبی : مقدار (مصرف منابع) کاهش یافته است
  • نارنجی : مقدار (مصرف منابع) به دست آمده
  • خاکستری : خنثی

با توجه به افسانه، اجازه دهید نگاهی دقیق تر به عملکرد بیندازیم. با کلیک بر روی نواری که می خواهید بزرگنمایی کنید، می توانید جزئیات بیشتری را در داخل پشته مشاهده کنید. لطفاً بر روی main.(*serverService).GetMatchCount نوار GetMatchCount کلیک کنید. همچنین با حرکت بر روی نوار، جزئیات مقایسه را مشاهده خواهید کرد.

ca08d942dc1e2502.png

می گوید زمان کل CPU از 5.26 ثانیه به 2.88 ثانیه کاهش می یابد (کل 10 ثانیه = پنجره نمونه برداری). این یک پیشرفت بزرگ است!

اکنون می توانید عملکرد برنامه خود را از تجزیه و تحلیل داده های نمایه بهبود ببخشید.

خلاصه

در این مرحله، شما یک ویرایش در سرویس سرور انجام دادید و بهبود حالت مقایسه Cloud Profiler را تایید کردید.

بعدی

در مرحله بعد سورس کد سرویس سرور را به روز کرده و تغییر از نسخه 1.0.0 را تایید می کنید.

7. مرحله اضافی: بهبود در Trace waterfall را تایید کنید

تفاوت بین ردیابی توزیع شده و پروفایل پیوسته

در قسمت 1 از Codelab، تأیید کردید که می‌توانید سرویس تنگنا را در میان میکروسرویس‌ها برای یک مسیر درخواست کشف کنید و نمی‌توانید علت دقیق گلوگاه را در سرویس خاص کشف کنید. در این قسمت 2 کد لبه، شما آموخته اید که پروفایل سازی مداوم شما را قادر می سازد تا گلوگاه داخل سرویس واحد را از پشته های تماس شناسایی کنید.

در این مرحله، بیایید نمودار آبشار را از روی ردیابی توزیع شده (Cloud Trace) مرور کنیم و تفاوت آن را با پروفایل پیوسته ببینیم.

این نمودار آبشار یکی از ردیابی های با پرس و جو "عشق" است. در کل حدود 6.7 ثانیه (6700 میلی ثانیه) طول می کشد.

e2b7dec25926ee51.png

و این پس از بهبود برای همان پرس و جو است. همانطور که می گویید، کل تاخیر اکنون 1.5 ثانیه (1500 میلی ثانیه) است که نسبت به اجرای قبلی پیشرفت بسیار زیادی دارد.

feeb7207f36c7e5e.png

نکته مهم در اینجا این است که در نمودار آبشار ردیابی توزیع شده، اطلاعات پشته تماس در دسترس نیست مگر اینکه ابزار شما در همه جا بچرخد. همچنین ردیابی‌های توزیع‌شده فقط بر تأخیر بین سرویس‌ها تمرکز می‌کنند، در حالی که نمایه‌سازی مداوم بر منابع رایانه (CPU، حافظه، رشته‌های سیستم‌عامل) یک سرویس متمرکز است.

از جنبه دیگر، ردیابی توزیع شده پایه رویداد است، مشخصات پیوسته آماری است. هر ردیابی نمودار تاخیر متفاوتی دارد و برای دریافت روند تغییرات تاخیر به فرمت متفاوتی مانند توزیع نیاز دارید.

خلاصه

در این مرحله، تفاوت بین ردیابی توزیع شده و پروفایل پیوسته را بررسی کردید.

8. تبریک می گویم

شما با موفقیت ردیابی های توزیع شده را با OpenTelemery ایجاد کردید و تاخیرهای درخواستی را در سراسر میکروسرویس در Google Cloud Trace تأیید کردید.

برای تمرین های طولانی، می توانید موضوعات زیر را خودتان امتحان کنید.

  • پیاده سازی کنونی تمام دهانه های ایجاد شده توسط بررسی سلامت را ارسال می کند. ( grpc.health.v1.Health/Check ) چگونه این گستره ها را از Cloud Traces فیلتر می کنید؟ اشاره اینجاست .
  • گزارش‌های رویداد را با دهانه‌ها مرتبط کنید و ببینید که چگونه در Google Cloud Trace و Google Cloud Logging کار می‌کند. اشاره اینجاست .
  • برخی از خدمات را با سرویسی به زبان دیگری جایگزین کنید و سعی کنید آن را با OpenTelemetry برای آن زبان ابزار کنید.

همچنین، اگر می‌خواهید پس از این در مورد پروفایل‌کننده اطلاعات کسب کنید، لطفاً به قسمت 2 بروید. در آن صورت می‌توانید از بخش پاک‌سازی زیر صرفنظر کنید.

تمیز کردن

پس از این کد، لطفاً خوشه Kubernetes را متوقف کنید و مطمئن شوید که پروژه را حذف کرده‌اید تا هزینه‌های غیرمنتظره‌ای در Google Kubernetes Engine، Google Cloud Trace، Google Artifact Registry دریافت نکنید.

ابتدا کلاستر را حذف کنید. اگر کلاستر را با skaffold dev اجرا می کنید، فقط باید Ctrl-C را فشار دهید. اگر کلاستر را با skaffold run اجرا می کنید، دستور زیر را اجرا کنید:

skaffold delete

خروجی فرمان

Cleaning up...
 - deployment.apps "clientservice" deleted
 - service "clientservice" deleted
 - deployment.apps "loadgen" deleted
 - deployment.apps "serverservice" deleted
 - service "serverservice" deleted

پس از حذف خوشه، از پنجره منو، "IAM & Admin" > "Settings" را انتخاب کنید و سپس روی دکمه "SHUT DOWN" کلیک کنید.

45aa37b7d5e1ddd1.png

سپس شناسه پروژه (نه نام پروژه) را در فرم موجود در گفتگو وارد کرده و خاموش شدن را تأیید کنید.