Dostrajanie wydajności serwera Apache o dużym obciążeniu

12

Chcę zrozumieć niektóre problemy z wydajnością serwera, które widzę w przypadku (dla nas) mocno obciążonego serwera WWW. Środowisko jest następujące:

  • Debian Lenny (wszystkie stabilne pakiety + załatane do aktualizacji bezpieczeństwa)
  • Apache 2.2.9
  • PHP 5.2.6
  • Duża instancja Amazon EC2

Zachowanie, które widzimy, polega na tym, że sieć zazwyczaj reaguje szybko, ale z niewielkim opóźnieniem, aby rozpocząć obsługę żądania - czasami ułamek sekundy, a czasem 2-3 sekundy w szczytowym okresie użytkowania. Rzeczywiste obciążenie serwera jest zgłaszane jako bardzo wysokie - często 10.xx lub 20.xx, jak podaje top. Co więcej, uruchamianie innych rzeczy na serwerze w tych czasach (nawet vi) jest bardzo wolne, więc obciążenie zdecydowanie tam jest. Dziwne, że Apache pozostaje bardzo responsywny, poza początkowym opóźnieniem.

Apache skonfigurowaliśmy w następujący sposób, używając prefork:

StartServers          5
MinSpareServers       5
MaxSpareServers      10
MaxClients          150
MaxRequestsPerChild   0

I KeepAlive jako:

KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

Patrząc na stronę statusu serwera, nawet w czasach dużego obciążenia rzadko uderzamy w limit klienta, zwykle obsługując od 80 do 100 żądań i wiele z nich w stanie podtrzymania. To każe mi wykluczyć powolność początkowego żądania jako „czekanie na moduł obsługi”, ale mogę się mylić.

Monitorowanie CloudWatch w Amazon mówi mi, że nawet gdy nasz system operacyjny zgłasza obciążenie> 15, użycie procesora przez instancję wynosi od 75 do 80%.

Przykładowe dane wyjściowe z top:

top - 15:47:06 up 31 days,  1:38,  8 users,  load average: 11.46, 7.10, 6.56
Tasks: 221 total,  28 running, 193 sleeping,   0 stopped,   0 zombie
Cpu(s): 66.9%us, 22.1%sy,  0.0%ni,  2.6%id,  3.1%wa,  0.0%hi,  0.7%si,  4.5%st
Mem:   7871900k total,  7850624k used,    21276k free,    68728k buffers
Swap:        0k total,        0k used,        0k free,  3750664k cached

Większość procesów wygląda następująco:

24720 www-data  15   0  202m  26m 4412 S    9  0.3   0:02.97 apache2                                                                       
24530 www-data  15   0  212m  35m 4544 S    7  0.5   0:03.05 apache2                                                                       
24846 www-data  15   0  209m  33m 4420 S    7  0.4   0:01.03 apache2                                                                       
24083 www-data  15   0  211m  35m 4484 S    7  0.5   0:07.14 apache2                                                                       
24615 www-data  15   0  212m  35m 4404 S    7  0.5   0:02.89 apache2            

Przykładowe dane wyjściowe vmstatw tym samym czasie co powyżej:

procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa
 8  0      0 215084  68908 3774864    0    0   154   228    5    7 32 12 42  9
 6 21      0 198948  68936 3775740    0    0   676  2363 4022 1047 56 16  9 15
23  0      0 169460  68936 3776356    0    0   432  1372 3762  835 76 21  0  0
23  1      0 140412  68936 3776648    0    0   280     0 3157  827 70 25  0  0
20  1      0 115892  68936 3776792    0    0   188     8 2802  532 68 24  0  0
 6  1      0 133368  68936 3777780    0    0   752    71 3501  878 67 29  0  1
 0  1      0 146656  68944 3778064    0    0   308  2052 3312  850 38 17 19 24
 2  0      0 202104  68952 3778140    0    0    28    90 2617  700 44 13 33  5
 9  0      0 188960  68956 3778200    0    0     8     0 2226  475 59 17  6  2
 3  0      0 166364  68956 3778252    0    0     0    21 2288  386 65 19  1  0

I na koniec wynik z Apache server-status:

Server uptime: 31 days 2 hours 18 minutes 31 seconds
Total accesses: 60102946 - Total Traffic: 974.5 GB
CPU Usage: u209.62 s75.19 cu0 cs0 - .0106% CPU load
22.4 requests/sec - 380.3 kB/second - 17.0 kB/request
107 requests currently being processed, 6 idle workers

C.KKKW..KWWKKWKW.KKKCKK..KKK.KKKK.KK._WK.K.K.KKKKK.K.R.KK..C.C.K
K.C.K..WK_K..KKW_CK.WK..W.KKKWKCKCKW.W_KKKKK.KKWKKKW._KKK.CKK...
KK_KWKKKWKCKCWKK.KKKCK..........................................
................................................................

