خطوة 29: إدارة الأداء

5.0 version
Maintained

إدارة الأداء

التحسين المبكر هو أصل كل الشرور.

ربما كنت قد قرأت بالفعل هذا الاقتباس من قبل. لكنني أحب أن أقتبسه بالكامل:

يجب أن ننسى الكفاءات الصغيرة ، قل حوالي 97 ٪ من الوقت: التحسين المبكر هو أصل كل الشرور. ومع ذلك ، يجب ألا نفوت فرصنا في هذه النسبة البالغة 3٪.

—دونالد نوث

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

أفضل طريقة للعثور على تحسينات الأداء هي استخدام منشئ ملفات التعريف. الخيار الأكثر شيوعًا في الوقت الحاضر هو Blackfire (إخلاء تام: أنا أيضًا مؤسس مشروع Blackfire).

تقديم Blackfire

يتكون Blackfire من عدة أجزاء:

  • عميل يقوم بتشغيل ملفات التعريف (أداة Blackfire CLI أو امتداد متصفح لمتصفح Google Chrome أو Firefox) ؛
  • وكيل يقوم بإعداد البيانات وتجميعها قبل إرسالها إلى blackfire.io للعرض؛
  • امتداد PHP (* probe* ) الذي يصوغ كود PHP.

للعمل مع Blackfire ، تحتاج أولاً إلى الإشتراك.

قم بتثبيت Blackfire على جهازك المحلي عن طريق تشغيل البرنامج النصي للتثبيت السريع التالي:

1
$ curl https://installer.blackfire.io/ | bash

يقوم هذا المثبت بتنزيل أداة Blackfire CLI Tool ثم يقوم بتثبيت مسبار PHP (دون تمكينه) على جميع إصدارات PHP المتوفرة.

تمكين التحقيق PHP لمشروعنا:

patch_file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
--- a/php.ini
+++ b/php.ini
@@ -6,3 +6,7 @@ max_execution_time=30
 session.use_strict_mode=On
 realpath_cache_ttl=3600
 zend.detect_unicode=Off
+
+[blackfire]
+# use php_blackfire.dll on Windows
+extension=blackfire.so

أعد تشغيل خادم الويب حتى يتمكن PHP من تحميل Blackfire:

1
2
$ symfony server:stop
$ symfony server:start -d

يلزم تهيئة أداة Blackfire CLI باستخدام بيانات اعتمادك الشخصية client (لتخزين ملفات تعريف المشروع الخاصة بك تحت حسابك الشخصي). ابحث عنها أعلى صفحة Settings/Credentials page وقم بتنفيذ الأمر التالي عن طريق استبدال العناصر النائبة:

1
$ blackfire config --client-id=xxx --client-token=xxx

Note

للحصول على إرشادات التثبيت الكامل ، اتبع اتبع دليل التثبيت المفصل الرسمي. تكون مفيدة عند تثبيت Blackfire على الخادم.

إعداد وكيل Blackfire على Docker

الخطوة الأخيرة هي إضافة خدمة وكيل Blackfire في مكدس Docker Compose:

patch_file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
--- a/docker-compose.yaml
+++ b/docker-compose.yaml
@@ -20,3 +20,8 @@ services:
     mailer:
         image: schickling/mailcatcher
         ports: [1025, 1080]
+
+    blackfire:
+        image: blackfire/blackfire
+        env_file: .env.local
+        ports: [8707]

للتواصل مع الخادم ، تحتاج إلى الحصول على بيانات اعتماد ** server** الشخصية (تحدد بيانات الاعتماد هذه المكان الذي تريد تخزين الملفات الشخصية فيه - يمكنك إنشاء واحد لكل مشروع) ؛ يمكن العثور عليها في أسفل صفحة Settings/Credentials ``<https://blackfire.io/my/settings/credentials> `_. قم بتخزينها في ملف `` env.local. محلي:

1
2
BLACKFIRE_SERVER_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
BLACKFIRE_SERVER_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

يمكنك الآن تشغيل الحاوية الجديدة:

1
2
$ docker-compose stop
$ docker-compose up -d

إصلاح تثبيت Blackfire غير العامل

إذا حصلت على خطأ أثناء إنشاء ملفات تعريف ، فقم بزيادة مستوى سجل Blackfire للحصول على مزيد من المعلومات في السجلات:

patch_file
1
2
3
4
5
6
7
--- a/php.ini
+++ b/php.ini
@@ -10,3 +10,4 @@ zend.detect_unicode=Off
 [blackfire]
 # use php_blackfire.dll on Windows
 extension=blackfire.so
+blackfire.log_level=4

