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

1. بررسی اجمالی

در حالی که برنامه‌نویس‌های برنامه‌های مشتری و توسعه‌دهندگان وب ظاهری معمولاً از ابزارهایی مانند نمایه‌ساز CPU Android Studio یا ابزارهای نمایه‌سازی موجود در Chrome برای بهبود عملکرد کد خود استفاده می‌کنند، تکنیک‌های معادل تقریباً توسط افرادی که روی خدمات پشتیبان کار می‌کنند در دسترس یا به خوبی مورد استفاده قرار نگرفته‌اند. Cloud Profiler این قابلیت‌ها را برای توسعه‌دهندگان خدمات ارائه می‌کند، صرف نظر از اینکه کد آن‌ها در Google Cloud Platform یا جاهای دیگر اجرا می‌شود.

95c034c70c9cac22.png

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

در این نرم افزار کد، نحوه راه اندازی Cloud Profiler برای برنامه Go را یاد خواهید گرفت و با چه نوع بینش هایی در مورد عملکرد برنامه کاربردی ابزار می تواند ارائه دهد آشنا خواهید شد.

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

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

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

  • یک پروژه Google Cloud Platform
  • یک مرورگر، مانند کروم یا فایرفاکس
  • آشنایی با ویرایشگرهای متن استاندارد لینوکس مانند Vim، EMACs یا Nano

چگونه از این آموزش استفاده خواهید کرد؟

فقط از طریق آن را بخوانید آن را بخوانید و تمرینات را کامل کنید

تجربه خود را با Google Cloud Platform چگونه ارزیابی می کنید؟

تازه کار متوسط مسلط

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

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

  1. به کنسول Cloud وارد شوید و یک پروژه جدید ایجاد کنید یا از یک موجود استفاده مجدد کنید. اگر قبلاً یک حساب Gmail یا Google Workspace ندارید، باید یک حساب ایجاد کنید .

96a9c957bc475304.png

b9a10ebdf5b5a448.png

a1e3c01a38fa61c2.png

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

  1. در مرحله بعد، برای استفاده از منابع Google Cloud، باید صورت‌حساب را در Cloud Console فعال کنید .

اجرا کردن از طریق این کد لبه نباید هزینه زیادی داشته باشد، اگر اصلاً باشد. حتماً دستورالعمل‌های موجود در بخش «تمیز کردن» را دنبال کنید که به شما توصیه می‌کند چگونه منابع را خاموش کنید تا بیش از این آموزش متحمل صورت‌حساب نشوید. کاربران جدید Google Cloud واجد شرایط برنامه آزمایشی رایگان 300 دلاری هستند.

Google Cloud Shell

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

Cloud Shell را فعال کنید

  1. از Cloud Console، روی Activate Cloud Shell کلیک کنید 4292cbf4971c9786.png .

bce75f34b2c53987.png

اگر قبلاً Cloud Shell را راه‌اندازی نکرده‌اید، یک صفحه میانی (در زیر تاشو) برای شما نمایش داده می‌شود که آن را توصیف می‌کند. اگر اینطور است، روی Continue کلیک کنید (و دیگر آن را نخواهید دید). در اینجا به نظر می رسد که آن صفحه یک بار مصرف:

70f315d7b402b476.png

تهیه و اتصال به Cloud Shell فقط باید چند لحظه طول بکشد.

fbe3a0674c982259.png

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

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

  1. برای تایید احراز هویت، دستور زیر را در Cloud Shell اجرا کنید:
gcloud auth list

خروجی فرمان

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. دستور زیر را در Cloud Shell اجرا کنید تا تأیید کنید که دستور gcloud از پروژه شما اطلاع دارد:
gcloud config list project

خروجی فرمان

[core]
project = <PROJECT_ID>

اگر اینطور نیست، می توانید آن را با این دستور تنظیم کنید:

gcloud config set project <PROJECT_ID>

خروجی فرمان

Updated property [core/project].

3. به Cloud Profiler بروید

در Cloud Console، با کلیک بر روی "Profiler" در نوار ناوبری سمت چپ، به رابط کاربری Profiler بروید:

37ad0df7ddb2ad17.png

یا می‌توانید از نوار جستجوی کنسول Cloud برای رفتن به رابط کاربری Profiler استفاده کنید: فقط «Cloud Profiler» را تایپ کنید و مورد پیدا شده را انتخاب کنید. در هر صورت، باید رابط کاربری Profiler را با پیام «عدم نمایش داده‌ای» مانند زیر ببینید. این پروژه جدید است، بنابراین هنوز هیچ داده پروفایلی جمع آوری نشده است.

d275a5f61ed31fb2.png

اکنون زمان آن است که چیزی را نمایه کنید!

4. مشخصات معیار

ما از یک برنامه ساده Go مصنوعی موجود در Github استفاده خواهیم کرد. در ترمینال Cloud Shell که هنوز باز است (و در حالی که پیام "عدم نمایش داده نیست" هنوز در رابط کاربری Profiler نشان داده شده است)، دستور زیر را اجرا کنید:

