1. بررسی اجمالی
در حالی که برنامهنویسهای برنامههای مشتری و توسعهدهندگان وب ظاهری معمولاً از ابزارهایی مانند نمایهساز CPU Android Studio یا ابزارهای نمایهسازی موجود در Chrome برای بهبود عملکرد کد خود استفاده میکنند، تکنیکهای معادل تقریباً توسط افرادی که روی خدمات پشتیبان کار میکنند در دسترس یا به خوبی مورد استفاده قرار نگرفتهاند. Cloud Profiler این قابلیتها را برای توسعهدهندگان خدمات ارائه میکند، صرف نظر از اینکه کد آنها در Google Cloud Platform یا جاهای دیگر اجرا میشود.
این ابزار اطلاعات استفاده از CPU و تخصیص حافظه را از برنامه های تولیدی شما جمع آوری می کند. این اطلاعات را به کد منبع برنامه نسبت می دهد و به شما کمک می کند تا قسمت هایی از برنامه را که بیشترین منابع را مصرف می کنند شناسایی کنید و در غیر این صورت ویژگی های عملکرد کد را روشن می کند. سربار کم تکنیک های مجموعه به کار رفته توسط این ابزار، آن را برای استفاده مداوم در محیط های تولیدی مناسب می کند.
در این نرم افزار کد، نحوه راه اندازی Cloud Profiler برای برنامه Go را یاد خواهید گرفت و با چه نوع بینش هایی در مورد عملکرد برنامه کاربردی ابزار می تواند ارائه دهد آشنا خواهید شد.
چیزی که یاد خواهید گرفت
- نحوه پیکربندی برنامه Go برای پروفایل با Cloud Profiler.
- نحوه جمع آوری، مشاهده و تجزیه و تحلیل داده های عملکرد با Cloud Profiler.
آنچه شما نیاز دارید
- یک پروژه Google Cloud Platform
- یک مرورگر، مانند کروم یا فایرفاکس
- آشنایی با ویرایشگرهای متن استاندارد لینوکس مانند Vim، EMACs یا Nano
چگونه از این آموزش استفاده خواهید کرد؟
تجربه خود را با Google Cloud Platform چگونه ارزیابی می کنید؟
2. راه اندازی و الزامات
تنظیم محیط خود به خود
- به کنسول Cloud وارد شوید و یک پروژه جدید ایجاد کنید یا از یک موجود استفاده مجدد کنید. اگر قبلاً یک حساب Gmail یا Google Workspace ندارید، باید یک حساب ایجاد کنید .
شناسه پروژه را به خاطر بسپارید، یک نام منحصر به فرد در تمام پروژه های Google Cloud (نام بالا قبلاً گرفته شده است و برای شما کار نخواهد کرد، متأسفیم!). بعداً در این آزمایشگاه کد به عنوان PROJECT_ID
نامیده خواهد شد.
- در مرحله بعد، برای استفاده از منابع Google Cloud، باید صورتحساب را در Cloud Console فعال کنید .
اجرا کردن از طریق این کد لبه نباید هزینه زیادی داشته باشد، اگر اصلاً باشد. حتماً دستورالعملهای موجود در بخش «تمیز کردن» را دنبال کنید که به شما توصیه میکند چگونه منابع را خاموش کنید تا بیش از این آموزش متحمل صورتحساب نشوید. کاربران جدید Google Cloud واجد شرایط برنامه آزمایشی رایگان 300 دلاری هستند.
Google Cloud Shell
در حالی که Google Cloud را میتوان از راه دور از لپتاپ شما کار کرد، برای سادهتر کردن راهاندازی در این کد، از Google Cloud Shell استفاده میکنیم، یک محیط خط فرمان که در Cloud اجرا میشود.
Cloud Shell را فعال کنید
- از Cloud Console، روی Activate Cloud Shell کلیک کنید .
اگر قبلاً Cloud Shell را راهاندازی نکردهاید، یک صفحه میانی (در زیر تاشو) برای شما نمایش داده میشود که آن را توصیف میکند. اگر اینطور است، روی Continue کلیک کنید (و دیگر آن را نخواهید دید). در اینجا به نظر می رسد که آن صفحه یک بار مصرف:
تهیه و اتصال به Cloud Shell فقط باید چند لحظه طول بکشد.
این ماشین مجازی با تمام ابزارهای توسعه مورد نیاز شما بارگذاری شده است. این دایرکتوری اصلی 5 گیگابایتی دائمی را ارائه می دهد و در Google Cloud اجرا می شود و عملکرد شبکه و احراز هویت را بسیار افزایش می دهد. بیشتر، اگر نه همه، کار شما در این کد لبه را می توان به سادگی با یک مرورگر یا Chromebook انجام داد.
پس از اتصال به Cloud Shell، باید ببینید که قبلاً احراز هویت شده اید و پروژه قبلاً روی ID پروژه شما تنظیم شده است.
- برای تایید احراز هویت، دستور زیر را در 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`
- دستور زیر را در 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 بروید:
یا میتوانید از نوار جستجوی کنسول Cloud برای رفتن به رابط کاربری Profiler استفاده کنید: فقط «Cloud Profiler» را تایپ کنید و مورد پیدا شده را انتخاب کنید. در هر صورت، باید رابط کاربری Profiler را با پیام «عدم نمایش دادهای» مانند زیر ببینید. این پروژه جدید است، بنابراین هنوز هیچ داده پروفایلی جمع آوری نشده است.
اکنون زمان آن است که چیزی را نمایه کنید!
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 در انتخابگر بازه زمانی دو بار کلیک کنید:
پس از رفرش کردن رابط کاربری، چیزی شبیه به این خواهید دید:
انتخابگر نوع نمایه پنج نوع نمایه موجود را نشان می دهد:
بیایید اکنون هر یک از انواع پروفایل ها و برخی از قابلیت های مهم رابط کاربری را مرور کنیم و سپس آزمایش هایی را انجام دهیم. در این مرحله دیگر نیازی به ترمینال Cloud Shell ندارید، بنابراین می توانید با فشردن CTRL-C و تایپ «exit» از آن خارج شوید.
5. داده های Profiler را تجزیه و تحلیل کنید
اکنون که برخی داده ها را جمع آوری کرده ایم، بیایید با دقت بیشتری به آن نگاه کنیم. ما از یک برنامه مصنوعی استفاده می کنیم (منبع در Github موجود است) که رفتارهای معمول انواع مختلف مشکلات عملکرد در تولید را شبیه سازی می کند.
کد فشرده CPU
نوع پروفایل CPU را انتخاب کنید. پس از اینکه رابط کاربری آن را بارگیری کرد، در نمودار شعله بلوک های چهار برگ برای عملکرد load
را مشاهده خواهید کرد که مجموعاً تمام مصرف CPU را شامل می شود:
این تابع به طور خاص برای مصرف چرخه های CPU زیادی با اجرای یک حلقه تنگ نوشته شده است:
main.go
func load() {
for i := 0; i < (1 << 20); i++ {
}
}
تابع به طور غیر مستقیم از busyloop
() از طریق چهار مسیر فراخوانی فراخوانی می شود: busyloop
→ { foo1
, foo2
} → { bar
, baz
} → load
. عرض یک جعبه تابع نشان دهنده هزینه نسبی مسیر تماس خاص است. در این حالت هر چهار مسیر تقریباً هزینه یکسانی دارند. در یک برنامه واقعی، شما می خواهید روی بهینه سازی مسیرهای تماس که بیشترین اهمیت را از نظر عملکرد دارند، تمرکز کنید. نمودار شعله، که به صورت بصری بر مسیرهای گرانتر با جعبههای بزرگتر تأکید میکند، شناسایی این مسیرها را آسان میکند.
برای اصلاح بیشتر نمایشگر می توانید از فیلتر داده پروفایل استفاده کنید. به عنوان مثال، سعی کنید یک فیلتر "Show stacks" اضافه کنید و "baz" را به عنوان رشته فیلتر مشخص کنید. شما باید چیزی شبیه به اسکرین شات زیر ببینید، که در آن تنها دو مسیر از چهار مسیر تماس برای load()
نمایش داده می شود. این دو مسیر تنها مسیرهایی هستند که از تابعی با رشته "baz" در نام آن عبور می کنند. چنین فیلترینگی زمانی مفید است که میخواهید روی بخش فرعی یک برنامه بزرگتر تمرکز کنید (مثلاً، زیرا شما فقط مالک بخشی از آن هستید).
کد حافظه فشرده
اکنون به نوع پروفایل "Heap" بروید. مطمئن شوید که فیلترهایی را که در آزمایشهای قبلی ایجاد کردهاید حذف کردهاید. اکنون باید نمودار شعله ای را مشاهده کنید که در آن allocImpl
که توسط alloc
فراخوانی می شود، به عنوان مصرف کننده اصلی حافظه در برنامه نمایش داده می شود:
جدول خلاصه بالای نمودار شعله نشان می دهد که مقدار کل حافظه استفاده شده در برنامه به طور متوسط ~ 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
گرفته می شود:
در خلاصه نمودار شعله بالا، می توانید ببینید که 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 ثانیه بود:
کدی که این نمایه را ایجاد می کند شامل 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 را یاد گرفتید!
بیشتر بدانید
- Cloud Profiler: https://cloud.google.com/profiler/
- بسته اجرا/pprof را که Cloud Profiler استفاده میکند بروید: https://golang.org/pkg/runtime/pprof/
مجوز
این اثر تحت مجوز Creative Commons Attribution 2.0 Generic مجوز دارد.