أعد تشغيل خادم الويب:

1
2
$ symfony server:stop
$ symfony server:start -d

وتتبع السجلات:

1
$ symfony server:log

الملف الشخصي مرة أخرى وتحقق من إخراج السجل.

تكوين Blackfire في الإنتاج

يتم تضمين Blackfire افتراضيًا في جميع مشاريع SymfonyCloud.

قم بإعداد بيانات اعتماد * server * كمتغيرات بيئة:

1
2
$ symfony var:set BLACKFIRE_SERVER_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
$ symfony var:set BLACKFIRE_SERVER_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

وقم بتمكين مسبار PHP مثل أي امتداد PHP آخر:

patch_file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
--- a/.symfony.cloud.yaml
+++ b/.symfony.cloud.yaml
@@ -4,6 +4,7 @@ type: php:7.3

 runtime:
     extensions:
+        - blackfire
         - xsl
         - amqp
         - redis

إعداد Varnish ل Blackfire

قبل أن تتمكن من النشر لبدء التوصيف ، فأنت بحاجة إلى طريقة لتجاوز ذاكرة التخزين المؤقت للورنيش HTTP. إذا لم يكن الأمر كذلك ، فلن تضغط Blackfire أبدًا على تطبيق PHP. ستقوم بتفويض طلبات ملفات التعريف فقط الواردة من جهازك المحلي.

ابحث عن عنوان IP الحالي الخاص بك:

1
$ curl https://ifconfig.me/

واستخدامه لتكوين Varnish:

patch_file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
--- a/.symfony/config.vcl
+++ b/.symfony/config.vcl
@@ -1,3 +1,11 @@
+acl profile {
+   # Authorize the local IP address (replace with the IP found above)
+   "a.b.c.d";
+   # Authorize Blackfire servers
+   "46.51.168.2";
+   "54.75.240.245";
+}
+
 sub vcl_recv {
     set req.backend_hint = application.backend();
     set req.http.Surrogate-Capability = "abc=ESI/1.0";
@@ -8,6 +14,16 @@ sub vcl_recv {
         }
         return (purge);
     }
