Prowadzę witrynę o stosunkowo niskim natężeniu ruchu, która raz w tygodniu doświadcza dużego wzrostu liczby odwiedzających po aktualizacji witryny. Podczas tego wzrostu wydajność witryny jest bardzo słaba w porównaniu z resztą tygodnia. Rzeczywiste obciążenie serwerów pozostaje bardzo niskie, niezawodnie poniżej 10% CPU i poniżej 30% RAM (sprzęt powinien być całkowicie przesadny w stosunku do tego, co faktycznie robimy), ale z jakiegoś powodu Apache wydaje się nie być w stanie poradzić sobie z ilością wniosków. Uruchamiamy apache 2.2.3 na RHEL 5.7, jądro 2.6.18-274.7.1.el5, x86_64.
Próbując odtworzyć to zachowanie poza godzinami pracy z ab, zauważam znaczny spadek wydajności po przekroczeniu około 256 użytkowników. Uruchomienie testu z najmniejszym możliwym przypadkiem użycia, jaki mogłem wymyślić (pobierany statyczny plik tekstowy, łącznie 223 bajty), wydajność jest normalna z 245 jednoczesnymi żądaniami:
Connection Times (ms)
min mean[+/-sd] median max
Connect: 15 25 5.8 24 37
Processing: 15 65 22.9 76 96
Waiting: 15 64 23.0 76 96
Total: 30 90 27.4 100 125
Percentage of the requests served within a certain time (ms)
50% 100
66% 108
75% 111
80% 113
90% 118
95% 120
98% 122
99% 123
100% 125 (longest request)
Ale gdy tylko podniosę liczbę do 265 równoczesnych żądań, ich część zaczyna zajmować absurdalnie dużo czasu:
Connection Times (ms)
min mean[+/-sd] median max
Connect: 13 195 692.6 26 3028
Processing: 15 65 21.3 72 100
Waiting: 15 65 21.3 71 99
Total: 32 260 681.7 101 3058
Percentage of the requests served within a certain time (ms)
50% 101
66% 108
75% 112
80% 116
90% 121
95% 3028
98% 3040
99% 3044
100% 3058 (longest request)
Wyniki te są bardzo spójne dla wielu przebiegów. Ponieważ do tego pola dociera inny ruch, nie jestem pewien, gdzie dokładnie byłaby twarda granica, jeśli taka istnieje, ale wydaje się, że jest podejrzanie zbliżona do 256.
Oczywiście założyłem, że jest to spowodowane limitem wątków w preforkach, więc posunąłem się do przodu i dostosowałem konfigurację, aby podwoić liczbę dostępnych wątków i zapobiec niepotrzebnemu powiększaniu się i zmniejszaniu puli wątków:
<IfModule prefork.c>
StartServers 512
MinSpareServers 512
MaxSpareServers 512
ServerLimit 512
MaxClients 512
MaxRequestsPerChild 5000
</IfModule>
mod_status potwierdza, że działam teraz z 512 dostępnymi wątkami
8 requests currently being processed, 504 idle workers
Jednak próba 265 jednoczesnych żądań nadal daje prawie identyczne wyniki jak wcześniej
Connection Times (ms)
min mean[+/-sd] median max
Connect: 25 211 714.7 31 3034
Processing: 17 94 28.6 103 138
Waiting: 17 93 28.5 103 138
Total: 57 306 700.8 138 3071
Percentage of the requests served within a certain time (ms)
50% 138
66% 145
75% 150
80% 161
90% 167
95% 3066
98% 3068
99% 3068
100% 3071 (longest request)
Po przeszukaniu dokumentacji (i wymianie stosów) brakuje mi dalszych ustawień konfiguracji, aby spróbować rozwiązać ten problem. Czy coś mi brakuje? Czy powinienem zacząć szukać odpowiedzi poza apache? Czy ktoś jeszcze widział takie zachowanie? Każda pomoc byłaby bardzo mile widziana.
EDYTOWAĆ:
Zgodnie z radą Ladadadady uciekałem przed apaczami. Próbowałem kilka razy z -tt i -T i nie mogłem znaleźć niczego niezwykłego. Następnie spróbowałem uruchomić strace -c na wszystkich aktualnie uruchomionych procesach Apache i otrzymałem:
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
22.09 0.317836 5 62128 4833 open
19.91 0.286388 4 65374 1896 lstat
13.06 0.187854 0 407433 pread
10.70 0.153862 6 27076 semop
7.88 0.113343 3 38598 poll
6.86 0.098694 1 100954 14380 read
(... porwany)
Jeśli czytam to dobrze (i nie przejmuj się, ponieważ nie używam zbyt często strace), żadne z wywołań systemowych nie może uwzględniać czasu, jaki zajmują te żądania. Wygląda na to, że wąskie gardło występuje, zanim żądania dotrą nawet do wątków roboczych.
EDYCJA 2:
Jak sugerowało kilka osób, ponownie uruchomiłem test na samym serwerze internetowym (wcześniej test był przeprowadzany z neutralnej lokalizacji internetowej). Wyniki były zaskakujące:
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 11 6.6 12 21
Processing: 5 247 971.0 10 4204
Waiting: 3 245 971.3 7 4204
Total: 16 259 973.3 21 4225
Percentage of the requests served within a certain time (ms)
50% 21
66% 23
75% 24
80% 24
90% 26
95% 4225
98% 4225
99% 4225
100% 4225 (longest request)
Czas końcowy jest podobny do testu internetowego, ale wydaje się być nieco gorszy, gdy jest uruchamiany lokalnie. Co ciekawsze, profil zmienił się dramatycznie. Podczas gdy wcześniej większość długoterminowych żądań była poświęcana na „łączenie”, teraz wąskie gardło wydaje się być w trakcie przetwarzania lub oczekiwania. Podejrzewam, że może to być osobny problem, który wcześniej był maskowany przez ograniczenia sieciowe.
Ponownie uruchamiając test z innego komputera w tej samej sieci lokalnej co host Apache, widzę znacznie bardziej rozsądne wyniki:
Connection Times (ms)
min mean[+/-sd] median max
Connect: 1 2 0.8 2 4
Processing: 13 118 99.8 205 222
Waiting: 13 118 99.7 204 222
Total: 15 121 99.7 207 225
Percentage of the requests served within a certain time (ms)
50% 207
66% 219
75% 220
80% 221
90% 222
95% 224
98% 224
99% 225
100% 225 (longest request)
Te dwa testy razem rodzą szereg pytań, ale niezależnie od tego, należy teraz przekonująco uzasadnić pewne poważne wąskie gardło sieci występujące pod pewnym obciążeniem. Myślę, że następnym krokiem będzie osobne zbadanie warstwy sieci.
źródło
Odpowiedzi:
To, co zrobiłbym w tej sytuacji, jest uruchomione
na jednym z procesów Apache podczas testu ab, aż do przechwycenia jednej z wolnych odpowiedzi. Następnie przejrzyj
trace.txt
.-tt
I-T
opcji daje znacznika czasu rozpoczęcia i czas trwania każdego wywołania systemowego, aby zidentyfikować te powolne.Możesz znaleźć pojedyncze wolne połączenie systemowe, takie jak
open()
lub,stat()
lub możesz znaleźć szybkie połączenie z (prawdopodobnie wieloma)poll()
połączeniami bezpośrednio po nim. Jeśli znajdziesz taki, który działa na pliku lub połączeniu sieciowym (całkiem prawdopodobne), przejrzyj ślad do tyłu, aż znajdziesz ten uchwyt pliku lub połączenia. Wcześniejsze wywołania tego samego uchwytu powinny dać ci wyobrażenie o tym, na copoll()
czekał.Dobry pomysł, patrząc na tę
-c
opcję. Czy upewniłeś się, że śledzone dziecko Apache zrealizowało co najmniej jedno wolne żądanie w tym czasie? (Nie jestem nawet pewien, jak byś to zrobił, opróczstrace
jednoczesnego uruchamiania na wszystkich dzieciach).Niestety
strace
nie daje nam pełnego obrazu tego, co robi uruchomiony program. Śledzi tylko połączenia systemowe. Wiele może się wydarzyć w programie, który nie wymaga pytania jądra o nic. Aby dowiedzieć się, czy tak się dzieje, możesz spojrzeć na znaczniki czasu rozpoczęcia każdego wywołania systemowego. Jeśli widzisz znaczące luki, tam właśnie zmierza czas. Nie jest to łatwe do grepowania, a między wywołaniami systemowymi zawsze występują niewielkie luki.Ponieważ powiedziałeś, że użycie procesora pozostaje niskie, prawdopodobnie nie jest to nadmierne zjawisko pomiędzy wywołaniami systemowymi, ale warto to sprawdzić.
Przyglądając się bliżej wynikom z
ab
:Nagły skok w czasach odpowiedzi (wygląda na to, że nie ma żadnych czasów odpowiedzi w przedziale od 150 ms do 3000 ms) sugeruje, że zdarza się określony limit czasu, który jest uruchamiany powyżej około 256 jednoczesnych połączeń. Bardziej płynna degradacja byłaby oczekiwana, gdyby zabrakło pamięci RAM lub cykli procesora normalnych operacji we / wy.
Po drugie, powolna
ab
odpowiedź pokazuje, że 3000 ms zostało wydane wconnect
fazie. Prawie wszystkie zajęły około 30ms, ale 5% zajęło 3000ms. Sugeruje to, że problem stanowi sieć.Skąd uciekasz
ab
? Czy możesz wypróbować go z tej samej sieci co komputer Apache?Aby uzyskać więcej danych, spróbuj uruchomić
tcpdump
na obu końcach połączenia (najlepiejntp
na obu końcach, aby zsynchronizować oba przechwytywanie.) I poszukaj retransmisji TCP. Wireshark jest szczególnie dobry do analizy zrzutów, ponieważ wyróżnia retransmisje TCP w innym kolorze, dzięki czemu można je łatwo znaleźć.Warto również przejrzeć dzienniki dowolnych urządzeń sieciowych, do których masz dostęp. Niedawno napotkałem problem z jedną z naszych zapór ogniowych, która mogła obsługiwać przepustowość pod względem kb / s, ale nie mogła obsłużyć liczby odbieranych pakietów na sekundę. Osiągnęło to prędkość 140 000 pakietów na sekundę. Kilka szybkich obliczeń w
ab
biegu prowadzi mnie do wniosku, że widziałbyś około 13 000 pakietów na sekundę (ignorując 5% powolnych żądań). Może to jest wąskie gardło, które osiągnąłeś. Fakt, że dzieje się to około 256, może być czystym zbiegiem okoliczności.źródło