Dziś jest poniedziałek, 13 października 2008 roku (z kalendarza...)

Formaty danych: benchmark

Icon

04.09.2007, 13:04

PHP

Komentarze (9)

Powrót

Napisałem już trochę kilobajtów kodu nowego silnika, lecz wciąż nie zdecydowałem się na jeden, konkretny format przechowywania konfiguracji oraz plików informacyjnych. Podstawowe pytania to: jakich możliwości od danego formatu oczekuję oraz jak przedstawia się sprawa wydajności. Dlatego postanowiłem zrobić mały benchmark i uszeregować wszystkie formaty, jakie zdołałem do czasu napisania wpisu wymyślić w kolejności od najszybszego do najwolniejszego. W szranki stanęły: zserializowane tablice, same skrypty PHP, pliki INI, XML oraz YAML. Pierwsze cztery obsługiwane są "sprzętowo" przez interpreter, w ostatnim przypadku trzeba zadowolić się napisanym w PHP parserem Spyc.

Test był prosty. Należało wczytać do pamięci listę pięćdziesięciu opcji konfiguracyjnych podzielonych na pięć grup. Dodatkowo w pliku znajdowało się dziesięć identycznych komentarzy. Każdy ze skryptów musiał załadować to wszystko do zmiennej $info i tyle - wyświetlenie już nie było potrzebne. Konfiguracja w każdym przypadku była przechowywana w osobnym pliku (tak więc nawet "skrypt PHP" musiał wykonać operację require), a wszystko po to, że normalnie właśnie z czymś takim mamy do czynienia i aplikacja jakieś operacje dyskowe musi wykonać. Skrypty są tak proste, że każdy może podobną procedurę na bazie opisu samodzielnie zrealizować w kwadrans i nie ma sensu ich tutaj publikować. Opiszę teraz każdy z testowanych formatów oraz to, czego się po nim spodziewałem:

  • Zserializowane tablice - jest to zwykła reprezentacja tablicy lub obiektu PHP za pomocą ciągu tekstowego, dzięki czemu można ją przesyłać np. w ciastkach. Format jest zoptymalizowany do przetwarzania maszynowego, dlatego ręczna edycja takich danych to masochizm. Najbardziej jest przydatny, gdy skrypt musi scache'ować jakieś dane w celu użycia przez późniejsze żądania HTTP. Szybkość przetwarzania zserializowanych tablic mierzyłem już wcześniej i wiem, że pod tym względem nie powinny mieć one konkurencji.
  • Pliki INI - PHP posiada parser plików INI z identyczną składnią, jak php.ini. Wystarcza on w zupełności do reprezentowania zbioru par nazwa => wartość, opcjonalnie podzielonych na grupy oraz z komentarzami, ale bardziej skomplikowane relacje (np. takie, jakie spotykamy w Zend Frameworku), trzeba implementować samemu.
  • XML - format bardzo rozbudowany i umożliwia reprezentację nawet bardzo złożonych zbiorów. Ponadto istnieje szereg dedykowanych narzędzi do edycji oraz przetwarzania XML. Możemy łatwo sprawdzić poprawność pliku lub sformatować go poprzez XSLT. Z drugiej strony, jego składnia jest przydługawa i najprostsze rzeczy ciągną się na wiele znaków kodu, zaś oferowana ilość możliwości jest często zbyt duża - gdy widzę, że ktoś używa go do zwyczajnego reprezentowania par nazwa => wartość bez jakiejś naprawdę wyższej przyczyny, to mnie coś trafia (np. wspomnianego formatowania, choć osobiście nie wiem, na co komu formatowanie konfiguracji każdego poranka :)).
  • YAML - stosunkowo młody język opisu danych, którego zaletą jest duże zbliżenie do naturalnego dla typowego człowieka zapisu (tyle że ustandaryzowane) oraz możliwość przetwarzania nawet prostymi wyrażeniami regularnymi, jako że składnia jest łatwa do obróbki maszynowej. YAML wykorzystują niektóre z frameworków, także tych napisanych w PHP. Z drugiej strony nie ma tutaj DTD, XSLT i jeśli ktoś bez tego żyć nie może, to będzie narzekać. Ponadto, dla PHP wciąż nie istnieje żadne kompilowane rozszerzenie służące do przetwarzania YAML, tak więc jesteśmy skazani na skryptowe parsery, co budziło u mnie obawy, jeśli chodzi o wydajność. W testach wykorzystałem parser Spyc.
  • Skrypty PHP - wiele aplikacji zapisuje swoje konfiguracje bezpośrednio jako pewien plik PHP, w którym inicjowanych jest nieco zmiennych. Zaleta to możliwość przetworzenia bezpośrednio przez parser PHP, lecz z drugiej strony biada temu, kto popełni jakiś błąd składni, albo dopisze do skryptu jakiś złośliwy kod. Ponadto tworzenie bardzo rozbudowanych struktur nie musi być wygodne - to zależy od przyjętych konwencji, ponieważ tu możemy dosłownie wszystko.