+
+    # Don't profile ESI requests
+    if (req.esi_level > 0) {
+        unset req.http.X-Blackfire-Query;
+    }
+
+    # Bypass Varnish when the profile request comes from a known IP
+    if (req.http.X-Blackfire-Query && client.ip ~ profile) {
+        return (pass);
+    }
 }

 sub vcl_backend_response {

يمكنك الآن نشر.

ملفات تعريف صفحات الويب

يمكنك تعريف صفحات الويب التقليدية من Firefox أو Google Chrome من خلال الإضافات المخصصة.

على جهازك المحلي ، لا تنسَ تعطيل ذاكرة التخزين المؤقت لـ HTTP في public/ index.php عند التوصيف: إذا لم يكن الأمر كذلك ، فستقوم بملف تعريف طبقة ذاكرة التخزين المؤقت لـ Symfony HTTP بدلاً من الرمز الخاص بك:

patch_file
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
--- a/public/index.php
+++ b/public/index.php
@@ -24,7 +24,7 @@ if ($trustedHosts = $_SERVER['TRUSTED_HOSTS'] ?? $_ENV['TRUSTED_HOSTS'] ?? false
 $kernel = new Kernel($_SERVER['APP_ENV'], (bool) $_SERVER['APP_DEBUG']);

 if ('dev' === $kernel->getEnvironment()) {
-    $kernel = new HttpCache($kernel);
+//    $kernel = new HttpCache($kernel);
 }

 $request = Request::createFromGlobals();

للحصول على صورة أفضل لأداء التطبيق الخاص بك في الإنتاج ، يجب عليك أيضًا تعريف بيئة "الإنتاج". تبعًا للإعدادات الافتراضية ، تستخدم البيئة المحلية بيئة "التطوير" ، والتي تضيف حمولة كبيرة (بشكل أساسي لجمع البيانات لشريط أدوات تصحيح الويب وملف التعريف Symfony).

يمكن تحويل جهازك المحلي إلى بيئة الإنتاج عن طريق تغيير متغير البيئة APP_ENV في ملف env.local.:

1
APP_ENV=prod

أو يمكنك استخدام الأمر server:prod:

1
$ symfony server:prod

لا تنسَ تبديلها مرة أخرى إلى نقطة التطوير عند انتهاء جلسة عمل ملفات التعريف:

1
$ symfony server:prod --off

موارد واجهة برمجة التطبيقات

من الأفضل عمل توصيف API أو SPA على CLI عبر Blackfire CLI Tool التي قمت بتثبيتها مسبقًا:

1
$ blackfire curl `symfony var:export SYMFONY_DEFAULT_ROUTE_URL`api

يقبل أمر blackfire curl نفس الحجج والخيارات تمامًا مثل cURL.

مقارنة الأداء

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

يجب عليك دائمًا قياس تأثير أي تحسين تقوم به مع المحلل. يجعل Blackfire الأمر أسهل بصريًا بفضل ميزة المقارنة.

كتابة الاختبارات الوظيفية للصندوق الأسود

لقد رأينا كيفية كتابة الاختبارات الوظيفية باستخدام Symfony. يمكن استخدام Blackfire لكتابة سيناريوهات التصفح التي يمكن تشغيلها عند الطلب عبر `Blackfire player. دعنا نكتب سيناريو يقدم تعليقًا جديدًا ويتحقق من صحته عبر رابط البريد الإلكتروني قيد التطوير ، وعبر المسؤول في الإنتاج.

قم بإنشاء ملف `` .blackfire.yaml`` بالمحتوى التالي:

.blackfire.yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
scenarios: |
    #!blackfire-player

    group login
        visit url('/login')
        submit button("Sign in")
            param username "admin"
            param password "admin"
            expect status_code() == 302

    scenario
        name "Submit a comment on the Amsterdam conference page"
        include login
        visit url('/fr/conference/amsterdam-2019')
            expect status_code() == 200
        submit button("Submit")
            param comment_form[author] 'Fabien'
            param comment_form[email] '[email protected]'
            param comment_form[text] 'Such a good conference!'
            param comment_form[photo] file(fake('image', '/tmp', 400, 300, 'cats'), 'awesome-cat.jpg')
            expect status_code() == 302
        follow
            expect status_code() == 200
            expect not(body() matches "/Such a good conference/")
            # Wait for the workflow to validate the submissions
            wait 5000
        when env != "prod"
            visit url(webmail_url ~ '/messages')
                expect status_code() == 200
                set message_ids json("[*].id")
            with message_id in message_ids
                visit url(webmail_url ~ '/messages/' ~ message_id ~ '.html')
                    expect status_code() == 200
                    set accept_url css("table a").first().attr("href")
                visit url(accept_url)
                    # we don't check the status code as we can deal
                    # with "old" messages which do not exist anymore
                    # in the DB (would be a 404 then)
        when env == "prod"
            visit url('/admin/?entity=Comment&action=list')
                expect status_code() == 200
                set comment_ids css('table.table tbody tr').extract('data-id')
            with id in comment_ids
                visit url('/admin/comment/review/' ~ id)
                    # we don't check the status code as we scan all comments,
                    # including the ones already reviewed
        visit url('/fr/')
            wait 5000
        visit url('/fr/conference/amsterdam-2019')
            expect body() matches "/Such a good conference/"

قم بتنزيل مشغل Blackfire لتتمكن من تشغيل السيناريو محليًا:

1
2
$ curl -OLsS https://get.blackfire.io/blackfire-player.phar
$ chmod +x blackfire-player.phar

قم بتشغيل هذا السيناريو في التطوير:

1
$ ./blackfire-player.phar run --endpoint=`symfony var:export SYMFONY_DEFAULT_ROUTE_URL` .blackfire.yaml --variable "webmail_url=`symfony var:export MAILER_WEB_URL 2>/dev/null`" --variable="env=dev"

أو في الإنتاج:

1
$ ./blackfire-player.phar run --endpoint=`symfony env:urls --first` .blackfire.yaml --variable "webmail_url=NONE" --variable="env=prod"

يمكن لسيناريوهات Blackfire أيضًا تشغيل ملفات تعريف لكل طلب وتشغيل اختبارات الأداء عن طريق إضافة علامة blackfire.

أتمتة التحقيقات الأداء

إدارة الأداء لا تتعلق فقط بتحسين أداء الشفرة الحالية ، بل تتعلق أيضًا بالتحقق من عدم ظهور انحدارات في الأداء.

يمكن تشغيل السيناريو المكتوب في القسم السابق تلقائيًا في سير عمل التكامل المستمر أو في الإنتاج بشكل منتظم.

في SymfonyCloud ، يسمح أيضًا بـ تشغيل السيناريوهات عندما تنشئ فرعًا جديدًا أو تنشر في الإنتاج للتحقق من الأداء من الكود الجديد تلقائيا.


  • « Previous خطوة 28: توطين تطبيق
  • Next » خطوة 30: إكتشاف بنية سيمفوني الداخلية

This work, including the code samples, is licensed under a Creative Commons BY-NC-SA 4.0 license.