Z mojego ograniczonego doświadczenia wyciągam następujące wnioski / pytania:

  • Możliwe, że zezwalamy na zbyt wiele KeepAliveżądań

  • Widzę trochę czasu spędzonego na czekaniu na IO w vmstat, chociaż nie konsekwentnie i nie za dużo (myślę?), Więc nie jestem pewien, czy to jest duże zmartwienie, czy nie, mam mniejsze doświadczenie z vmstat

  • Również w vmstat widzę w niektórych iteracjach szereg procesów oczekujących na obsłużenie, do czego przypisuję początkowe opóźnienie ładowania strony na naszym serwerze WWW, być może błędnie

  • Podajemy mieszankę zawartości statycznej (75% lub wyższej) i treści skryptu, a treść skryptu jest często dość intensywna pod względem procesora, dlatego ważne jest znalezienie właściwej równowagi między nimi; długoterminowo chcemy przenieść statykę w inne miejsce, aby zoptymalizować oba serwery, ale nasze oprogramowanie nie jest na to gotowe

Z przyjemnością udzielam dodatkowych informacji, jeśli ktoś ma jakieś pomysły, druga uwaga jest taka, że ​​jest to instalacja produkcyjna o wysokiej dostępności, więc obawiam się poprawiać po poprawce i dlatego sam nie grałem z takimi KeepAlivewartościami, jak wartość jeszcze.

przyszłościowy
źródło
+1 Krwawe świetne pytanie, dobrze sformułowane i przemyślane. Mam nadzieję, że masz odpowiedź, na którą zasługuje!
Dave Rix

Odpowiedzi:

7

Zacznę od przyznania, że ​​nie mam wiele do czynienia z chmurami - ale na podstawie mojego doświadczenia w innych miejscach powiedziałbym, że ta konfiguracja serwera WWW odzwierciedla dość mały ruch. To, że kolejka jest tak duża, sugeruje, że po prostu nie ma wystarczającej ilości procesora, aby sobie z tym poradzić. Co jeszcze jest w kolejce?

Możliwe, że zezwalamy na zbyt wiele żądań KeepAlive

Nie - keeplive wciąż poprawia wydajność, nowoczesne przeglądarki są bardzo inteligentne, kiedy wiedzą, kiedy należy potokować, a kiedy uruchamiać żądania równolegle, chociaż limit czasu 5 sekund jest nadal dość wysoki, a czeka na Ciebie mnóstwo serwerów - chyba że „ MAMY OGROMNE problemy z opóźnieniami, zaleciłbym zmniejszenie tego do 2-3. To powinno skrócić nieco runqueueue.

Jeśli nie masz jeszcze zainstalowanego mod_deflate na serwerze - polecam to zrobić - i dodaj ob_gzhandler () do swoich skryptów PHP. Możesz to zrobić jako automatyczne dodawanie:

if(!ob_start("ob_gzhandler")) ob_start();

(tak, kopresja zużywa więcej procesora - ale powinieneś oszczędzać procesor ogólnie, szybciej usuwając serwery z kolejki / obsługując mniej pakietów TCP - a dodatkowo twoja strona jest szybsza).

Polecam ustawić górną granicę MaxRequestsPerChild - powiedzmy coś w rodzaju 500. To tylko pozwala na pewien obrót w procesach na wypadek, gdybyś miał przeciek pamięci. Twoje procesy httpd wyglądają na OGROMNE - upewnij się, że usunąłeś wszystkie moduły apache, których nie potrzebujesz i upewnij się, że podajesz statyczne treści z dobrymi informacjami o buforowaniu.

Jeśli nadal występują problemy, oznacza to, że problem prawdopodobnie dotyczy kodu PHP (jeśli przełączysz się na używanie fastCGI, powinno to być oczywiste bez większych strat wydajności).

aktualizacja

Jeśli zawartość statyczna nie różni się znacznie na stronach, warto również poeksperymentować z:

if (count($_COOKIE)) {
    header('Connection: close');
}

również w skryptach PHP.

symcbean
źródło
Spośród wielu dobrych odpowiedzi zaznaczam to jako zaakceptowane, ponieważ wyraźnie stwierdziłeś, że był to problem związany z procesorem (głównie ze względu na słabą aplikację, którą uruchamiamy) i na pewno tak było. Wdrożyłem wszystko na instancjach 2xlarge EC2 (w porównaniu z dużymi) i większość problemów zniknęła, chociaż wiele innych cech wydajności wciąż istnieje. Na tych serwerach działa tylko jedna aplikacja i jest to po prostu brzydkie.
przyszły
4

Należy rozważyć zainstalowanie asynchronicznego zwrotnego proxy, ponieważ liczba procesów w stanie W jest również dość wysoka. Wydaje się, że procesy Apache spędzają dużo czasu na wysyłaniu treści do powolnych klientów za pośrednictwem sieci, która jest zablokowana. Nginx lub lighttpd jako nakładka na serwer Apache mogą znacznie zredukować liczbę procesów w stanie W. I tak, powinieneś ograniczyć liczbę żądań podtrzymania. Prawdopodobnie warto spróbować wyłączyć Keepalive.

