Download: KnowHow_Apache_optymalizacja
Transkrypt
Download: KnowHow_Apache_optymalizacja
KNOW HOW Dostrajanie Apache Skuteczna optymalizacja serwerów WWW Szybki jak strzała Nie ma nic bardziej irytującego niż serwer Apache, który nie radzi sobie z odpowiadaniem na żądania klientów i działa zbyt wolno. Webmasterzy znajdują się pod ciągłą presją i nieustannie próbują zapewnić płynność działania serwisów WWW. Przyczyn powolnego działania jest wiele, ale wiele jest także sposobów na rozwiązanie problemu „wąskiego gardła”. CHRISTIAN KRUSE G dy użytkownicy zaczynają coraz częściej narzekać na długi czas pobierania dokumentów, webmaster musi coś z tym zrobić. Przyczyn opóźnień może być wiele: zbyt mała przepustowość sieci, przeciążenie serwera lub po prostu zbyt duża liczba zapytań generowana przez użytkowników. W artykule zaprezentowano kilka sposobów przyspieszenie działania serwisów WWW. Omówione zostały również sposoby testowania wprowadzonych zmian za pomocą prostych narzędzi do pomiaru wydajności. Problemy z siecią i routerem Na pewno lepszą strategią, niż doraźne reagowanie na pojawiające się problemy, jest systematyczna kontrola systemu i zapobieganie potencjalnym kłopotom. Najbardziej prawdopodobnym źródłem problemów jest mała przepustowość sieci i powstawanie „wąskiego gardła” w miejscach styku z siecią WAN (router) lub niestabilne parametry połączenia. Użytecznymi narzędziami diagnostycznymi w takiej sytuacji są tracepath oraz traceroute, które pozwalają łatwo ustalić przebieg pakietów, wielkość opóźnienia między kolejnymi skoka- Listing 1. Wyniki działania tracepath. 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 44 ckruse@shine:~ $ tracepath www.defunced.de 1?: [LOCALHOST] pmtu 1500 1: fogg.defunced.de (192.168.1.1) 2: 10.3.11.1 (10.3.11.1) 3: gwin-gw-gig00-112.HRZ.Uni-Dortmund.DE (129.217.129.190) 4: ar-essen2.g-win.dfn.de (188.1.44.33) 5: cr-essen1-ge4-0.g-win.dfn.de (188.1.86.1) 6: cr-frankfurt1-po8-1.g-win.dfn.de (188.1.18.89) 7: 188.1.80.42 (188.1.80.42) 8: gi-0-3-ffm2.noris.net (80.81.192.88) 9: ge0-2-151-nbg5.noris.net (62.128.0.209) 10: no.gi-5-1.RS8K1.RZ2.hetzner.de (213.133.96.25) 11: et-1-16.RS3K1.RZ2.hetzner.de (213.133.96.230) 12: srv001.occuris.de (213.133.103.124) Resume: pmtu 1500 hops 12 back 12 Luty 2004 www.linux-magazine.pl 2.625ms 5.109ms 13.403ms 222.119ms 12.839ms 24.964ms 24.872ms 26.466ms 40.772ms 31.012ms 32.433ms 38.802ms mi itp. Takie testy trzeba wykonywać redukując parametr TTL (Time to Live) i oczekując aż router zwróci błąd przekroczenia czasu oczekiwania (TIME_EXCEEDED). Pole TTL najczęściej określa ilość skoków (hops) dozwolonych przy przekazywaniu pakietu przez sieć. Pozwala to administratorom bliżej analizować problemy z połączeniem. Listing 1 pokazuje następujący przykład: router w 4 skoku, ar-essen2.g-win.dfn.de, odpowiada dość wolno. Tym niemniej czas 0,2 sekundy nie jest jeszcze krytyczną wartością, należy zatem założyć, że „wąskie gardło” występuje jednak gdzieś indziej. Następnym krokiem jest analiza obciążenia serwera. Najlepszym sposobem sprawdzenia Tabela 1. Najważniejsze moduły Apache. reached Nazwa modułu Nazwa modułu env_module alias_module config_log_module rewrite_module mime_module access_module includes_module auth_module autoindex_module setenvif_module dir_module headers_module cgi_module expires_module action_module php4_module gzip_module Dostrajanie Apache się jednak także tak, że wykresy obciążenia serwera stale przedstawiają niskie wartości, ale poziom ruchu w sieci jest zdecydowanie zbyt wysoki. Czy serwer jest przeciążony? KNOW HOW oprogramowania z odpowiednią flagą kompilatora. Wiele popularnych dystrybucji zawiera pakiet Apache, skompilowany do pracy na procesorach serii 386 w celu zachowania kompatybilności. Rekompilacji można dokonać ustawiając flagi kompilacji stosownie do posiadanej platformy sprzętowej. Jeśli twój serwer bazuje na procesorze Athlon (zobacz poniższą tabelę „Środowisko testowe”), możesz użyć poniższego zestawu flag: Fakt, że serwer jest CFLAGS='-march=athlon U mocno obciążony, -fexpensive-optimizations -O3' niekoniecznie musi Rysunek 1. Zmiana parametru Connection Timeout w pliku konfigurastanowić powód do cyjnym Apache może zwiększyć wydajność. Flagi te wskazują kompilatorowi, żeby generozmartwień. Duże wał kod maszynowy działający wyłącznie na i często używane dokumenty, mają tendencję procesorach typu Athlon. W naszym przykłatego jest monitorowanie serwera podczas stando generowania dużego obciążenia. W wielu dzie poziom optymalizacji jest ustawiony na 3, dardowej pracy, przez łączenie się do konsoli przypadkach administrator niewiele może co pozwala kompilatorowi użyć zoptymalizonp. przy pomocy SSH. Narzędzia takie jak top z tym zrobić. Pierwszą rzeczą, której można wanych metod (kosztem dłuższego czasu komi ps dostarczają ogólnych wskazówek, podobnie spróbować, jest ponowne przekompilowanie pilacji i kompatybilności). wartość uptime, która pozwoli ustalić poziom bieżącego obciążenia serwera. Narzędzie Apachetop, opisywane w Linux Magazine [3], bęŚrodowisko testowe dzie również bardzo przydatne w przeprowana Gentoo Linux 1.4 z jądrem 2.4.22, dzaniu analizy. Niestety, nie ma żadnej gwai Perl 5.8.0. Moje podstawowe narzęrancji, że tak zidentyfikowane „wąskie gardzie testujące wydajność, to skrypt nadło” jest elementem stałym; tak naprawdę pisany przeze mnie w Perlu, który można ściągnąć z [1]. Na rysunku może ono mieć charakter chwilowy i powstać 2 przedstawiono fragment jego dzianp. w wyniku przerw w pracy urządzeń sieciołania. Skrypt ściąga adres URL, podawych i awarii łącz. Rozwiązaniem tego prony jako argument przy jego wywołablemu jest użycie programu MRTG [4], słuniu, wraz ze wszystkimi odwołaniami żącego do rejestrowania działań serwera potrzebnymi do pomiarów. Skrypt w dłuższym przedziale czasu. Opis przykładomierzy czas potrzebny do wykonania wej instalacji MRTG znajduje się w [5]. tego (zobacz rysunek 3). Analizowanie wykresów MRTG zwykle Rysunek 2. Fragmenty skryptu testowego autora Drugie narzędzie to dostarczony ujawnia, że serwer jest przeładowany lub ponapisanego w Perlu, do ściągnięcia ze stron WWW z Apache program ab [2]. Służy on ziom ruchu jest zbyt wysoki. Wykresy średnieLinux Magazine. głównie do pomiarów obciążenia. Aby go obciążenia oraz obciążenia procesora, to określić jego poziom, narzędzie to syTesty wydajności są używane do określenia wskaźniki pozwalające łatwo wykryć zbyt duże muluje dużą liczbę jednoczesnych zapytań, efektywności dokonanej optymalizacji. Doobciążenie serwera. Wykaz liczby aktywnych następnie mierzy liczbę zapytań obsługiwabrym kryterium porównawczym jest mierzeprocesów pozwala zidentyfikować winowajcę. nych przez serwer w czasie jednej sekundy nie czasu między otrzymaniem przez serwer oraz czas potrzebny Apache na ich obsługę. Jeśli liczba procesów pozostaje stała, powinnizapytania, a dostarczeniem odpowiedzi na śmy poszukać procesu, który wymknął się spod nie. Aby to sprawdzić, uruchomiłem kontroli i działa wadliwie, zajmując pamięć 2 komputery PC i podłączyłem je do i czas procesora. sieci wewnętrznej 100 MB. Mój serwer (AMD Athlon 600 z 64 MB pamięci Jednak jeśli liczba procesów się zmienia, SD-RAM) pracował na FreeBSD 4.6 należy sprawdzić skrypty CGI, które również i Apache 1.3.27. mogą blokować zasoby. W tym celu przyda Charakterystyki serwera WWW opisasię plik Access.log z Apache oraz lista procene w tym artykule odnoszą się również sów (uzyskana programem top) zużywających do Apache 2, o ile nie zaznaczono najwięcej zasobów, obejmujące przedział czainaczej. Do symulowania prędkości su, w którym serwer był w znacznym stopniu ISDN zainstalowałem również moduł obciążony. Dzięki nim można się dowiedzieć, Mod_bandwidth, aby różnice w wydajktóre adresy URL były najczęściej wywołyRysunek 3. Skrypt testowy autora w akcji. Ściąga ności były bardziej widoczne. wane. Ta informacja pozwala administratowybrany adres URL i mierzy czas potrzebny na tą Maszyny klienckie (AMD Duron 800 rom zlokalizować skrypt lub program odpooperację. z 312 MB pamięci SD-RAM) działały wiedzialny za przeciążanie serwera. Zdarza www.linux-magazine.pl Luty 2004 45 KNOW HOW Dostrajanie Apache Wiele modułów Apache podczas obsługi zapytań tworzy pliki tymczasowe; PHP tworzy jednorazowe pliki, ułatwiające zarządzanie sesją. Dlatego następny krok optymalizacji, to przeniesienie katalogu /tmp z dysku twardego do pamięci (RAM-dysk), standardowo o rozmiarze około 128 MB. Mimo, że Linux używa bardzo efektywnej strategii buforowania danych, RAM-dysk znacznie przyspiesza czas reakcji serwera. Dostrajanie HTTPD Sam serwer Apache posiada duże możliwości optymalizacji. Chociaż podstawowa domyślna konfiguracja zazwyczaj wystarcza, niektóre dystrybucje próbują ładować zbyt wiele zbędnych modułów. Do normalnej pracy po- Standardowe CGI: Mordercy wydajności Skrypty CGI, działające na serwerze WWW, należy dokładnie przeanalizować. Te niewątpliwie użyteczne pogramy często wywołują problemy z wydajnością, ponieważ uruchomienie ich wymaga przetworzenia plików binarnych. Usunąłem rzeczywiste nazwy hostów, ale poniższy przykład jest z życia wzięty: Serwer WWW, działający w środowisku produkcyjnym, miał bardzo duży i skomplikowany skrypt CGI napisany w Perlu. Gdy serwer zaczął mieć problemy z dużym obciążeniem, odpowiedzialny za jego działanie zespół zmodyfikował zasady działania skryptu tak, aby sprawdzał średnie obciążenie i usuwał procesy CGI w przypadku wykrycia przeciążenia. Skutki były odwrotne do zamierzonych: obciążenie wciąż było bardzo duże, a uruchamianie interpretera i przetwarzanie skryptów zajmowało bardzo dużo zasobów systemu. Następnym krokiem było napisanie 804–bajtowego programu w C, który podejmował decyzje w zależności od wydajności. Gdy obciążenie było zbyt duże, generował informację o błędzie, jeśli nie – uruchamiał oryginalny skrypt CGI. Rozwiązanie to okazało się bardzo efektywne, system radził sobie z dużym obciążeniem znacznie lepiej niż w poprzednim przypadku. Programiści mogą iść jeszcze krok dalej i napisać moduł mod_loadavg do serwera Apache i ograniczyć w jeszcze większym stopniu obciążenie serwera. Moduły tego typu pozwalają zrezygnować z wywoływania interpreterów języków programowania. Moduły Apache są dostępne dla wszystkich najważniejszych języków programowania, np.: mod_perl, mod_php, mod_ruby, mod_fastcgi. 46 Luty 2004 trzebne są wyłącznie moduły wymienione w Tabeli 1. Usunięcie zbędnych modułów zmniejszy rozmiar pamięci zajmowany przez proces HTTPD, skróci również czas obsługi zapytań. Dzieje się tak, ponieważ dla każdego obsługiwanego zapytania Apache musi sprawdzić każdy aktywny moduł pod kątem przydatności do jego obsługi. Przyjrzyjmy się teraz jawnym parametrom zapisanym w pliku konfiguracyjnym serwera. Doświadczenie pokazuje, że np. zmniejszenie wartości connection timeout w parametrze Timeout pliku konfiguracyjnego może wiele zmienić. Czy naprawdę trzeba czekać aż 300 sekund, żeby serwer zamknął połączenie, nie doczekawszy się nowego pakiet lub zapytania? Takie powolne zapytania blokują procesy podrzędne i uniemożliwiają przyjmowanie nowych połączeń, które Apache mógłby obsłużyć w międzyczasie. Czas oczekiwania wynoszący 120–150 sekund powinien wystarczyć, nawet w przypadku klientów korzystających z wolniejszych połączeń internetowych (zobacz Rysunek 1). Administratorzy powinni również sprawdzić, czy opcja Keep Alive jest ustawiona na On. Ten parametr włącza obsługę zapytań przy pomocy Keep Alive. Pozwala ona klientom używać jednego połączenia do obsługi wielu zapytań. W innym przypadku klient musi korzystać z nowego połączenia dla każdego nowego zapytania, a to wiąże się za każdym razem z przejściem przez procedurę nawiązywania połączenia i niepotrzebnym wykorzystaniem trzech dodatkowych pakietów. Przy obciążeniu na poziomie 50 zapytań na sekundę, oznacza to 9000 pakietów na minutę, potrzebnych tylko i wyłącznie na nawiązanie połączeń. W ten sposób, przyjmując, że 3 klientów generuje 50 zapytań, włączenie opcji Keep Alive zredukuje liczbę połączeń na sekundę do 3, a liczbę pakietów potrzebnych do nawiązania tych połączeń do 540. Redukowanie opóźnień Parametr KeepAliveTimeout powinien mieć możliwie niską wartość – zwykle wystarcza 15 sekund. Parametr MaxSpareServers ogranicza liczbę bezczynnych procesów httpd. Powoduje to zmniejszenie liczby procesów httpd w okresach mniejszego obciążenia serwera. Oznacza to również, że Apache będzie musiał podzielić kilka nowych procesów httpd w celu obsłużenia zwiększającego się obciążenia. W przypadku serwisów narażonych na czasowe skrajne obciążenia, administratorzy powinni jednak zablokować (wykomentować) ten parametr, monitorując jednocześnie wyniki i sprawdzając, czy efektywność serwera wzrasta. Parametr MaxSpareServers powinien być ustawiony w okresach mniejszego obciążenia, dzięki czemu będziesz miał kontrolę nad ilością procesów httpd. Zupełnie inną funkcję pełni parametr MinSpareServers. Określa on liczbę bezczynnych procesów, które powinien podtrzymywać w pamięci serwer. Procesy te stanowią rodzaj bufora w razie pojawienia się drastycznych skoków obciążenia. Pamiętaj, że sposób reakcji serwera na poziom obciążenia zależny jest od wyboru odpowiednich modułów. Serwer będzie się zachowywał inaczej w przypadku użycia modułu MPM – Multiprocessing Module [6, 7] dostępnego dla Apache 2. Wówczas możesz skorzystać z parametrów w MaxSpareThreads i MinSpareThreads. W tym przypadku te wartości Listing 2. Rezultaty przed tuningiem. 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 Concurrency Level: Time taken for tests: Complete requests: Failed requests: Write errors: Total transferred: HTML transferred: Requests per second: Time per request: Time per request: Transfer rate: 10 2.842457 seconds 100 0 0 11023620 bytes 10994986 bytes 35.18 [#/sec] (mean) 284.246 [ms] (mean) 28.425 [ms] (mean, across all concurrent requests) 3787.22 [Kbytes/sec] received Connection Times (ms) min mean[+/-sd] Connect: 0 0 1.0 Processing: 39 278 342.6 Waiting: -83 -22 19.1 Total: 39 278 342.8 www.linux-magazine.pl median max 0 5 105 1012 -21 1 106 1012 Dostrajanie Apache jąc w każdej fazie jednocześnie po 10 zapytań. Listing 2 pokazuje fragmenty wyników zawierające najważniejsze wartości. Warto spojrzeć na ciekawe wykresy Requests per second (zapytania na sekundę) i Time per request (czas potrzebny na obsłużenie zapytania). Uzyskane tu średnie wartości są interesujące – jest to około 35 zapytań na sekundę i 28 milisekund na obsługę każdego zapytania. Po wykonaniu tego testu należy zmienić konfigurację serwera (optymalizując go) i ponownie wykonać test wydajności. Listing 3 pokazuje przykładowe wyniki po wykonaniu optymalizacji. Wygląda na to, że w tym wypadku proces optymalizacji powiódł się całkowicie. Można ostrożnie założyć, że teraz serwer będzie mógł obsłużyć dwukrotnie większą liczbę zapytań. Listing 3. Wydajność po tuningu. 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 Concurrency Level: Time taken for tests: Complete requests: Failed requests: Write errors: Total transferred: HTML transferred: Requests per second: Time per request: Time per request: Transfer rate: 10 1.58400 seconds 100 0 0 11290258 bytes 11261068 bytes 94.48 [#/sec] (mean) 105.840 [ms] (mean) 10.584 [ms] (mean, across all concurrent requests) 10416.67 [Kbytes/sec] received Connection Times (ms) min mean [+/-sd] median max Connect: 0 0 0.3 0 3 Processing: 34 98 21.1 95 155 Waiting: -102 -46 17.9 -42 0 Total: 34 98 21.0 95 155 odnoszą się do liczby wątków w procesie Apache. Ogólnie rzecz biorąc, jest to lepsze rozwiązanie, ponieważ Apache 2 powinien mieć mniejsze problemy z tworzeniem nowych wątków niż nowych procesów. Wątek nie musi posiadać własnego obszaru pamięci, do którego proces musiałby być skopiowany. Ponadto wątek nie posiada własnego identyfikatora (process ID), ale wraz z pozostałymi wątkami współdzieli ID głównego procesu. W poszukiwaniu kompromisu Kolejnym istotnym parametrem jest MaxRequestsPerChild, który usuwa procesy potomne po przetworzeniu pewnej liczby zapytań i tworzy nowe procesy potomne. Jest to przydatna funkcja, ponieważ niektóre biblioteki i moduły są podatne na „wycieki pamięci” (memory leaks) i należy je co pewien czas przeładować, żeby oczyścić pamięć. Należy jednak wykonać dokładne testy przed włączeniem tego parametru, w celu sprawdzenia, czy stosowanie go jest na pewno potrzebne. Jeśli okaże się, że liczba procesów Apache rośnie gwałtownie podczas okresów wyższego obciążenia (do sprawdzenia tego możesz użyć narzędzia top), w zasadzie nie ma innego wyjścia, jak użycie tego parametru. W tym przypadku należy ustawić wysoką wartość, jest ona zależna od konfiguracji systemu i musi być dobrana metodą prób i błędów. Jest to zawsze kompromis między wydajnością, a stopniem wykorzystania zasobów pamięci. Drugim „kompromisowym” parametrem jest HostnameLookups. Jeśli priorytetem jest szybkość pracy, należy go ustawić na Off. Uaktywnienie tej opcji wymusza dla każdego zapy- KNOW HOW Optymalizacja na poziomie HTTP tania odwrócone (reverse) wyszukiwanie DNS. Powoduje to z kolei wysłanie przynajmniej jednego zapytania do serwera DNS i prowadzi zazwyczaj do generowania kolejnych zapytań DNS do serwerów nazw po stronie zdalnego klienta. Powoduje to nie tylko zwiększony ruch w sieci, ale także zabiera dużo czasu. Na ile skuteczna jest optymalizacja Apache? Dość trudno jest ocenić efekt wykonanej optymalizacji. Skrypt [1] nie nadaje się do przetestowania wprowadzonych zmian, ponieważ nie generuje żadnego obciążenia na serwerze. Test Apache ab (wersja 2, [2]) powinien jednak dostarczyć oczekiwanych informacji (zobacz ramka „Środowisko testowe”). Uruchom go przed rozpoczęciem optymalizowania: ckruse@shine:~ $ ab2 -n 100 U -c 10 http://rain/article/ Program uruchamia 100 faz zapytań, wykonu- Optymalizacja na poziomie protokołu HTTP jest związana głównie z obniżaniem poziomu ruchu i zmniejszaniem liczby zapytań, przy czym pomocne będą nagłówki warunkowe (conditional header) i nagłówki buforu (caching header). Nagłówki buforu mówią klientowi (np. przeglądarce WWW), że nie ma potrzeby ponownego pobierania przez określony czas pewnej części danych. Jest to bardzo użyteczne w przypadku statycznego kodu HTML lub arkuszy stylów CSS. Nagłówek Expires wskazuje, kiedy dokument powinien zostać ponownie pobrany (zobacz Listing 4). Jeśli chcesz przekazać do UA (User Agent – może to być przeglądarka, proxy lub inny klient), że dokument stał się nieaktualny natychmiast po wygenerowaniu przez Apache i trzeba go pobierać za każdym razem, należy w polu nagłówka wstawić wartość Date. Wartości takie jak now lub 0 są niewłaściwe, ale są akceptowane w celu zwiększenia poziomu tolerancji błędów i przyrównywane do poprzedniej wartości. Od klienta zależy, czy uwzględni tę informację. Listing 4. Ustawianie nagłówków Expires i Cache-Control. 1 ExpiresActive On 02 ExpiresByType text/html „access plus 1 month” 03 ExpiresByType text/css „access plus 6 month” 04 ExpiresByType text/javascript „access plus 6 month” 05 ExpiresByType image/gif „access plus 6 month” 06 ExpiresByType image/jpeg „access plus 6 month” 07 ExpiresByType image/png „access plus 6 month” 08 09 <Files ~ "\.(js|css|gif|jpe?g|png)$"> 10 Header append Cache-Control "public" 11 </Files> www.linux-magazine.pl Luty 2004 47 KNOW HOW Dostrajanie Apache Listing 5. Przykład zapytania HTTP. 01 02 03 04 05 06 07 08 09 10 11 12 13 14 ckruse@shine:~ $ telnet rain 80 Trying 192.168.1.3... Connected to rain.defunced.de. Escape character is '^]' GET /article/ HTTP/1.1 Host: rain Connection: close HTTP/1.1 200 OK Date: Sun, 09 Nov 2003 19:52:04 GMT Server: Apache/1.3.27 (Unix) PHP/4.2.3 AuthMySQL/2.20 Cache-Control: max-age=2592000 Expires: Tue, 09 Dec 2003 19:52:04 GMT Last-Modified: Tue, 04 Nov 2003 23:50:42 GMT ETag: "a3a068-1a9d9-3fa83b52" Accept-Ranges: bytes Content-Length: 109017 Connection: close Content-Type: text/html 15 16 17 18 19 20 21 <I>HTML contents<I> Nagłówek Cache-Control jest bardziej precyzyjny. Określa ściśle polecenia i parametry buforowania, które każdy klient HTTP zgodny z RFC, musi obsługiwać. Składnia dla Cache-Control jest nieco inna niż dla Expires. Okres ważności dokumentu jest określany przez parametr max-age=wartość. Wartość jest okresem ważności w sekundach, liczonym od czasu określonego w polu Date. Ustawiając tę wartość na 0 określamy, że dokument nie powinien być w ogóle buforowany, jednak takie rozwiązanie nie jest zalecane. Nagłówki Atrybuty publiczne w nagłówku Cache-Control mogą w pewnych okolicznościach zwiększyć szybkość, ponieważ zezwalają serwerowi proxy na większą swobodę w interpretacji. Jeśli tak poinstruowany serwer proxy odbierze zapytanie, które nie powinno być buforowane, np. zapytanie autoryzacyjne używające HTTP-Auth, może je zignorować i mimo wszystko zapamiętywać. Obydwa nagłówki wymagają do pracy modułów mod_expires i mod_headers. Administratorzy mogą użyć mod_expires do określenia daty wygaśnięcia ważności dokumentu. Jednakże moduł ten nie obsługuje atrybutu publicznego, więc oznacza to, że będzie potrzebny również mod_headers, aby zezwolić plikom graficznym, 48 Luty 2004 skryptom Javascript oraz plikom CSS na jego użycie. Listing 4 pokazuje przykład zapytania HTTP do skonfigurowanego w ten sposób serwera. Zapytanie pokazane na Listingu 5 powinno zostać zapamiętane przez UA (proxy lub przeglądarkę) na okres miesiąca, bez konieczności kontaktowania się w międzyczasie UA z serwerem. Doświadczenie pokazuje jednak, że UA buforują wyniki tylko na krótki czas, najczęściej około dwóch dni, a następnie używają nagłówków warunkowych do sprawdzenia, czy zapamiętana wersja jest aktualna lub czy wymaga uaktualnienia. Do tego celu służy grupa nagłówków rozpoczynających się od If. Dopuszczalne są nagłówki takie jak If-Match, If-Modified-Since, If-None-Match, If-Range oraz If-Unmodified-Since. Jednak w praktyce nie są one używane, za wyjątkiem If-None-Match (Opera 7 i nowsza oraz Mozilla) i If-Modified-Since (Mozilla, Opera 7, MS Internet Explorer 5.5 oraz nowsze). Pozostałe nagłówki zostały opisane w [8]. Mierzenie wydajności Nagłówki warunkowe Techniki kompresji Wszystkie nagłówki warunkowe odwołują się do pól, które serwer generuje podczas pierwszego zapytania. If-Modified-Since odwołuje się do pola Last-Modified, które zawiera datę ostatniej modyfikacji dokumentu. Nagłówek If-None-Match odwołuje się do ETag, sumy kontrolnej dokumentu. UA zachowuje te wartości i odpowiednio formułuje zapytania (zobacz Listing 6). Jak widać, serwer zwraca odpowiedź 304 Not Modified ('niezmodyfikowany') i kilka innych nagłówków, ale nie odsyła żadnej zawartości. Kilka słów należy poświęcić skryptom CGI. Skrypt CGI powinien wysyłać nagłówek Last-Modified lub ETag, umożliwiający przeglądarce używanie algorytmów warunkowego polecenia GET. Ponadto skrypt musi także przetwarzać nagłówek, ponieważ jest to wymagane do odpowiedniego formatowania daty (zwykle podawanego jako liczba sekund od 1970 roku). Dopiero wtedy można sprawdzić, na podstawie informacji o wersji w nagłówku If-Modified-Since, czy dokument jest aktualny. Podobnie jest w przypadku nagłówka If-None-Match: skrypt oblicza sumę kontrolną i w ten sposób sprawdza, czy wersja dokumentu opisana w nagłówku jest aktualna. Jako algorytmu obliczającego sumę kontrolną można użyć algorytmu haszującego, takiego jak na przykład MD5. Zmienne środowiskowe CGI, HTTP_IF_MODIFIED_SINCE i HTTP_IF_NONE_MATCH umożliwiają dostęp do wartości w obu nagłówkach. Kodowanie zawartości jest inną metodą optymalizowania HTTP. Wymaga ona wysłania przez agenta użytkownika przy zapytaniu o dokument nagłówka Accept-Encoding. Nagłówek określa sposób przetwarzania odpowiedni dla zawartości i może zawierać takie wartości jak: gzip [9] lub compress. Obie wartości okre- www.linux-magazine.pl Do zbadania efektywności optymalizacji można użyć skryptu [1] (patrz ramka 'Środowisko testowe'): ckruse@shine:~ $./measure.pl U --base-url http://rain/article/ Getting http://rain/article/... [...] Time elapsed: 4.642203 seconds Włączenie obsługi nagłówków warunkowych sprawiło, że całe zapytanie jest przetwarzane w czasie poniżej sekundy. ckruse@shine:~ $./measure.pl U --send-if-modified-since U --send-if-none-match --base-url U http://rain/article/ Getting http://rain/article/... [...] Time elapsed: 0.181876 seconds Listing 6. Warunkowe polecenie GET. 1 ckruse@shine:~ $ telnet rain 80 02 Trying 192.168.1.3... 03 Connected to rain.defunced.de. 04 Escape character is '^]'. 05 GET /article/ HTTP/1.1 06 Host: rain 07 Connection: close 08 If-Modified-Since: Tue, 04 Nov 2003 23:50:42 GMT 09 If-None-Match: "a3a068-1a9d93fa83b52" 10 11 HTTP/1.1 304 Not Modified 12 Date: Sun, 09 Nov 2003 20:28:43 GMT 13 Server: Apache/1.3.27 (Unix) PHP/4.2.3 AuthMySQL/2.20 14 Connection: close 15 ETag: "a3a068-1a9d9-3fa83b52" 16 Expires: Tue, 09 Dec 2003 20:28:43 GMT 17 Cache-Control: max-age=2592000 18 19 Connection closed by foreign host. Dostrajanie Apache Optymalizacja na poziomie kodu HTML Pliki HTML posiadają największy potencjał optymalizacyjny. Znaczna część kodu HTML, zwłaszcza przygotowywana dla serwisów firmowych i komercyjnych, jest dostarczana przez projektantów używających edytorów WYSIWYG, takich jak np. Dreamweaver. Edytory te generują jednak dużo nadmiarowego kodu, który bardzo często można skrócić aż o 50 %, bez uszczerbku dla kodu. Generalnie zaleca się usuwanie możliwie wielu sekwencji formatujących z pliku HTML i umieszczanie ich w plikach arkuszy stylów CSS. Z tym zadaniem radzą sobie doskonale nowe edytory WYSIWYG, niestety w przeciwieństwie do ich użytkowników... W odróżnieniu od sekwencji formatujących umieszczonych bezpośrednio w plikach HTML, pliki CSS są ładowane tylko raz, co oznacza, że serwer HTTP tylko raz wysyła sekwencje formatujące. Należy również unikać nadmiernego zagnieżdżania tabeli, jak to się często dzieje w przypadku programu Dreamweaver. Projektanci stron nie powinni traktować kodu wygenerowanego przez tego rodzaju programy jako produktu ostatecznego, lecz jedynie jako prototypu. Taki kod należy upo- rządkować i oczyścić ze zbędnych sekwencji, używając w tym celu przykładowo narzędzia HTML-Tidy [10]. Obrazy i grafika Projektanci stron mogą znacząco ograniczyć ruch w sieci, zwracając więcej uwagi na obróbkę obrazów i grafiki. Najpopularniejsze formaty obsługiwane przez większość przeglądarek to GIF, JPEG i PNG. Proste rysunki i animacje, to przeważnie pliki GIF, natomiast format JPEG jest używany do zdjęć i obrazów wysokiej jakości – mimo iż algorytm JPEG obniża jakość obrazu. Format GIF nie jest przydatny do tego celu, ponieważ może obsługiwać jedynie 256 kolorów. Jeśli najważniejsza jest jakość, to najlepszym wyborem będzie skompresowany format PNG, chociaż rozmiar pliku może być trochę większy niż porównywalnego pliku JPEG. Często spotyka się duże pliki graficzne w wysokiej rozdzielczości, skalowane na stronie WWW przy użyciu parametrów width i height. Takie rozwiązanie ma dwie wady: po pierwsze, oznacza to konieczność niepotrzebnego przesłania dużego pliku. Po drugie, jakość obrazu jest niższa, ponieważ dowolny program do obróbki grafiki pozwala uzyskać dużo lepsze efekty wygładzania i korekcji przy zmniejszaniu pliku niż wewnętrzne mechanizmy przeglądarki. Kiedyś projektanci stron byli ograniczeni powolnymi modemami 14,400 Kb/s i wysoką ceną miejsca na serwerach. Obecnie nie stanowi to już problemu, jednak użytkownicy przyzwyczaili się do zmniejszania obrazków i pozwalają przeglądarce powiększać je z powrotem. Niestety UA niezbyt dobrze radzą sobie z takim zadaniem. Najlepszym rozwiązaniem wydaje się być dobranie takiej skali dla obrazów, aby były wyświetlane w oryginalnym rozmiarze – jest to doskonały kompromis między rozmiarem i jakością pliku. Spacje i znaczniki nowej linii HTML jest językiem nie narzucającym wymagań dotyczących formatowania, co pozwala usunąć zbędne spacje i znaki nowej linii. Dla UA jest obojętne, czy kod HTML jest ładnie sformatowany, czy też jest to ciąg znaków w jednym wierszu. Umożliwia to dalsze ograniczenie ruchu w sieci, podobnie jak w przypadku konwersji znaków końca linii w Windows na znaki końca linii w Uniksie, które zajmują jeden bajt zamiast dwóch. Każdy nowoczesny edytor HTML powinien posiadać tę opcję. Użytkownicy Apache 2 mogą użyć w tym celu modułu mod_blanks. Użytkownicy pozosta- łych wersji Apache mogą uzyskać podobny efekt, używając dwóch odrębnych wersji dokumentu – jednej do projektowania, drugiej do publikacji. Po każdej zmianie w pliku do projektowania należy uruchomić prosty skrypt (zobacz [11]). Usuwa on z wersji ostatecznej zbędne spacje i znaki końca linii. Zastosowanie wszystkich omówionych metod optymalizacji powinno przynieść oczekiwany efekt – lepszą wydajność serwisu. Będzie to szczególnie dobrze widoczne w przypadku średnio i bardzo obciążonych serwerów. Aby dokładnie określić wpływ wprowadzonych zmian na działanie systemu, należy zawsze przeprowadzać testy wydajności przed i po wykonaniu optymalizacji, używając w tym celu technik omówionych powyżej. ■ INFO [1] Skrypt autora artykułu do pomiaru wydajności: http://www.linux-magazin.de/ Service/Listings/2004/01/Apache-Tuning [2] Apache benchmarking tool: http:// httpd.apache.org/docs/programs/ab.html [3] Charly Kühnast, „The Sysadmin's Daily Grind: Apache Tracking”: Linux Magazine, numer 38, strona 54 [4] Multi Router Traffic Grapher: http://people.ee.ethz.ch/~oetiker/ webtools/mrtg [5] Przykładowa instalacja MRTG: http://www.defunced.de/mrtg [6] Multiprocessing Module: http:// httpd.apache.org/docs-2.0/mpm.html [7] T Grahammer, „Apache 2.0 – Rules of Succession”: Linux Magazine, numer 24, padźiernik 2002, strona 29 [8] HTTP RFC: ftp://ftp.rfc-editor.org/ in-notes/rfc2616.txt [9] U. Keil, „Dynamic Webpage Compression with Mod_gzip and Apache”: Linux Magazine, numer 24, październik 2002, strona 26 [10] HTML-Tidy: http://sourceforge.net/projects/tidy [11] Skrypt do usuwania spacji z plików HTML: http://www.defunced.de/blanks.pl.gz AUTOR ślają algorytmy kompresowania zawartości dokumentu, zanim zostanie ona wygenerowana przez serwer oraz sposób rozpakowania jej po stronie klienta. Metoda ta znacznie zmniejsza poziom ruchu w sieci – nawet o 90 %. Ma jednak kilka zasadniczych wad: po pierwsze, nie wszyscy agenci potrafią ją obsłużyć – np. Netscape 4 wysyła nagłówek Accept-Encoding z wartością gzip, jednak przeglądarka nie obsługuje tej metody poprawnie. Po drugie, proces kompresji zmniejsza wydajność serwera, ponieważ każdy dokument musi zostać odpowiednio spakowany. Po trzecie, technika ta może zostać nieprawidłowo zinterpretowana podczas przekazywania danych przez Internet – wiele aplikacji filtrujących zawartość (content filters) usuwa po prostu nagłówek Accept-Encoding, nie sprawdzając go. Ponadto większość serwerów proxy nie reaguje prawidłowo na nagłówek Vary, wymagany dla potrzeb kompresji. Lista nagłówków generowana przez Vary zależy od wariantu zapytania. Starsze wersje linuksowego proxy, Squid HTTP, wyłączają wszelkiego rodzaju nagłówki zawierające parametry ustalające sposoby zapamiętywania. Dlatego zalecamy dokładnie przemyśleć wszystkie zalety i wady wynikające ze stosowania modułu mod_gzip. Szczególnie istotne jest to, kto będzie z serwera korzystać. KNOW HOW Christian Kruse studiuje informatykę na uniwersytecie w Dortmundzie. Pracuje dorywczo jako administrator i jest odpowiedzialny za wiele serwerów pracujących pod kontrolą Linuksa i FreeBDS. www.linux-magazine.pl Luty 2004 49