تحليل أداء الإنتاج باستخدام Stackdriver Profiler

على الرغم من أن تطبيق العميل ومطوّري برامج الواجهة الأمامية يستخدمان عادةً أدوات مثل أداة تحليل وحدة المعالجة المركزية في Android Studio أو أدوات تحديد الملفات الشخصية في Chrome لتحسين أداء الرموز والتقنيات المكافئة، لم يكن من الممكن الوصول إليها أو استخدامها بشكل جيد من قِبل الأشخاص الذين يعملون في الخدمات الخلفية. يوفّر Stackdriver Profiler الإمكانيات نفسها لمطوّري الخدمات، بغض النظر عمّا إذا كان الرمز الخاص به يعمل على Google Cloud Platform أو في أي مكان آخر.

تجمع الأداة معلومات استخدام وحدة المعالجة المركزية (CPU) وتخصيص الذاكرة من تطبيقات الإنتاج. وتُحيل هذه المعلومات إلى رمز مصدر التطبيق، مما يساعدك على تحديد أجزاء التطبيق التي تستهلك معظم الموارد، وتوضيح خصائص أداء الرمز بأي طريقة أخرى. النفقات العامة التي تغطيها تقنيات جمع الأدوات المستخدَمة في الأداة تجعلها مناسبة للاستخدام المستمر في بيئات الإنتاج.

في هذا الدرس التطبيقي حول الترميز، ستتعلّم كيفية إعداد Stackdriver Profiler لبرنامج Go وستتعرّف على نوع الإحصاءات عن أداء التطبيقات التي يمكن أن تقدّمها الأداة.

ما ستتعرّف عليه

  • كيفية ضبط برنامج Go لإنشاء ملفات تعريفية باستخدام Stackdriver Profiler.
  • كيفية جمع بيانات الأداء وعرضها وتحليلها باستخدام Stackdriver Profiler.

المتطلبات اللازمة

  • مشروع في Google Cloud Platform
  • متصفح، مثل Chrome أو Firefox
  • الإلمام بأدوات تحرير النصوص في Linux مثل Vim أو EMACs أو Nano

كيف ستستخدم هذا البرنامج التعليمي؟

قراءة القراءة فقط قراءة القراءة وإكمال التدريبات

كيف تقيّم تجربتك مع Google Cloud Platform؟

مبتدئ متوسط محترف

إعداد البيئة الذاتية

إذا لم يكن لديك حساب على Google (Gmail أو Google Apps)، يجب إنشاء حساب. تسجيل الدخول إلى وحدة تحكُّم Google Cloud Platform (console.cloud.google.com) وإنشاء مشروع جديد:

لقطة شاشة من 2016-02-10 الساعة 12:45:26.png

عذرًا! وسيُشار إليه لاحقًا في هذا الدرس التطبيقي بعنوان PROJECT_ID.

بعد ذلك، ستحتاج إلى تفعيل الفوترة في Cloud Console لاستخدام موارد Google Cloud.

من المفترض ألا يكلفك العمل على هذا الدرس التطبيقي أكثر من بضعة دولارات، ولكن قد يترتّب عليك أكثر إذا قررت استخدام المزيد من الموارد أو إذا تركتها قيد التشغيل (راجع قسم "عرض الأسعار التقديري" في نهاية هذا المستند).

يكون المستخدمون الجدد لخدمة Google Cloud Platform مؤهَّلين للاستفادة من فترة تجريبية مجانية تبلغ 300 دولار أمريكي.

Google Cloud Shell

يمكن تشغيل Google Cloud عن بُعد من الكمبيوتر المحمول، ولتسهيل عملية الإعداد في هذا الدرس التطبيقي حول الترميز، سنستخدم Google Cloud Shell، وهو عبارة عن بيئة سطر أوامر يتم تشغيلها في السحابة الإلكترونية.

تفعيل Google Cloud Shell

من وحدة تحكّم Google Cloud Platform، انقر على رمز Cloud Shell في شريط الأدوات العلوي الأيسر:

ثم انقر على "بدء Cloud Shell":

ينبغي ألا تستغرق إدارة الحسابات والاتصال بالبيئة أكثر من بضع لحظات.

يتم تحميل هذه الآلة الافتراضية مزوّدة بكل أدوات التطوير التي ستحتاج إليها. وتوفِّر هذه الآلة دليلاً رئيسيًا دائمًا بسعة 5 غيغابايت ويتمّ تشغيله على Google Cloud، ما يحسّن كثيرًا أداء الشبكة والمصادقة. ويمكن إتمام معظم عملك إن لم يكن كلّه في هذا الدرس ببساطة من خلال متصفّح أو جهاز Google Chromebook فقط.