BTW, 107 procesów Apache są zbyt wysokie dla 22 rps, byłem w stanie obsłużyć 100-120 rps przy użyciu tylko 5 procesów Apache. Prawdopodobnie następnym krokiem jest profilowanie aplikacji.

Alex
źródło
Tak, zdecydowanie zgodziłem się, że aplikacja stanowi dużą część problemu. Został zlecony na zewnątrz i od tego czasu został poddany wielu łatkom, które jeszcze go nie pogorszyły, a proces przeprojektowywania jest w toku. Dziś wieczorem próbowałem wyłączyć KeepAlive bez żadnego efektu, a moim następnym krokiem jest wypróbowanie tego odwrotnego proxy, prawdopodobnie z nginx na podstawie wszystkiego, co przeczytałem.
przyszły
W dalszej kolejności zacząłem eksperymentować z odwrotnym proxy i prawdopodobnie zastosuję go w produkcji w najbliższej przyszłości. Dziękuję (i innym, którzy go zasugerowali) za ten pomysł. Nie było to coś, z czym wcześniej majstrowałem, ale myślę, że wywrze ono wpływ, dopóki nie będziemy w stanie wykonać pełnego przeprojektowania.
przyszły
1

Masz dwa wiersze w vmstat, które pokazują, że twój czas oczekiwania procesora jest dość wysoki, a wokół nich wykonujesz sporo zapisów (io - bo) i przełączanie kontekstu. Spojrzałbym na to, co pisze bloki i jak wyeliminować to czekanie. Myślę, że największą poprawę można znaleźć w poprawianiu IO dysku. Sprawdź syslog - ustaw, aby zapisywał asynchronicznie. Upewnij się, że pamięć podręczna zapisu kontrolera działa (sprawdź - może być zła bateria).

Keepalive nie powoduje problemów z perfem, oszczędza czas konfiguracji połączenia, jeśli nie korzystasz z pamięci podręcznej z przodu. Możesz nieco podnieść MaxSpareServers, aby w sytuacji kryzysowej nie czekać na wszystkie widelce.

fasolki
źródło
Nie jestem wystarczająco zaznajomiony z syslog, aby wiedzieć, jak ustawić go dla zapisów asynchronicznych pod Apache, chociaż na pewno będę go szukał i szukał. Wprowadziłem dziś kilka zmian związanych z KeepAlive i MaxSpareServers, ale nie przyniosło to żadnego efektu. Zgadzam się, że zostawię więcej części zamiennych, przegapiłem to. Jedną (słabą) jakością naszej aplikacji jest to, że mocno zapisuje ona pliki sesji użytkownika (tak, pliki) i właśnie tam zaczynam myśleć, że cierpimy. Mam opcję przeniesienia zarządzania sesjami do bazy danych, którą prawdopodobnie spróbuję w następnej kolejności.
przyszły
Tak, zgodziłbym się, że zapisy sesji są źródłem problemu. Możesz utracić zapisy dysku sesji, jeśli używasz sesji php - zainstaluj memcache i ustaw PHP session.save_handler na memcache, a session.save_path na tcp : //127.0.0.1: 11211 (lub gdziekolwiek skonfigurujesz memcache). Logowanie Apache'a jest domyślnie asynchroniczne, ale czasami aplikacje internetowe mogą korzystać z syslog, lub syslog może być czatujący i synchronizuje się z każdą linią. W końcu nie wygląda na to, że byłby to problem. Możesz poprzedzić wiersze wprowadzania pliku znakiem „-” w pliku syslog.conf, aby pominąć synchronizację.
fasola
0

powinieneś rozważyć wyłączenie Keepalive jako pierwszej próby ...

przy 107 przetworzonych żądaniach utrzymałbym MaxSpareServers wyżej niż ustawiłeś ...

IMHO w długoterminowej nginx jako odwrotny serwer proxy dla treści statycznych powinien być brany pod uwagę

evcz
źródło
0

Pierwsza sugestia: wyłącz Keepalives. Potrzebowałem go tylko wtedy, gdy mogłem zidentyfikować konkretną sytuację, w której wydajność wzrosła, ale ogólnie liczba żądań na sekundę spadła przy włączonej Keepalive.

Druga sugestia: Ustaw MaxRequestsPerChild. I echo symcbean tutaj, to pomoże w przejściu procesu w przypadku wycieku pamięci. 500 jest dobrym punktem wyjścia.

Trzecia sugestia: Zwiększ MaxClients. Obliczeniem typu ballpark jest to (pamięć fizyczna - pamięć używana przez proces inny niż httpd) / rozmiar każdego procesu httpd. W zależności od sposobu kompilacji httpd liczba ta wynosi maks. 255. Używam 250 dla moich publicznych serwerów, aby radzić sobie z Google / Yahoo / MS indeksującymi systemy.

Czwarta sugestia: Zwiększ MaxSpareServers: coś w rodzaju 4-5x MinSpareServers.

Jeśli te sugestie zawiodą, przyjrzałbym się równoważeniu obciążenia za pomocą odwrotnego proxy lub memcache dla DB.

Paul S.
źródło