Оптимизация производительности на уровне PHP c помощью Blackfire

Данная статья будет частью серии публикаций посвященных созданию примера приложения – блога с галереей.(Репозитарий можно легко посмотреть здесь).

В данной статье мы применим Blackfire, чтобы улучшить производительность нашего приложения.

Установка

Значение настроек, которые используются при оценке графиков, созданных Blackfire.

  • Reference Profile: такой профиль будет основой оценки производительности приложения. Мы сможем сравнивать любой профиль с исходным для объективной оценки показателей производительности.
  • Exclusive Time: число времени, потраченное на выполнение возможности / способа, без учета времени на обработку внешних вызовов.
  • Inclusive Time: общее число времени, потраченное на выполнение возможности, включая обработку всех внешних вызовов.
  • Hot Paths: части приложения, которые были наиболее активными во время тестирования. Это могут быть части, которые занимают больше памяти или процессорного времени.

Первым шагом будет регистрация учетной записи в Blackfire. Страница учетной записи будет содержать токены и идентификаторы, которые потребуются для размещения в Homestead.yaml после клонирования проекта. Внизу есть форма для установки всех значений:

# blackfire:# - id: foo# token: bar# client-id: foo# client-token: bar

После этого надо установить браузерное расширение Chrome companion. Оно может запустить тестирование вручную. Также доступны и иные интеграции, полный список которых можно легко найти здесь.

Оптимизация с использованием Blackfire

Мы протестируем домашнюю страницу. Ведь она будет самой важной частью любого веб-сайта.

Эта версия приложения загружает все галереи и сортирует их по дате. Тестирование проводится просто. Мы открываем новую страницу, которую хотим оценить, кликаем по кнопке расширения в браузере и выбираем «Profile».

Посмотрите пример полученных результатов профилирования.

Время выполнения inclusive и exclusive составляет 100 % при выполнении PDO. У иных вызовов способов светло-розовая полоска может быть больше, чем у PDO. Но данные светло-розовые части представляют собой сумму всех зависимых возможностей. Это означает, что при индивидуальном рассмотрении данные возможности не представляют собой проблему.

Возможности, отмеченные темным тоном, должны быть обработаны в первую очередь. Кроме этого переключение в режим ОЗУ показывает, что пока весь вызов использовал 40 МБ ОЗУ, большая часть памяти приходится на рендеринг Twig.

Оптимизация производительности на уровне PHP c помощью Blackfire

На диаграмме hot paths имеют толстые границы и указывают на проблемные места.

Рассматривая проблемные способы и кликая по соответствующим узлам, можно определить, что PDOExecute будет самым слабым местом. А unserialize использует больше памяти, по сравнению с иными способами. Обе данные проблемы возникают из-за того, что мы загружаем весь набор галерей на главную страницу. Для их поиска и сортировки PDOExecute требуется слишком много памяти и времени, а Doctrine надо много ресурсов ЦП для их визуализации в unserialize и запуска в шаблоне twig. Решение кажется простым: добавить нумерацию на главную страницу!

Установив константу PER_PAGE в HomeController на 12 и используя ее в процедуре извлечения, мы блокируем первый вызов новых 12 галерей:

$galleries = $this->em->getRepository(Gallery::class)->findBy([], ['createdAt' => 'DESC'], self::PER_PAGE);

Мы будем использовать отложенную загрузку, когда посетитель достигнет конца страницы при прокрутке. Так что надо добавить код JavaScript:

{% block javascripts %} {{ parent() }}  <script>        $(function() {            var nextPage = 2;            var $galleriesContainer = $('.home__galleries-container');            var $lazyLoadCta = $('.home__lazy-load-cta');            function onScroll() {                var y = $(window).scrollTop() + $(window).outerHeight();                if(y >= $('body').innerHeight() - 100) {                    $(window).off('scroll.lazy-load');                    $lazyLoadCta.click();                }            }            $lazyLoadCta.on('click', function() {                var url = "{{ url('home.lazy-load') }}";                $.ajax({                    url: url,                    data: {page: nextPage},                    success: function(data) {                        if(data.success === true) {                            $galleriesContainer.append(data.data);                            nextPage++;                            $(window).on('scroll.lazy-load', onScroll);                        }                    }                });            });            $(window).on('scroll.lazy-load', onScroll);        });    </script>{% endblock %}

Мы используем аннотации, так что можно легко без проблем добавить новый способ в HomeController для выполнения отложенной загрузки галерей при их вызове:

/** * @Route("/galleries-lazy-load", name="home.lazy-load") */public function homeGalleriesLazyLoadAction(Request $request){    $page = $request->get('page', null);    if(empty($page)) {        return new JsonResponse([            'success' => false,            'msg'     => 'Page param is required',        ]);    }    $offset =($page - 1) * self::PER_PAGE;    $galleries = $this->em->getRepository(Gallery::class)->findBy([], ['createdAt' => 'DESC'], 12, $offset);    $view = $this->twig->render('partials/home-galleries-lazy-load.html.twig', [        'galleries' => $galleries,    ]);    return new JsonResponse([        'success' => true,        'data'    => $view,    ]);}

Сравнение

Сравним обновленное приложение с предыдущей версией. Сейчас веб-сайту требуется в 10 раз меньше памяти и загружается он гораздо быстрее. Согласно графику, сейчас самым ресурсоемким вызовом способа будет DebugClass.

Оптимизация производительности на уровне PHP c помощью Blackfire

Это происходит потому, что мы находимся в режиме разработки. Это надо, чтобы изменения, внесенные в программный код, можно легко было сразу проверить без необходимости очищать кеш APC или любой другой используемый кеш.

Если мы переключимся в режим prod(производственный), мы увидим заметную разницу.

Заключение

Скорость работы нашего приложения поражает –58 мс для загрузки страницы, без всякого загрузчика классов. Имейте в виду, что все это происходит на виртуальной машине с тысячами записей фиктивных данных. Добро пожаловать в мир непрерывного тестирования производительности!

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *