Zarządzanie wydajnością
Przedwczesna optymalizacja jest źródłem wszelkiego zła.
Ten cytat może już być Ci znany, ale lubię go w całości:
Powinniśmy zapomnieć o małych usprawnieniach, powiedzmy w około 97% przypadków: przedwczesna optymalizacja jest źródłem wszelkiego zła. Nie powinniśmy jednak rezygnować z możliwości zwiększenia wydajności w tych krytycznych trzech procentach.
-- Donald Knuth
Nawet niewielka poprawa wydajności może mieć znaczenie, zwłaszcza w przypadku sklepów internetowych. Teraz, gdy aplikacja księgi gości jest gotowa, zobaczmy, jak możemy sprawdzić jej wydajność.
Najlepszym sposobem na znalezienie optymalizacji wydajności jest użycie profilera. Najbardziej popularną obecnie opcją jest Blackfire (Ważna informacja: jestem również założycielem projektu Blackfire).
Przedstawienie Blackfire
Blackfire składa się z kilku części:
- Klient, który uruchamia profilowanie (narzędzie Blackfire CLI lub rozszerzenie przeglądarki dla Google Chrome lub Firefox);
- Agent, który przygotowuje i zbiera dane przed wysłaniem ich do serwisu blackfire.io w celu ich wyświetlenia;
- Rozszerzenie PHP (sonda), które analizuje wykonanie kodu PHP.
Aby pracować z Blackfire, najpierw musisz się zarejestrować.
Zainstaluj Blackfire na swoim komputerze, uruchamiając następujący skrypt instalacyjny:
1
$ curl https://installer.blackfire.io/installer.sh | bash
Instalator pobiera i instaluje narzędzie Blackfire CLI.
Po zakończeniu, zainstaluj sondę dla wszystkich dostępnych wersji PHP:
1
$ sudo blackfire php:install
Włącz też sondę PHP dla naszego projektu:
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
Uruchom ponownie serwer WWW, aby PHP mógł załadować Blackfire:
1 2
$ symfony server:stop
$ symfony server:start -d
Aby powiązać profile z Twoim kontem, narzędzie Blackfire CLI po zainstalowaniu musi być skonfigurowane Twoimi danymi uwierzytelniającymi, które znajdziesz na górze strony Settings/Credentials. Wykonaj następujące polecenie podmieniając symbole zastępcze:
1
$ blackfire client:config --client-id=xxx --client-token=xxx
Instalowanie agenta Blackfire na Dockerze
Usługa agenta Blackfire została już skonfigurowana w stosie Docker Compose:
Aby komunikować się z serwerem, musisz uzyskać swoje dane uwierzytelniające do serwera (te dane wskazują, gdzie chcesz przechowywać profile -- możesz utworzyć jeden na projekt); można je znaleźć na dole strony Settings/Credentials. Przechowuj je pośród poufnych danych:
1 2 3 4
$ symfony console secrets:set BLACKFIRE_SERVER_ID
# xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
$ symfony console secrets:set BLACKFIRE_SERVER_TOKEN
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Możesz już uruchomić nowy kontener:
1 2
$ docker-compose stop
$ docker-compose up -d
Naprawianie niedziałającej instalacji Blackfire
Jeśli podczas profilowania pojawi się błąd, zwiększ poziom logowania Blackfire, aby uzyskać więcej informacji w logach:
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
Uruchom ponownie serwer WWW:
1 2
$ symfony server:stop
$ symfony server:start -d
A następnie śledź logi:
1
$ symfony server:log
Wykonaj profilowanie ponownie i sprawdź wyjście logów.
Konfigurowanie Blackfire w środowisku produkcyjnym
Blackfire jest domyślnie włączony dla wszystkich projektów Platform.sh.
Ustaw dane uwierzytelniające serwera jako poufne dane produkcyjne:
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
Sonda PHP jest już włączona, jak każde inne potrzebne rozszerzenie PHP:
Konfigurowanie serwera Varnish dla Blackfire
Zanim będziesz w stanie wykonać wdrożenie potrzebne do rozpoczęcia profilowania, potrzebujesz sposobu na ominięcie pamięci podręcznej Varnish HTTP. W innym przypadku, Blackfire nigdy nie odpyta aplikacji PHP. Będziesz autoryzować tylko prośby o profilowanie pochodzące z twojej lokalnej maszyny.
Znajdź swój bieżący adres IP:
1
$ curl https://ifconfig.me/
I użyj go, aby skonfigurować 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 {
Teraz możesz wdrożyć.
Profilowanie stron internetowych
Możesz profilować tradycyjne strony internetowe używając Firefoksa lub Google Chrome poprzez ich dedykowane rozszerzenia.
Na lokalnym komputerze, podczas profilowania, nie zapomnij wyłączyć pamięci podręcznej HTTP w config/packages/framework.yaml
: jeśli tego nie zrobisz, będziesz profilować warstwę pamięci podręcznej HTTP Symfony zamiast własnego kodu.
Aby uzyskać lepszy obraz wydajności Twojej aplikacji w środowisku produkcyjnym, należy je również profilować. Domyślnie, twoje lokalne środowisko korzysta ze środowiska deweloperskiego, które dodaje znaczny narzut (głównie w celu zebrania danych dla paska narzędzi do debugowania sieci i profilera Symfony).
Note
Ponieważ będziemy profilować środowisko produkcyjne, nie ma nic do zmiany w konfiguracji, ponieważ w poprzednim rozdziale włączyliśmy warstwę pamięci podręcznej HTTP Symfony tylko dla środowiska produkcyjnego.
Przełączenie maszyny lokalnej do środowiska produkcyjnego można wykonać poprzez zmianę zmiennej środowiskowej APP_ENV
w pliku .env.local
:
1
APP_ENV=prod
Albo możesz użyć polecenia server:prod
:
1
$ symfony server:prod
Nie zapomnij przełączyć go z powrotem na środowisko deweloperskie po zakończeniu sesji profilowania:
1
$ symfony server:prod --off
Profilowanie zasobów API
Profilowanie API lub SPA jest wygodniejsze z poziomu linii komend, za pomocą zainstalowanego wcześniej narzędzia Blackfire CLI:
1
$ blackfire curl `symfony var:export SYMFONY_PROJECT_DEFAULT_ROUTE_URL`api
Polecenie blackfire curl
akceptuje dokładnie takie same argumenty i opcje jak cURL.
Porównanie wydajności
W etapie poświęconym pamięci podręcznej dodaliśmy warstwę pamięci podręcznej, aby poprawić wydajność naszego kodu, ale nie sprawdziliśmy ani nie zmierzyliśmy wpływu zmiany na wydajność. Ponieważ źle nam idzie zgadywanie, co będzie szybkie, a co powolne, możesz znaleźć się w sytuacji, w której niektóre usprawnienia spowalniają działanie Twojej aplikacji.
Za każdym razem należy zmierzyć wpływ wszelkich optymalizacji, które robisz za pomocą profilera. Blackfire ułatwia wizualne ich porównanie dzięki narzędziu porównywania.
Tworzenie czarnoskrzynkowych testów funkcjonalnych (ang. black box)
Dowiedzieliśmy się już, jak pisać testy funkcjonalne z Symfony. Blackfire może być używany do pisania scenariuszy przeglądania, które mogą być uruchamiane na żądanie przez odtwarzacz Blackfire. Napiszmy scenariusz, który przesyła nowy komentarz i zatwierdza go poprzez link e-mailowy w środowisku deweloperskim oraz przez konto administracyjne w środowisku produkcyjnym.
Utwórz plik .blackfire.yaml
o następującej zawartości:
Pobierz odtwarzacz Blackfire, aby móc uruchomić scenariusz lokalnie:
1 2
$ curl -OLsS https://get.blackfire.io/blackfire-player.phar
$ chmod +x blackfire-player.phar
Uruchomienie tego scenariusza w środowisku deweloperskim:
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
Albo w środowisku produkcyjnym:
1
$ ./blackfire-player.phar run --endpoint=`symfony cloud:env:url --pipe --primary` .blackfire.yaml --variable "webmail_url=NONE" --variable="env=prod" -vv
Scenariusze Blackfire mogą również wyzwalać profilowanie dla każdego żądania i uruchamiać testy wydajności poprzez dodanie flagi --blackfire
.
Automatyzowanie kontroli wydajności
Zarządzanie wydajnością polega nie tylko na poprawie wydajności istniejącego kodu, ale również na sprawdzeniu, czy dotychczasowe działania wydajności nie zmniejszyły.
Scenariusz napisany w poprzedniej sekcji może być uruchamiany automatycznie w trybie ciągłej integracji (ang. continuous integration) lub w środowisku produkcyjnym w regularnych odstępach.
Platform.sh pozwala również na uruchamianie scenariuszy, gdy tworzysz nową gałąź lub wdrażasz w środowisku produkcyjnym, aby automatycznie sprawdzić wydajność nowego kodu.