Do testowania wykorzystałem program Apache Bench z opcjami -n 500 -c 50 (wyślij 500 żądań HTTP, po 50 jednoczesnych). Oto wyniki po kilku próbach w kolejności od najlepszego:

  1. Zserializowane tablice - ok. 4160 req/s.
  2. Skrypty PHP - ok. 3780 req/s.
  3. Pliki INI - zazwyczaj ok. 3300 req/s, ale bywały też sięgające 3900 req/s.
  4. XML - ok. 2800 req/s.
  5. YAML - ok. 250 req/s.

Tak, jak przypuszczałem - skryptowy parser YAML-a zupełnie nie poradził sobie w konkurencji z parserem XML, lecz ten z kolei przegrał z prostszymi formatami. Zastanawiające może być, że pliki INI o całkiem prostej składni są przetwarzane wolniej, niż skrypty PHP. Wniosek jest jeden: twórcy nie przywiązywali dużej wagi do optymalizacji prostszego parsera, gdyż przede wszystkim służy on jedynie do załadowania pliku php.ini, a to jest robione raz na długi czas. Spróbowałem sprawdzić, czy jest dla YAML-a jakiś ratunek poprzez cache'owanie wyniku działania w zserializowanych tablicach. Przerobiony skrypt musiał sprawdzić, czy istnieje scache'owana wersja i jeśli nie, to ją wygenerować. Rezultat znacznie się poprawił, aczkolwiek nadal nie dogonił reszty - ok. 850 req/s.

Podsumowując: dla prostych danych pozostanę przy plikach INI oraz tablicach tworzonych bezpośrednio w skryptach. Bardziej złożoną zawartość pozostawię parserowi XML wspomożonemu przez zserializowane tablice. Niestety, dopóki nie pojawi się szeroko stosowane i kompilowane rozszerzenie do parsowania YAML, w aplikacjach kładących duży nacisk na wydajność nie widzę za bardzo miejsca, chyba że przy jakichś sporadycznie wykonywanych operacjach.

Dopisek: mała poprawka, rozszerzenie do YAML jest już w repozytorium PECL, ale w wersji mocno-beta. Przeoczyłem je z powodu idiotycznej wyszukiwarki pakietów, która na zapytanie "YAML" pokazała odpowiedź "No matches found". Postaram się je skompilować i dołączyć wyniki z testów do wpisu.

Powrót

Komentarze

Napisał Anonymous w wtorek, 4 września 2007 o 16:50

Przechowuję konfigurację w plikach .PHP, lecz myślę, czy nie przenieść się na zserializowane tablice. Zaleta - nie potrzeba funkcji zapisującej poprawnie te dane. Jest jeden problem - jeśli na serwerze .htaccess nie działa, każdy sobie zobaczy zawartość pliku (dotyczy szczególnie darmowych kont). Którą metodę z tych 2 więc lepiej zastosować?

Napisał seaquest w wtorek, 4 września 2007 o 19:17

A dlaczego nie użyć yaml + cache w formie zserializowanej tablicy?

