• Save
Dynamiczna analiza aplikacji php - meet.php
Upcoming SlideShare
Loading in...5
×
 

Dynamiczna analiza aplikacji php - meet.php

on

  • 1,044 views

Dynamiczna analiza aplikacji php z uzyciem Xhprof

Dynamiczna analiza aplikacji php z uzyciem Xhprof
meet.php#6
Poznan, 11.08.2012

Statistics

Views

Total Views
1,044
Views on SlideShare
1,043
Embed Views
1

Actions

Likes
2
Downloads
0
Comments
0

1 Embed 1

https://twitter.com 1

Accessibility

Categories

Upload Details

Uploaded via as OpenOffice

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • Część, jestem Wojtek Stryszyk, pracuje w Allegro gdzie zajmuje się obszarami zwiazanymi z wydajnoscia aplikacji. Między innymi poszukuje rozwiazań które pozwolą okiełznać i panowac nad wydajnoscia dość dużej aplikacji do jakiej urosło Allegro tworzone przez ponad 10 lat przez kilkudziesieciu ludzi. W sumie wyszło pewnie tysiące plików i pewnie miliony linii kodu PHP.
  • Skad wiemy....? Zwykle sie domyslamy, czesto mierzymy stan zasobow, load na WWW, uzycie CPU czy uzycie pamieci i z wykresow widzimy kiedy zbliżamy się do sufitu. Gorzej gdy dowiadujemy sie od uzytkownikow ktorzy zamiast swojej ulubionej strony ogladaja legendarna juz gabke. Niestety wydajność aplikacji nie jest zagadnieniem z którym jest łatwo sobie poradzić używając samej intuicji. Pol biedy jesli jest sie autorem calego kodu, coraz czesciej jednak pracujemy w wieloosobowych zespolach, korzystamy z frameworkow, zewnetrznych bibliotek i chcac nie chcac w ktoryms momencie przestajemy nadazac nad ciagle rozrastajacym sie kodem. Gdy zaczyna brakowac zasobów, mamy do wyboru dolozyc kolejnego WWWsa, albo przyjrzec sie czy nie daloby sie odchudzic naszego dzieła. Tylko jak to zrobic z aplikacja ktorej niektore zakamarki staja sie coraz bardziej obce, a rozgrzane WWW-sy pilnie potrzebuja odrobiny wytchnienia? Oczywiscie trzeba jakos nasza aplikacje pomierzyc. Z namy już metryki statyczne, a teraz chcialbym zaprezentowac dopelniajaca metode oceny jakosci kodu czyli analize dynamiczna. Gdy zapytalem znajomych czy mierza wydajność napisanego przez nich kod, większość odpowiedzialo 'nie lub rzadko' tlumaczac się brakiem wiedzy czy tez brakiem czasu. Postaram się pokazac ze profilowanie nie jest żadna tajemna wiedza i nie jest ani skomplikowane ani czasochlonne.
  • Profilowanie to badanie zachowania programu używając informacji zdobytych podczas jego wykonywania mowiac wprost jest to tak zwane rozpoznanie walka. Celem jest poznanie najwolniejszych lub najbardziej zasobochlonnych fragmentów kodu. A co mierzymy? {klik} Mierzymy bardziej konkretne parametry niż w przypadku metryk statycznych tzn dla kazdej pojedynczej instrukcji: - liczbe wywpłań w pojedynczym przejsciu -czas wykonania -czas procesora -uzycie pamieci Dla latwiejszej lokalizacji wywoływaną funkcję wiążemy w wyniku z funkcją nadrzedną lub z miejscem wywolania czyli nazwa pliku i linią
  • Można analizować każdy pojedynczy request. Można porównać 2 równoważne requesty... Co jednak jeśli requestów mamy miliony? Które wybrać? Dodatkowo kazdy request może w zaleznosci od prametrow mieć rozna sciezke przejsc. Wykres aplikacja jako całość Pierwszym krokiem mogłoby być podzielenie aplikacji na jakieś logiczne grupy (np.: każdy kontroler to wydzielona grupa): zrobic z tego wykres, zamiast nazw plików, nazwy funkcjonalnosci Jednak weźmy na przykład pierwsze 2 grupy: WebAPI i ShowItem ilość requestów w tych 2 grupach jest porównywalna jednak niekoniecznie porównywalna może być ich jakość. W ogólności funkcjonalność z miejsca 20 może zużywać więcej cykli CPU niż funkcjonalność z pozycji pierwszej wykres z rozbiciem na funkcjonalności, oraz zobrazowaniem udziału funkcjonalności w utylizacji CPU Aby jeszcze bardziej skomplikować zagadnienie zauważmy, że owe webapi jak i każdą kolejną grupę można by było rozbić chociażby wg parametrów wywołań. Podejście do mierzenia tak rozdrobnionej aplikacji doprowadziło by każdego do bólu głowy. Jak to zatem ugryźć? Po wielu próbach z różnymi metodami podejścia do dekompozycji oraz szczegółowości podziału aplikacji doszedłem do wniosku, że najlepiej: wrócić do wykresu pierwszego czyli wrzucić wszystko do jednego worka a jakość wyniku końcowego pomiaru pozostawić na statystyce. Ma to szczególnie zastosowanie jeśli możemy sobie pozwolić na pomiary przy ruchu produkcyjnym (małe obciążenie xhprof) lub odtwarzając ruch syntetyczny w środowisku testowym – dostajemy wówczas najbardziej reprezentatywny obraz aplikacji. W efekcie dostaniemy: jedną listę metod posortowana wg zużycia zasobów/ilości wywołań optymalizujemy utylizacje zasobów maszyny, traktując aplikację jako całość na szczycie listy pojawiają się metody z najpopularniejszych requestów lub ekstremalnie słabe bloku kodu
  • Można analizować każdy pojedynczy request. Można porównać 2 równoważne requesty... Co jednak jeśli requestów mamy miliony? Które wybrać? Dodatkowo kazdy request może w zaleznosci od prametrow mieć rozna sciezke przejsc. Wykres aplikacja jako całość Pierwszym krokiem mogłoby być podzielenie aplikacji na jakieś logiczne grupy (np.: każdy kontroler to wydzielona grupa): zrobic z tego wykres, zamiast nazw plików, nazwy funkcjonalnosci Jednak weźmy na przykład pierwsze 2 grupy: WebAPI i ShowItem ilość requestów w tych 2 grupach jest porównywalna jednak niekoniecznie porównywalna może być ich jakość. W ogólności funkcjonalność z miejsca 20 może zużywać więcej cykli CPU niż funkcjonalność z pozycji pierwszej wykres z rozbiciem na funkcjonalności, oraz zobrazowaniem udziału funkcjonalności w utylizacji CPU Aby jeszcze bardziej skomplikować zagadnienie zauważmy, że owe webapi jak i każdą kolejną grupę można by było rozbić chociażby wg parametrów wywołań. Podejście do mierzenia tak rozdrobnionej aplikacji doprowadziło by każdego do bólu głowy. Jak to zatem ugryźć? Po wielu próbach z różnymi metodami podejścia do dekompozycji oraz szczegółowości podziału aplikacji doszedłem do wniosku, że najlepiej: wrócić do wykresu pierwszego czyli wrzucić wszystko do jednego worka a jakość wyniku końcowego pomiaru pozostawić na statystyce. Ma to szczególnie zastosowanie jeśli możemy sobie pozwolić na pomiary przy ruchu produkcyjnym (małe obciążenie xhprof) lub odtwarzając ruch syntetyczny w środowisku testowym – dostajemy wówczas najbardziej reprezentatywny obraz aplikacji. W efekcie dostaniemy: jedną listę metod posortowana wg zużycia zasobów/ilości wywołań optymalizujemy utylizacje zasobów maszyny, traktując aplikację jako całość na szczycie listy pojawiają się metody z najpopularniejszych requestów lub ekstremalnie słabe bloku kodu
  • Można analizować każdy pojedynczy request. Można porównać 2 równoważne requesty... Co jednak jeśli requestów mamy miliony? Które wybrać? Dodatkowo kazdy request może w zaleznosci od prametrow mieć rozna sciezke przejsc. Wykres aplikacja jako całość Pierwszym krokiem mogłoby być podzielenie aplikacji na jakieś logiczne grupy (np.: każdy kontroler to wydzielona grupa): zrobic z tego wykres, zamiast nazw plików, nazwy funkcjonalnosci Jednak weźmy na przykład pierwsze 2 grupy: WebAPI i ShowItem ilość requestów w tych 2 grupach jest porównywalna jednak niekoniecznie porównywalna może być ich jakość. W ogólności funkcjonalność z miejsca 20 może zużywać więcej cykli CPU niż funkcjonalność z pozycji pierwszej wykres z rozbiciem na funkcjonalności, oraz zobrazowaniem udziału funkcjonalności w utylizacji CPU Aby jeszcze bardziej skomplikować zagadnienie zauważmy, że owe webapi jak i każdą kolejną grupę można by było rozbić chociażby wg parametrów wywołań. Podejście do mierzenia tak rozdrobnionej aplikacji doprowadziło by każdego do bólu głowy. Jak to zatem ugryźć? Po wielu próbach z różnymi metodami podejścia do dekompozycji oraz szczegółowości podziału aplikacji doszedłem do wniosku, że najlepiej: wrócić do wykresu pierwszego czyli wrzucić wszystko do jednego worka a jakość wyniku końcowego pomiaru pozostawić na statystyce. Ma to szczególnie zastosowanie jeśli możemy sobie pozwolić na pomiary przy ruchu produkcyjnym (małe obciążenie xhprof) lub odtwarzając ruch syntetyczny w środowisku testowym – dostajemy wówczas najbardziej reprezentatywny obraz aplikacji. W efekcie dostaniemy: jedną listę metod posortowana wg zużycia zasobów/ilości wywołań optymalizujemy utylizacje zasobów maszyny, traktując aplikację jako całość na szczycie listy pojawiają się metody z najpopularniejszych requestów lub ekstremalnie słabe bloku kodu
  • W historii allegro testowalismy 2 najbardziej popularne narzedzia. Od 2008 r uzywalismy xdebug-a, natomiast w tym roku przeszlismy na facebookowego xhprof. {klik} Oba narzedzia są równie uzyteczne. Funkcjonalnie xdebug ma nawet większe mozliwosci, ale xhprof ma 2 podstawowe zalety: -jest znaczaco lzejszy od xdebuga, do tego stopnia ze profilujemy 100% ruchu standardowego WWW-sa z farmy, bez wplywu na jego wydajnosc, -xhprof – zlicza czas procesora przez jaki mierzona funkcja działała – jest to lepsze od mierzenia czasu brutto, do którego liczą się wszystkie wait-y czyli m.in. sleep-y czy operacje na socketach itepe
  • Do uruchomienia potrzebujemy -zainstalowany modul xhprof – robimy to jak kazde inne rozszerzenie z pecl-a oraz -jawnie wskazac gdzie profiler ma zaczac a gdzie skonczyc. Ponieważ zwykle chcemy zmierzyc cały pojedynczy przebieg , dlatego najprosciej do auto_prepend-a wrzucamy funkcje xhprof_enable(), a do shutdown_functions xhprof_disable(). Na wyjsciu otrzymujemy tablice zsumowanych czasow i ilosc wywołań dla kazdej pary funkcja/parent, która zapisujemy np. do pliku do pozniejszej analizy. Cala operacja nie powinna zajac więcej niż 3 minuty. W fukcji xhprof_enable mozemy włączyc 3 parametry profilera. Domyslnie zliczana jest tylko ilosc wywolan instrukcji/funkcji oraz czas ich trwania. Opcjonalnie można wlaczyc cpu time oraz uzycie pamieci. Trzecia opcja jest wybor czy mierzymy czasy dla wbudowanych funkcji standartowych php.
  • Agregowanie wynikow z poszczegolnych requestów Dla pojedynczego requestu xhprof zapisuje zsumowane pogrupowane wyniki wg funkcji i funkcji rodzica w postaci tablicy: $data[function_name][parent_function_name] = array( call_counter, cpu, time, memory_usage) Wyniki kolejne requestów latwo jest sumowac grupujac je za wybrany czas.
  • Mając listę funkcji wraz z metrykami pozostaje nam interpretacja wyników. Pomocne do tego jest przejrzyste zobrazowanie wyników. Dolączony do xhprof UI pozwala na zaprezentowanie wyników pomiaru, zawiera , podsumowanie z ogólną statystyką oraz tabelę wszystkich wywołań funkcji, które można sortować według kilku parametrów: ilość wywołań CPU – inclusive i exclusive czas (Wall) – inclusive i exclusive Czas Inclusive obejmuje czas spędzony w samej funkcji i we wszystkich funkcjach potomnych Exclusive czas spędzony w samej funkcji. {klik} Ponieważ xhprof agreguje wyniki funkcji z kontekstem możemy w każdej chwili podejrzeć szczegóły dotyczące funkcji nadrzednej, czy też wywołań wewnątrz funkcji.
  • Mając listę funkcji wraz z metrykami pozostaje nam interpretacja wyników. Pomocne do tego jest przejrzyste zobrazowanie wyników. Dolączony do xhprof UI pozwala na zaprezentowanie wyników pomiaru, zawiera , podsumowanie z ogólną statystyką oraz tabelę wszystkich wywołań funkcji, które można sortować według kilku parametrów: ilość wywołań CPU – inclusive i exclusive czas (Wall) – inclusive i exclusive Czas Inclusive obejmuje czas spędzony w samej funkcji i we wszystkich funkcjach potomnych Exclusive czas spędzony w samej funkcji. {klik} Ponieważ xhprof agreguje wyniki funkcji z kontekstem możemy w każdej chwili podejrzeć szczegóły dotyczące funkcji nadrzednej, czy też wywołań wewnątrz funkcji.
  • Zachowując historię z poszczególnych okresów pomiarowych można pokusić się o śledzenie zmienności udziału poszczególnych metod w ruchu np.: dobowym. Na przykładzie można zaobserwowac utrzymujacy się trend a pierwsze 10 metod utylizuje 20% cpu, pierwsze 20 metod 28%. Jest to wskazówka potwierdzająca zasadę pareto.
  • Warto pamiętać o zasadzie pareto i zajmować się funkcjami z góry listy. Dluga na kilkanascie tysiecy lista nie powinna nas rozpraszać, ani jakoś specjalnie zajmować. Iteracyjne optymalizacje powinny stopniowo spłaszczać charakterystykę udziału instrukcji w czasie wykonania/cpu
  • Doswiadczenie pokazuje ze optymalizacje większości aplikacji robi się w skonczonej liczbie krokow. Zazwyczaj problemy jakie wystepuja powtarzaja się i są zwiazane najczesciej z ograniczeniami systemu. Zatem w większości przypadkow przy pierwszej iteracji na szczycie listy pojawia się;: Popularne pozycje na szczycie listy: operacje na socketach (wszystkie zdalne źródła danych) operacje na plikach, także include-y ( file_init/run_init ) długie pętle niektóre wbudowane funkcje php np.: define, defined operacje na stringach, wyrazenia regularne Jak się przed nimi chronic? -rozwazyc sensownosc wybranego bloku kodu -sprobowac zoptymalizowac -uzywac cache tam gdzie się da -unikac zewnetrznych zrodel danych -filtrowac dane (ograniczenie petli z przy fetchowaniu)