$ go get -u github.com/GoogleCloudPlatform/golang-samples/profiler/...

سپس به دایرکتوری برنامه بروید:

$ cd ~/gopath/src/github.com/GoogleCloudPlatform/golang-samples/profiler/hotapp

دایرکتوری حاوی فایل "main.go" است که یک برنامه مصنوعی است که عامل پروفایل را فعال کرده است:

main.go

...
import (
        ...
        "cloud.google.com/go/profiler"
)
...
func main() {
        err := profiler.Start(profiler.Config{
                Service:        "hotapp-service",
                DebugLogging:   true,
                MutexProfiling: true,
        })
        if err != nil {
                log.Fatalf("failed to start the profiler: %v", err)
        }
        ...
}

عامل پروفایل به طور پیش فرض پروفایل های CPU، Heap و Thread را جمع آوری می کند. کد در اینجا مجموعه پروفایل های mutex (همچنین به عنوان "contention" شناخته می شود) را فعال می کند.

حالا برنامه را اجرا کنید:

$ go run main.go

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

$ go run main.go
2018/03/28 15:10:24 profiler has started
2018/03/28 15:10:57 successfully created profile THREADS
2018/03/28 15:10:57 start uploading profile
2018/03/28 15:11:19 successfully created profile CONTENTION
2018/03/28 15:11:30 start uploading profile
2018/03/28 15:11:40 successfully created profile CPU
2018/03/28 15:11:51 start uploading profile
2018/03/28 15:11:53 successfully created profile CONTENTION
2018/03/28 15:12:03 start uploading profile
2018/03/28 15:12:04 successfully created profile HEAP
2018/03/28 15:12:04 start uploading profile
2018/03/28 15:12:04 successfully created profile THREADS
2018/03/28 15:12:04 start uploading profile
2018/03/28 15:12:25 successfully created profile HEAP
2018/03/28 15:12:25 start uploading profile
2018/03/28 15:12:37 successfully created profile CPU
...

پس از جمع‌آوری اولین نمایه‌ها، UI خود را به‌روزرسانی می‌کند. پس از آن به‌روزرسانی خودکار نمی‌شود، بنابراین برای دیدن داده‌های جدید، باید رابط کاربری Profiler را به‌صورت دستی بازخوانی کنید. برای انجام این کار، روی دکمه Now در انتخابگر بازه زمانی دو بار کلیک کنید:

650051097b651b91.png

پس از رفرش کردن رابط کاربری، چیزی شبیه به این خواهید دید:

47a763d4dc78b6e8.png

انتخابگر نوع نمایه پنج نوع نمایه موجود را نشان می دهد:

b5d7b4b5051687c9.png

بیایید اکنون هر یک از انواع پروفایل ها و برخی از قابلیت های مهم رابط کاربری را مرور کنیم و سپس آزمایش هایی را انجام دهیم. در این مرحله دیگر نیازی به ترمینال Cloud Shell ندارید، بنابراین می توانید با فشردن CTRL-C و تایپ «exit» از آن خارج شوید.

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

اکنون که برخی داده ها را جمع آوری کرده ایم، بیایید با دقت بیشتری به آن نگاه کنیم. ما از یک برنامه مصنوعی استفاده می کنیم (منبع در Github موجود است) که رفتارهای معمول انواع مختلف مشکلات عملکرد در تولید را شبیه سازی می کند.

کد فشرده CPU

نوع پروفایل CPU را انتخاب کنید. پس از اینکه رابط کاربری آن را بارگیری کرد، در نمودار شعله بلوک های چهار برگ برای عملکرد load را مشاهده خواهید کرد که مجموعاً تمام مصرف CPU را شامل می شود:

fae661c9fe6c58df.png

این تابع به طور خاص برای مصرف چرخه های CPU زیادی با اجرای یک حلقه تنگ نوشته شده است:

main.go

func load() {
        for i := 0; i < (1 << 20); i++ {
        }
}

تابع به طور غیر مستقیم از busyloop () از طریق چهار مسیر فراخوانی فراخوانی می شود: busyloop → { foo1 , foo2 } → { bar , baz } → load . عرض یک جعبه تابع نشان دهنده هزینه نسبی مسیر تماس خاص است. در این حالت هر چهار مسیر تقریباً هزینه یکسانی دارند. در یک برنامه واقعی، شما می خواهید روی بهینه سازی مسیرهای تماس که بیشترین اهمیت را از نظر عملکرد دارند، تمرکز کنید. نمودار شعله، که به صورت بصری بر مسیرهای گران‌تر با جعبه‌های بزرگ‌تر تأکید می‌کند، شناسایی این مسیرها را آسان می‌کند.

برای اصلاح بیشتر نمایشگر می توانید از فیلتر داده پروفایل استفاده کنید. به عنوان مثال، سعی کنید یک فیلتر "Show stacks" اضافه کنید و "baz" را به عنوان رشته فیلتر مشخص کنید. شما باید چیزی شبیه به اسکرین شات زیر ببینید، که در آن تنها دو مسیر از چهار مسیر تماس برای load() نمایش داده می شود. این دو مسیر تنها مسیرهایی هستند که از تابعی با رشته "baz" در نام آن عبور می کنند. چنین فیلترینگی زمانی مفید است که می‌خواهید روی بخش فرعی یک برنامه بزرگتر تمرکز کنید (مثلاً، زیرا شما فقط مالک بخشی از آن هستید).

