Skip to content
  • About
    • What is Symfony?
    • Community
    • News
    • Contributing
    • Support
  • Documentation
    • Symfony Docs
    • Symfony Book
    • Screencasts
    • Symfony Bundles
    • Symfony Cloud
    • Training
  • Services
    • Platform.sh for Symfony Best platform to deploy Symfony apps
    • SymfonyInsight Automatic quality checks for your apps
    • Symfony Certification Prove your knowledge and boost your career
    • SensioLabs Professional services to help you with Symfony
    • Blackfire Profile and monitor performance of your apps
  • Other
  • Blog
  • Download
sponsored by
  1. Home
  2. Documentation
  3. Symfony: The Fast Track
  4. Ukrainian
  5. Управління продуктивністю

Управління продуктивністю

Передчасна оптимізація — корінь усього зла.

Можливо ви вже читали цю цитату раніше. Але я хотів би навести її повністю:

Нам слід забути про невелику ефективність, скажімо, у 97% випадків: передчасна оптимізація — корінь усього зла. Однак ми не маємо упускати наші можливості в цих критичних 3%.

-- Donald Knuth

Навіть невеликі поліпшення продуктивності можуть щось змінити, особливо для веб-сайтів електронної комерції. Тепер, коли застосунок гостьової книги готовий до прайм-тайму, подивімося, як ми можемо перевірити його продуктивність.

Найкращим способом пошуку потенційно слабких місць для оптимізації продуктивності є використання профілювальника. Найпопулярнішим варіантом сьогодні є Blackfire (повна відмова від відповідальності: я також є засновником проекту Blackfire).

Знайомство з Blackfire

Blackfire складається з кількох частин:

  • Клієнт, який запускає профілювання (інструмент Blackfire CLI чи розширення браузера Google Chrome або Firefox);
  • Агент, який готує й агрегує дані перед їх відправкою в blackfire.io для відображення;
  • Розширення PHP (зонд), яке аналізує код PHP.

Щоб працювати з Blackfire, вам спочатку потрібно зареєструватися.

Встановіть Blackfire на ваш локальний комп'ютер, запустивши наступний сценарій швидкого встановлення:

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

Цей інсталятор завантажує і встановлює інструмент Blackfire CLI.

Після завершення встановлює зонд PHP на всі доступні версії PHP:

1
$ sudo blackfire php:install

І увімкніть зонд PHP для нашого проекту:

1
2
3
4
5
6
7
8
9
10
--- a/php.ini
+++ b/php.ini
@@ -7,3 +7,7 @@ session.use_strict_mode=On
 realpath_cache_ttl=3600
 zend.detect_unicode=Off
 xdebug.file_link_format=vscode://file/%f:%l
+
+[blackfire]
+# use php_blackfire.dll on Windows
+extension=blackfire.so

Перезавантажте веб-сервер, щоб PHP міг завантажити Blackfire:

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

Інструмент Blackfire CLI потрібно налаштувати за допомогою ваших клієнтських облікових даних (щоб зберігати профілі проектів у вашому особистому кабінеті). Знайдіть їх у верхній частині сторінки Settings/Credentials і виконайте наступну команду, замінивши заповнювачі:

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

Налаштування агента Blackfire у Docker

Сервіс агента Blackfire вже налаштований у стеку Docker Compose:

docker-compose.override.yml
1
2
3
4
5
6
7
8
9
###> blackfireio/blackfire-symfony-meta ###
blackfire:
    image: blackfire/blackfire:2
    # uncomment to store Blackfire credentials in a local .env.local file
    #env_file: .env.local
    environment:
    BLACKFIRE_LOG_LEVEL: 4
    ports: [8307]
###< blackfireio/blackfire-symfony-meta ###

Щоб організувати обмін інформацією з сервером вам потрібно отримати ваші особисті серверні облікові дані (ці облікові дані визначають, де ви хочете зберігати профілі — ви можете створити один для кожного проекту); їх можна знайти в нижній частині сторінки Settings/Credentials`. Збережіть їх у локальному файлі .env.local``:

1
2
3
4
$ symfony console secrets:set BLACKFIRE_SERVER_ID
# xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
$ symfony console secrets:set BLACKFIRE_SERVER_TOKEN
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Тепер ви можете запустити новий контейнер:

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

Виправлення помилок Blackfire

Якщо ви отримуєте помилку під час профілювання, збільште рівень журналювання Blackfire, щоб отримувати більше інформації в журналах:

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 включено у всі проекти Platform.sh за замовчуванням.

Налаштуйте серверні облікові дані як конфіденційні дані продакшн:

1
2
3
4
$ symfony console secrets:set BLACKFIRE_SERVER_ID --env=prod
# xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
$ symfony console secrets:set BLACKFIRE_SERVER_TOKEN --env=prod
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Зонд PHP уже ввімкнено, як і будь-яке інше необхідне розширення PHP:

.platform.app.yaml
1
2
3
4
5
6
7
8
9
10
runtime:
    extensions:
        - apcu
        - blackfire
        - ctype
        - iconv
        - mbstring
        - pdo_pgsql
        - sodium
        - xsl

Налаштування Varnish для Blackfire

Перш ніж ви зможете розгорнути, щоб почати профілювання, вам потрібен спосіб, щоб обійти HTTP-кеш Varnish. Якщо ні, то Blackfire ніколи не потрапить у застосунок PHP. Ви збираєтеся дозволити обхід Varnish тільки для запитів профілювання, що надходять з вашого локального комп'ютера.

Знайдіть свою поточну IP-адресу:

1
$ curl https://ifconfig.me/

І використовуйте її для налаштування Varnish:

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/.platform/config.vcl
+++ b/.platform/config.vcl
@@ -1,3 +1,11 @@
+acl profile {
+   # Authorize the local IP address (replace with the IP found above)
+   "192.168.0.1";
+   # 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 +16,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-кеш на вашому локальному комп'ютері, у файлі config/packages/framework.yaml: якщо ні, ви профілюватимите шар HTTP-кешу Symfony, замість власного коду.

Щоб отримати краще уявлення про продуктивність вашого застосунку в продакшн, вам також слід профілювати "production" середовище. За замовчуванням ваше локальне середовище використовує середовище "development", яке додає значні накладні витрати (в основному для збору даних для панелі інструментів веб-наладження і профілювальника Symfony).

Note

Оскільки ми будемо профільувати «продакшн» середовище, у конфігурації нічого змінювати не потрібно, оскільки ми ввімкнули рівень HTTP-кешу Symfony лише для середовища «розробки» в попередньому розділі.

Перемкнути ваш локальний комп'ютер у продакшн середовище можна змінивши змінну середовища APP_ENV у файлі .env.local:

1
APP_ENV=prod

Або ви можете використовувати команду server:prod:

1
$ symfony server:prod

Не забудьте перемкнути її назад у середовище розробки, коли ваш сеанс профілювання завершиться:

1
$ symfony server:prod --off

Профілювання ресурсів API

Профілювання API чи ОЗ краще виконувати за допомогою Blackfire CLI, інструменту, який ви встановили раніше:

1
$ blackfire curl `symfony var:export SYMFONY_PROJECT_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
51
52
53
54
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] 'me@example.com'
            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")
                include login
                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')
                expect status_code() == 302
            follow
            click link("Comments")
                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 Player, щоб мати можливість виконувати сценарій локально:

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_PROJECT_DEFAULT_ROUTE_URL` .blackfire.yaml --variable "webmail_url=`symfony var:export MAILER_WEB_URL 2>/dev/null`" --variable="env=dev" -vv
1
$ rm blackfire-player.phar

Або в продакшн:

1
$ ./blackfire-player.phar run --endpoint=`symfony cloud:env:url --pipe --primary` .blackfire.yaml --variable "webmail_url=NONE" --variable="env=prod" -vv

Сценарії Blackfire також можуть профілювати кожен запит і виконувати тести продуктивності, додавши прапорець --blackfire.

Автоматизація перевірок продуктивності

Управління продуктивністю полягає не тільки в поліпшенні продуктивності наявного коду, але і в перевірці того, що внесені зміни не призводять до її регресії.

Сценарій, що написаний у попередньому розділі, може виконуватися автоматично в робочому процесі безперервної інтеграції або у продакшн, на регулярній основі.

Platform.sh також дозволяє виконувати сценарії щоразу, коли ви створюєте нову гілку чи розгортаєте у продакшн, щоб автоматично перевірити продуктивність нового коду.

Йдемо далі

  • Книга Blackfire: Пояснення продуктивності коду PHP;
  • Навчальний посібник SymfonyCasts: Blackfire.
Previous page Локалізація застосунку
Next page Дослідження внутрішніх механізмів Symfony
This work, including the code samples, is licensed under a Creative Commons BY-NC-SA 4.0 license.
TOC
    Version

    Symfony 5.4 is backed by

    Peruse our complete Symfony & PHP solutions catalog for your web development needs.

    Peruse our complete Symfony & PHP solutions catalog for your web development needs.

    Be safe against critical risks to your projects and businesses

    Be safe against critical risks to your projects and businesses

    Version:
    Locale:
    ebook

    This book is backed by:

    see all backers

    Symfony footer

    Avatar of Ilia Lazarev, a Symfony contributor

    Thanks Ilia Lazarev (@ilzrv) for being a Symfony contributor

    1 commit • 2 lines changed

    View all contributors that help us make Symfony

    Become a Symfony contributor

    Be an active part of the community and contribute ideas, code and bug fixes. Both experts and newcomers are welcome.

    Learn how to contribute

    Symfony™ is a trademark of Symfony SAS. All rights reserved.

    • What is Symfony?

      • What is Symfony?
      • Symfony at a Glance
      • Symfony Components
      • Symfony Releases
      • Security Policy
      • Logo & Screenshots
      • Trademark & Licenses
      • symfony1 Legacy
    • Learn Symfony

      • Symfony Docs
      • Symfony Book
      • Reference
      • Bundles
      • Best Practices
      • Training
      • eLearning Platform
      • Certification
    • Screencasts

      • Learn Symfony
      • Learn PHP
      • Learn JavaScript
      • Learn Drupal
      • Learn RESTful APIs
    • Community

      • Symfony Community
      • SymfonyConnect
      • Events & Meetups
      • Projects using Symfony
      • Contributors
      • Symfony Jobs
      • Backers
      • Code of Conduct
      • Downloads Stats
      • Support
    • Blog

      • All Blog Posts
      • A Week of Symfony
      • Case Studies
      • Cloud
      • Community
      • Conferences
      • Diversity
      • Living on the edge
      • Releases
      • Security Advisories
      • Symfony Insight
      • Twig
      • SensioLabs Blog
    • Services

      • SensioLabs services
      • Train developers
      • Manage your project quality
      • Improve your project performance
      • Host Symfony projects

      Powered by

    Follow Symfony