Dynamiczna analiza aplikacji php - meet.php Dynamiczna analiza aplikacji php - meet.php Presentation Transcript

  • Dynamiczna analiza aplikacji PHP Wojciech Stryszyk meet.php#6, Poznań, 11.08.2012
  • Skąd wiemy że aplikacja jest wydajna?20.08.12 Dynamiczna analiza aplikacji PHP 2
  • Profilowanie aplikacji Co mierzymy? • liczbę wywołań instrukcji • czas wykonania pojedynczej instrukcji • czas procesora • użycie pamięci20.08.12 Dynamiczna analiza aplikacji PHP 3
  • 20.08.12 % requestów w próbie 0 2 4 6 8 10 12 14 16 18 20 Webapi ShowItem Listing Suggest ShowCategories Search MainpagePromo Mainpage MainpagePromo2 UserAuctions ShowCase Login MyAccount Cafe Webapi2Dynamiczna analiza aplikacji PHP ShowUser Banners MyAccount2 Ilosc requestów wybranych funkcjonalności w jednostce czasu Rss Czas Login2 Moja aplikacja jest skomplikowana!4
  • 20.08.12 % requestów w próbie 0 2 4 6 8 10 12 14 16 18 20 Webapi ShowItem Listing Suggest ShowCategories Search MainpagePromo Mainpage MainpagePromo2 UserAuctions ShowCase Login MyAccount Cafe Webapi2Dynamiczna analiza aplikacji PHP ShowUser Banners MyAccount2 Rss Login2 Ilosc requestów wybranych funkcjonalności oraz uzycie CPU w jednostce czasu Czas % CPU w próbie Moja aplikacja jest skomplikowana!5
  • Moja aplikacja jest skomplikowana! Wrzuć wszystko do jednego worka i pozwól zadziałać statystyce20.08.12 Dynamiczna analiza aplikacji PHP 6
  • Warsztat pracy- Xdebug – WinCacheGrind, KCacheGrind- Xhprof + XH GUI20.08.12 Dynamiczna analiza aplikacji PHP 7
  • Instalacja i uruchomienie xhprof • Instalacja standartowo z pecl-a • Uruchomienie: xhprof_enable( XHPROF_FLAGS_CPU | XHPROF_FLAGS_MEMORY | XHPROF_FLAGS_NO_BUILTINS ); /* the code you want to profile */ $xhprof_data = xhprof_disable();20.08.12 Dynamiczna analiza aplikacji PHP 8
  • Format danych xhprof Array ( [main()==>strlen] => Array ( [ct] => 1 [wt] => 279 ) [main()==>xhprof_disable] => Array ( [ct] => 1 [wt] => 9 ) [main()] => Array ( [ct] => 1 [wt] => 610 ) )20.08.12 Dynamiczna analiza aplikacji PHP 9
  • Prezentacja wyników20.08.12 Dynamiczna analiza aplikacji PHP 10
  • Prezentacja wyników20.08.12 Dynamiczna analiza aplikacji PHP 11
  • Obserwacja trendu Z serii kilkunastu tysięcy instrukcji jakie wywoływane są w pojedyńczym przebiegu, pierwszych kilkadziesiąt funkcji tj. zwykle < 1% utylizuje nawet 80% CPU !20.08.12 Dynamiczna analiza aplikacji PHP 12
  • Analiza wynikówNa co zwracać uwagę?• Duże wartości liczby wywołań funkcji• Procentowy udział instrukcji w czasie wykonania/czasie CPU całej próby 20.08.12 Dynamiczna analiza aplikacji PHP 13
  • PHP-owi recydywiści Popularne pozycje na szczycie listy najciężczych instrukcji:• operacje na socketach (wszystkie zdalne źródła danych)• operacje na plikach, także include-y, file_exists• długie pętle• niektóre wbudowane funkcje php np.: define, defined, is_numeric, array_key_exists• operacje na stringach, wyrazenia regularne 20.08.12 Dynamiczna analiza aplikacji PHP 14
  • Pytania?20.08.12 Dynamiczna analiza aplikacji PHP 15