yaml jest bardzo przyjazny dla oka, a serializacja bardzo szybka.

Ja kiedyś porównywałem prędkość serializacji i includowania tablicy. Nawet gdzieś na mojej stronce chyba odpowiedni art na ten temat jest.

Napisał eRIZ w wtorek, 4 września 2007 o 20:48

> Którą metodę z tych 2 więc lepiej zastosować?
A chmod dla "other" na 0 by nie wystarczył...?

Napisał sopel w wtorek, 4 września 2007 o 21:07

a co ze starymy zwykłymi PHPowskimi tablicami?

Napisał splatch w wtorek, 4 września 2007 o 22:18

W jaki sposób obsłużyłeś XML - czy był to DOM/SAX/SimpleXML a może XMLReader? Może warto pokusić się również o porównanie tych narzędzi? :-)

Pozdrawiam,
Łukasz

Napisał Zyx w środę, 5 września 2007 o 08:54

Seaquest -> wiem, że serializacja jest szybsza, ale żeby prawidłowo obsłużyć taki cache, trzeba wykonać więcej operacji dyskowych, ponadto zadziała to skutecznie dopiero wtedy, gdy Spyc będzie ładowany jedynie, gdy go potrzeba. Ale masz rację, serializacja i cache'owanie YAML-a to pestka w porównaniu w XML-em :).

Sopel -> patrz pozycja "Skrypty PHP".

eRIZ -> jeśli skrypt wykonywany jest na prawach serwera (czyli mod_php), to nic to nie da, jeśli nie będzie safe_mode włączony i poprawnie ustawiony. Musiałbyś dać grupie prawa na "0", ale wtedy zablokowałbyś dostęp samemu Apache'owi :).

Splatch -> to był SimpleXML. Jeśli dwa narzędzia korzystają z tej samej biblioteki XML, to różnice wydajnościowe będą jedynie wynikać z jej implementacji w samym PHP.

Napisał Anonymous w środę, 5 września 2007 o 13:28

W takim razie jedynym sposobem zabezpieczenia pliku ze zserializowaną tablicą jest .htaccess? Nie mówimy o konfiguracji Apache, bo do niej zazwyczaj nie mamy dostępu.

Napisał Zyx w środę, 5 września 2007 o 15:46

Jeśli chodzi o dostęp z przeglądarki - można umieścić konfigurację poza publicznym katalogiem, albo zabezpieczyć przez .htaccess. Jednak jeśli serwer jest źle skonfigurowany, właściciel innego konta, znając jedynie ścieżkę, może Twoje pliki przez zwykłe file_get_contents() otworzyć i system mu na to pozwoli.

Napisał Anonymous w środę, 5 września 2007 o 20:55

Na to wychodzi, że lepiej przechowywać konfigurację w postaci skryptu PHP. Nie każdy serwer posiada niepubliczny (wyższy) folder. Wart jednak rozważyć w projektach możliwość umieszczenia w nim opcji mimo przewagi unserialize(file_get_contents()) nad require(), o ile te funkcje zostały wykorzystane w testach.

Strona 1 z 1 :: 1

Skomentuj

NickInformacja
E-mailTylko do użytku wewnętrznego.
WWWNie zapomnij o http://
LayoutNapisz tu, czy widzisz dzienny czy nocny layout.
WpisFormatowanie wiki
Internauto, pamiętaj! Wolność to nie samowola - dbaj o kulturę wypowiedzi oraz dyskusji w sieci.

Na Zyxist.com panuje swoboda wyrażania opinii oraz krytyki pod dowolnym adresem. Jedyny warunek: musi być ona kulturalna i rzeczowa. Na chamstwo, prostactwo lub jawne obrażanie kogokolwiek nie ma tu miejsca i takie komentarze są bardzo szybko usuwane. Jeśli zamierzasz polemizować z treścią wpisu, wpierw uważnie ją przeczytaj.

© Tomasz "Zyx" Jędrzejewski 2005 - 2008 | Wykonanych zapytań: 2 | Serwer wirtualny zapewnia