eb1d97491782b03f.png

کد حافظه فشرده

اکنون به نوع پروفایل "Heap" بروید. مطمئن شوید که فیلترهایی را که در آزمایش‌های قبلی ایجاد کرده‌اید حذف کرده‌اید. اکنون باید نمودار شعله ای را مشاهده کنید که در آن allocImpl که توسط alloc فراخوانی می شود، به عنوان مصرف کننده اصلی حافظه در برنامه نمایش داده می شود:

f6311c8c841d04c4.png

جدول خلاصه بالای نمودار شعله نشان می دهد که مقدار کل حافظه استفاده شده در برنامه به طور متوسط ​​~ 57.4 مگابایت است که بیشتر آن توسط تابع allocImpl اختصاص داده شده است. با توجه به اجرای این تابع، تعجب آور نیست:

main.go

func allocImpl() {
        // Allocate 64 MiB in 64 KiB chunks
        for i := 0; i < 64*16; i++ {
                mem = append(mem, make([]byte, 64*1024))
        }
}

این تابع یک بار اجرا می‌شود، 64 مگابایت را در تکه‌های کوچک‌تر تخصیص می‌دهد، سپس نشانگرها را به آن تکه‌ها در یک متغیر سراسری ذخیره می‌کند تا از جمع‌آوری زباله محافظت کند. توجه داشته باشید که مقدار حافظه نشان‌داده‌شده توسط پروفیل‌کننده کمی متفاوت از 64 مگابایت است: نمایه‌ساز هیپ Go یک ابزار آماری است، بنابراین اندازه‌گیری‌ها سربار پایین هستند اما بایت دقیق نیستند. با دیدن تفاوت 10 درصدی این چنینی تعجب نکنید.

کد IO-intensive

اگر "Threads" را در انتخابگر نوع نمایه انتخاب کنید، نمایشگر به نمودار شعله ای تغییر می کند که در آن بیشتر عرض با توابع wait و waitImpl گرفته می شود:

ebd57fdff01dede9.png

در خلاصه نمودار شعله بالا، می توانید ببینید که 100 گوروتین وجود دارد که پشته تماس خود را از تابع wait رشد می دهند. این دقیقاً درست است، با توجه به اینکه کدی که این انتظارها را شروع می کند به این صورت است:

main.go

func main() {
        ...
        // Simulate some waiting goroutines.
        for i := 0; i < 100; i++ {
                go wait()
        }

این نوع نمایه برای درک اینکه آیا برنامه زمان غیرمنتظره ای را در انتظار صرف می کند (مانند I/O) مفید است. چنین پشته های فراخوانی معمولاً توسط نمایه ساز CPU نمونه برداری نمی شوند، زیرا آنها بخش قابل توجهی از زمان CPU را مصرف نمی کنند. اغلب می‌خواهید از فیلترهای «پنهان کردن پشته‌ها» با نمایه‌های Threads استفاده کنید - برای مثال، برای مخفی کردن همه پشته‌هایی که با تماس به gopark, زیرا آن‌ها اغلب گوروتین‌های بی‌کار هستند و جالب‌تر از مواردی هستند که در I/O منتظر می‌مانند.

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

کد مناقشه برانگیز

نوع نمایه Contention بیشترین قفل های "تحت تعقیب" را در برنامه شناسایی می کند. این نوع نمایه برای برنامه‌های Go موجود است، اما باید به صراحت با مشخص کردن " MutexProfiling: true " در کد پیکربندی عامل فعال شود. این مجموعه با ثبت (تحت معیار "مشاهده") تعداد دفعاتی که یک قفل خاص، هنگام باز شدن توسط یک گوروتین A، یک گوروتین B دیگر در انتظار باز شدن قفل بود، کار می کند. همچنین (تحت معیار "تاخیر") زمانی را که گوروتین مسدود شده برای قفل منتظر ماند ثبت می کند. در این مثال، یک پشته منازعه وجود دارد و کل زمان انتظار برای قفل 10.5 ثانیه بود:

83f00dca4a0f768e.png

کدی که این نمایه را ایجاد می کند شامل 4 گوروتین است که بر سر یک mutex می جنگند:

main.go

func contention(d time.Duration) {
        contentionImpl(d)
}

func contentionImpl(d time.Duration) {
        for {
                mu.Lock()
                time.Sleep(d)
                mu.Unlock()
        }
}
...
func main() {
        ...
        for i := 0; i < 4; i++ {
                go contention(time.Duration(i) * 50 * time.Millisecond)
        }
}

6. خلاصه

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

7. تبریک می گویم!

شما نحوه پیکربندی و استفاده از Cloud Profiler را یاد گرفتید!

بیشتر بدانید

مجوز

این اثر تحت مجوز Creative Commons Attribution 2.0 Generic مجوز دارد.