عند الاتصال بخدمة Cloud Shell، من المفترض أن تتم مصادقتها وأنّ المشروع قد سبق وتم ضبطه على PROJECT_ID.

شغِّل الأمر التالي في Cloud Shell لتأكيد أنّك تمت مصادقته:

gcloud auth list

مخرجات الأوامر

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

مخرجات الأوامر

[core]
project = <PROJECT_ID>

إذا لم يكن كذلك، يمكنك تعيينه من خلال هذا الأمر:

gcloud config set project <PROJECT_ID>

مخرجات الأوامر

Updated property [core/project].

في Cloud Console، انتقِل إلى واجهة مستخدم المحلّل من خلال النقر على "Profiler" في شريط التنقل الأيمن:

بدلاً من ذلك، يمكنك استخدام شريط بحث Cloud Console للانتقال إلى واجهة مستخدم المحلّل: ما عليك سوى كتابة "Stackdriver Profiler&quot؛ وتحديد العنصر الذي تم العثور عليه. وأيًا كانت الطريقة التي ستظهر لك، من المفترض أن تظهر لك واجهة مستخدم المحلّل مع رسالة &;عدم عرض أي بيانات لعرضها&كما هو موضّح أدناه. المشروع جديد، لذلك لم يتم جمع أي بيانات لإنشاء الملفات التعريفية بعد.

حان الوقت للحصول على ملف شخصي!

سنستخدِم تطبيقًا اصطناعيًا بسيطًا Go متوفّرًا على Github. في الوحدة الطرفية لـ Cloud Shell التي لا تزال مفتوحة (وفي الوقت نفسه، ما مِن بيانات لعرضها أو لا تظهر فيها الرسالة في واجهة مستخدم المحلّل)، شغِّل الأمر التالي:

$ 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) والأجزاء لعناصر متعددة وسلاسل المحادثات تلقائيًا. يُفعّل الرمز هنا مجموعة ملفات TalkBackx (المعروفة أيضًا باسم "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
...

وسيتم تحديث واجهة المستخدم تلقائيًا بعد فترة وجيزة من جمع أول الملفات الشخصية. ولن يتم تحديثه تلقائيًا بعد هذا التاريخ، لذا للاطّلاع على البيانات الجديدة، عليك إعادة تحميل واجهة المحلّل يدويًا. ولإجراء ذلك، انقر على الزر "الآن" في منتقي الفاصل الزمني مرتين:

بعد تحديث واجهة المستخدم، سيظهر لك ما يلي:

تعرض أداة اختيار نوع الملف الشخصي أنواع الملفات الشخصية الخمسة المتاحة:

لنراجع الآن كل نوع من أنواع الملفات الشخصية وبعض إمكانات واجهة المستخدم المهمة، ثم نجري بعض التجارب. في هذه المرحلة، لم تعد بحاجة إلى محطة دفع Cloud Shell، لذلك يمكنك الخروج منها بالضغط على CTRL-C وكتابة "exit&quot؛

والآن بعد أن جمعنا بعض البيانات، دعنا نلقي نظرة عليها عن كثب. نحن نستخدم تطبيقًا اصطناعيًا (يكون المصدر متاحًا على Github) الذي يحاكي السلوكيات المعتادة لأنواع مختلفة من مشاكل الأداء في الإنتاج.

رمز وحدة المعالجة المركزية (CPU)

اختَر نوع الملف الشخصي لوحدة المعالجة المركزية. وبعد تحميل واجهة المستخدم، سيظهر في الرسم البياني لللهب رموز ورقة الشجر الأربعة لوظيفة load، والتي تُمثّل معًا جميع استهلاك وحدة المعالجة المركزية (CPU):

وهذه الدالة مكتوبة خصيصًا لاستهلاك العديد من دورات وحدة المعالجة المركزية (CPU) من خلال تشغيل حلقة متكررة:

main.go

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

يتم استدعاء الدالة بشكل غير مباشر من busyloop() عبر أربعة مسارات اتصال: busyloop → {foo1, foo2} → {bar, baz} → load. يمثّل عرض مربّع الدالة التكلفة النسبية لمسار الاتصال المحدّد. في هذه الحالة، تحتوي جميع المسارات الأربعة على التكلفة نفسها تقريبًا. في برنامج حقيقي، تريد التركيز على تحسين مسارات الاتصال الأكثر أهمية من حيث الأداء. ويجعل الرسم البياني لللهب، الذي يركّز بصريًا على المسارات الأعلى تكلفة ذات المربعات الأكبر، من السهل تحديد هذه المسارات.

ويمكنك استخدام فلتر بيانات الملف الشخصي لزيادة تحسين العرض. على سبيل المثال، جرِّب إضافة &"عرض حِزم "فلتر وتحديد "baz" كسلسلة فلتر. من المفترض أن ترى شيئًا مثل لقطة الشاشة أدناه، حيث يتم عرض مسارين من مسارات الاتصال الأربعة فقط إلى load(). هذان المساران هما المساران الوحيدان اللذان يتضمّنان السلسلة التي تحمل اسمًا خاصًا بالسلسلة النصية. تكون هذه الفلترة مفيدة عندما تريد التركيز على جزء فرعي من برنامج أكبر (على سبيل المثال، لأنك تملك جزءًا منه فقط).

الرمز الذي يستهلك قدرًا كبيرًا من الذاكرة

والآن بدّل إلى نوع الملف الشخصي احرص على إزالة أي فلاتر تم إنشاؤها في تجارب سابقة. من المفترض أن ترى الآن رسمًا بيانيًا لللهب حيث يتم عرض 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% على هذا النحو.

رمز مكثّف لاستخدام تكنولوجيا المعلومات

إذا اخترت "سلاسل المحادثات&; في أداة اختيار نوع الملف الشخصي، سيتم التبديل إلى الرسم البياني لللهب حيث يتم استخدام معظم العرض بواسطة دالّتَي wait وwaitImpl:

في الملخّص أعلى الرسم البياني للهب، يمكنك ملاحظة أنّ هناك 100 خوارزمية تنقيط لحزمة المكالمات من الدالة wait. هذا صحيح تمامًا، بافتراض أن الرمز الذي يطلق أوقات الانتظار هذه يبدو كما يلي:

main.go

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

يُعدّ نوع الملف الشخصي هذا مفيدًا لمعرفة ما إذا كان البرنامج يقضي أي وقت غير متوقّع في حالات الانتظار (مثل I/O). ولن يتم عادةً أخذ عينات حِزم المكالمات هذه من أداة تحليل وحدة المعالجة المركزية (CPU)، لأنها لا تستهلك أي جزء كبير من وقت وحدة المعالجة المركزية (CPU). غالبًا ما تريد استخدام &"إخفاء الأكواد&quot؛ والفلاتر التي تحتوي على ملفات شخصية لسلاسل المحادثات - على سبيل المثال، لإخفاء جميع الحِزم التي تنتهي باستدعاء في gopark, نظرًا لأنها غالبًا ما تكون خوارزم خاملة وتكون أقل إثارة من تلك التي تنتظر في مؤتمر I/O.

يمكن أن يساعد نوع الملف الشخصي لسلاسل المحادثات أيضًا في تحديد النقاط المتاحة في البرنامج والتي تنتظرها سلاسل المحادثات التي يملكها جزء آخر من البرنامج لفترة طويلة، ولكن نوع الملف الشخصي التالي أكثر فائدة من ذلك.

الرمز الذي يكثر على المنافسة

يحدّد نوع الملف الشخصي بنظام "المنافسة" معظم الأقفال والمفاتيح المطلوبة في البرنامج. هذا النوع من الملفات الشخصية متاح لبرامج Go ولكن يجب تفعيله صراحةً من خلال تحديد "MutexProfiling: true" في رمز إعداد الوكيل. وتعمل المجموعة من خلال تسجيل (ضمن "المقياس"&و"عدد الاقتراحات" و"عرض الأسعار") عدد المرات التي حصل فيها قفل معيّن، عند فتح القفل بواسطة "أ" من نوع "أندرو"، على مقياس "أو" آخر من نوع خوارزمية "ب"، في انتظار فتح القفل. ويسجِّل أيضًا (ضمن مقياس "&&;;تأخير&" الوقت) الذي انتظر فيه المحرك المحظور القفل. في هذا المثال، هناك حزمة منافسة واحدة وبلغ إجمالي وقت الانتظار للقفل 11.03 ثوانٍ:

ويتألف الرمز الذي يُنشئ هذا الملف الشخصي من 4 قطع غامقة تقاتل من خلال كائن الصوت:

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)
        }
}

في هذا الدرس التطبيقي، تعلّمت كيفية ضبط برنامج Go للاستخدام مع Stackdriver Profiler. وتعرّفت أيضًا على كيفية جمع بيانات الأداء وعرضها وتحليلها باستخدام هذه الأداة. يمكنك الآن تطبيق مهاراتك الجديدة على الخدمات الحقيقية التي تشغّلها على Google Cloud Platform.

لقد تعلّمت طريقة ضبط أداة Stackdriver Profiler واستخدامها.

مزيد من المعلومات

الترخيص

يخضع هذا العمل لترخيص بموجب رخصة المشاع الإبداعي مع نسب العمل إلى مؤلفه 2.0.