Apache Tomcat dusi się po 300 połączeniach

16

Mamy serwer Apache przed Tomcat hostowany na EC2, typ instancji jest bardzo duży z pamięcią 34 GB.

Nasza aplikacja zajmuje się wieloma zewnętrznymi usługami internetowymi i mamy bardzo kiepską zewnętrzną usługę internetową, która zajmuje prawie 300 sekund, aby odpowiedzieć na żądania w godzinach szczytu.

W godzinach szczytu serwer dusi się przy około 300 procesach httpd. ps -ef | grep httpd | wc -l = 300

Poszukałem go i znalazłem wiele sugestii, ale wydaje się, że nic nie działa. Poniżej podano niektóre konfiguracje, które wykonałem bezpośrednio z zasobów internetowych.

Zwiększyłem limity maksymalnego połączenia i maksymalnej liczby klientów zarówno w Apache, jak i Tomcat. oto szczegóły konfiguracji:

// apache

   <IfModule prefork.c>
    StartServers 100
    MinSpareServers 10
    MaxSpareServers 10
    ServerLimit 50000
    MaxClients 50000
    MaxRequestsPerChild 2000
    </IfModule>

//kocur

    <Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol"
           connectionTimeout="600000"
           redirectPort="8443"
           enableLookups="false" maxThreads="1500"
           compressableMimeType="text/html,text/xml,text/plain,text/css,application/x-javascript,text/vnd.wap.wml,text/vnd.wap.wmlscript,application/xhtml+xml,application/xml-dtd,application/xslt+xml"
           compression="on"/>

//Sysctl.conf

 net.ipv4.tcp_tw_reuse=1
 net.ipv4.tcp_tw_recycle=1
 fs.file-max = 5049800
 vm.min_free_kbytes = 204800
 vm.page-cluster = 20
 vm.swappiness = 90
 net.ipv4.tcp_rfc1337=1
 net.ipv4.tcp_max_orphans = 65536
 net.ipv4.ip_local_port_range = 5000 65000
 net.core.somaxconn = 1024

Próbowałem wiele sugestii, ale na próżno ... jak to naprawić? Jestem pewien, że serwer m2xlarge powinien obsłużyć więcej żądań niż 300, prawdopodobnie może się nie udać moja konfiguracja.

Serwer dusi się tylko w godzinach szczytu i gdy 300 współbieżnych żądań czeka na odpowiedź usługi [z opóźnieniem 300 sekund].

Właśnie monitorowałem połączenia tcp z netstat

znalazłem około 1000 połączeń w stanie TIME_WAIT, nie mam pojęcia, co to by oznaczało pod względem wydajności, jestem pewien, że to musi powiększać problem.

Produkcja TOP

 8902  root      25   0 19.6g 3.0g  12m S  3.3  8.8  13:35.77 java
 24907 membase   25   0  753m 634m 2528 S  2.7  1.8 285:18.88 beam.smp
 24999 membase   15   0  266m 121m 3160 S  0.7  0.3  51:30.37 memcached
 27578 apache    15   0  230m 6300 1536 S  0.7  0.0   0:00.03 httpd
 28551 root      15   0 11124 1492  892 R  0.3  0.0   0:00.25 top


 Output of free -m
 total       used       free     shared    buffers    cached
 35007       8470       26536    0          1         61
 8407        26599
 15999       15         15984

 output of iostat
 avg-cpu:  %user   %nice %system %iowait  %steal   %idle
      26.21    0.00    0.48    0.13    0.02   73.15

Device:            tps   Blk_read/s   Blk_wrtn/s   Blk_read   Blk_wrtn
sda1             14.36         4.77       329.37    9005402  622367592
sdb               0.00         0.00         0.00       1210         48

Również w godzinach szczytu jest około 10-15 tys. Połączeń TCP do serwera membase [lokalny]

NIEKTÓRE BŁĘDY W DZIENNIKU MODJK, mam nadzieję, że rzuci to nieco światła na ten problem ..

[Wed Jul 11 14:39:10.853 2012] [8365:46912560456400] [error]         ajp_send_request::jk_ajp_common.c (1630): (tom2) connecting to backend failed. Tomcat is probably not started or is listening on the wrong port (errno=110)
[Wed Jul 11 14:39:18.627 2012] [8322:46912560456400] [error] ajp_send_request::jk_ajp_common.c (1630): (tom2) connecting to backend failed. Tomcat is probably not started or is listening on the wrong port (errno=110)
[Wed Jul 11 14:39:21.358 2012] [8351:46912560456400] [error] ajp_get_reply::jk_ajp_common.c (2118): (tom1) Tomcat is down or refused connection. No response has been sent to the client (yet)
[Wed Jul 11 14:39:22.640 2012] [8348:46912560456400] [error] ajp_get_reply::jk_ajp_common.c (2118): (tom1) Tomcat is down or refused connection. No response has been sent to the client (yet)

~

Worker.properties
workers.tomcat_home=/usr/local/tomcat/
worker.list=loadbalancer
worker.tom1.port=8009
worker.tom1.host=localhost
worker.tom1.type=ajp13
worker.tom1.socket_keepalive=True
worker.tom1.connection_pool_timeout=600
worker.tom2.port=8109
worker.tom2.host=localhost
worker.tom2.type=ajp13
worker.tom2.socket_keepalive=True
worker.tom2.connection_pool_timeout=600
worker.loadbalancer.type=lb
worker.loadbalancer.balanced_workers=tom1,tom2
worker.loadbalancer.sticky_session=True
worker.tom1.lbfactor=1
worker.tom1.socket_timeout=600
worker.tom2.lbfactor=1
worker.tom2.socket_timeout=600

//Rozwiązany

dzięki za cenne sugestie. Pominąłem ustawienia maxThreads dla złącza AJP 1.3. Teraz wszystko wydaje się pod kontrolą.

Zacznę też patrzeć na nawet oparte na serwerach, takich jak Nginx.

John Titus
źródło
Jakie są twoje ustawienia Keepalive?
Tom O'Connor,
Jakiego rodzaju błędy klienci zwracają podczas próby załadowania strony?
Shane Madden
1
Czy zwiększyłeś maksymalną dozwoloną liczbę otwartych opisów plików dla użytkownika apache / httpd?
golja
@Tom My Keep Alive Ustawienia są KeepAliveTimeout 10 w httpd.conf
john titus
3
Jak wygląda wyjście topw tych czasach? Jak o free -m? I na koniec iostat?
Zypher,

Odpowiedzi:

13

Czy zwiększyłeś maxThreads w złączu AJP 1.3 na porcie 8009?

HTTP500
źródło
1500 jest tym, co mam na instancję tomcat
John Titus
@ john, czy mówisz, że dla każdego złącza podałeś maxThreads = "1500"? Czy możesz opublikować swoją sekcję dotyczącą złącza AJP 1.3 (port 8009)?
HTTP500
dzięki za zwrócenie na to uwagi .. nie ma w ogóle ustawienia maxThreads dla AJP1.3. czy to może być powód?
John Titus
1
Tak, dodaj maxThreads do sekcji dla tego łącznika. Wartość domyślna to 200.
HTTP500
6

Rozważ skonfigurowanie asynchronicznego serwera proxy, takiego jak Apache nginxlub lighttpdprzed nim. Apache obsługuje zawartość synchronicznie, więc pracownicy są blokowani, dopóki klienci nie pobiorą w pełni wygenerowanej treści (więcej szczegółów tutaj ). Skonfigurowanie asynchronicznego (nieblokującego) serwera proxy zwykle znacznie poprawia sytuację (zwykłem zmniejszać liczbę równolegle działających pracowników Apache z 30 do 3–5, używając nginxproxy jako interfejsu użytkownika).

Alex
źródło
5

Podejrzewam, że twój problem dotyczy tomcat, a nie apache, z dzienników, które i tak pokazałeś. Gdy pojawia się „błąd 110”, który próbuje ponownie połączyć się z tomcat, oznacza to, że masz kolejkę połączeń oczekujących na obsłużenie, której już nie można dopasować do konfiguracji zaległości nasłuchiwania dla gniazda nasłuchiwania w tomcat.

From the listen manpage:
   The  backlog  parameter defines the maximum length the queue of pending 
   connections may grow to.  If a connection request arrives with
   the queue full the client may receive an error with an indication
   of ECONNREFUSED or, if the underlying protocol supports  
   retransmission, the request may be ignored so that retries succeed.

Gdybym musiał zgadywać, podejrzewałbym, że ogromna większość żądań HTTP, gdy serwer „dusi się” jest zablokowana, czekając na coś, co wróci z tomcat. Założę się, że jeśli spróbujesz pobrać jakieś statyczne treści, które są bezpośrednio obsługiwane przez apache (zamiast być proxy dla tomcat), że zadziała to nawet wtedy, gdy normalnie „dusi się”.

Niestety nie jestem zaznajomiony z tomcat, ale czy istnieje sposób na zmanipulowanie tego ustawienia współbieżności?

Aha, i może trzeba również wziąć pod uwagę możliwość, że jej zewnętrzne usługi sieciowe ów ograniczający liczbę połączeń, to jest robienie z tobą aż do 300, więc nie ma znaczenia, ile manipulacja współbieżności robisz na przedniej stronie jeśli praktycznie każde wykonane połączenie opiera się na odpowiedzi zewnętrznych usług internetowych.

W jednym z komentarzy wspomniałeś, że dane stają się nieaktualne po 2 minutach. Sugeruję buforowanie odpowiedzi otrzymywanej z tej usługi przez dwie minuty, aby zmniejszyć liczbę jednoczesnych połączeń, które kierujesz do zewnętrznej usługi internetowej.

Matthew Ife
źródło
2

Pierwszym krokiem do rozwiązania tego problemu jest włączenie mod_status Apache'a i przestudiowanie jego raportu - dopóki tego nie zrobisz, tak naprawdę ślepo chodzisz. To nie jest sprawiedliwe. ;-)

Drugą rzeczą do wspomnienia (sam nie lubię otrzymywać odpowiedzi na pytania, których nie zadawałem, ale ...) używa bardziej wydajnych i specjalnych serwerów typu front-end nginx.

Również zrobił dokładnie restartapache, lub po prostu gracefully przeładował go? :)

poige
źródło
Apache uruchomił się ponownie. Nie jest to pełne wdzięku przeładowanie
John Titus
@johntitus, cóż, w każdym razie mod_statusjest twoim przyjacielem. :)
poige
1

W przypadku wszelkiego rodzaju wdrożeń w przedsiębiorstwie prefabrykacja MPM jest prawie najgorszym wyborem, jaki możesz zrobić: pożera zasoby jak niczyja firma, a restartowanie wątków zajmuje ZAWSZE w porównaniu z innymi MPM.

Przynajmniej przełącz się na roboczy MPM (apache 2.2 i nowsze) lub - jeszcze lepiej - uaktualnij do bieżącej stabilnej wersji 2.4.2 z domyślnym zdarzeniem MPM.

Oba z łatwością poradzą sobie z tysiącami równoczesnych połączeń przy bardzo niewielkim obciążeniu.

adapttr
źródło
dzięki .. próbowałem tego też ... bez powodzenia. Liczba połączeń TIME_WAIT stale rośnie. Serwer przestaje odpowiadać przy 350 połączeniach
John Titus
1
Nie zgadzam się, że jest to najgorszy wybór - jest to zły wybór w tym kontekście i prawdopodobne jest, że problemy zostaną złagodzone przy użyciu serwera wątkowego, ale lepszym rozwiązaniem byłoby użycie serwera opartego na zdarzeniach (nginx lub lighttpd). Apache oparty na zdarzeniach nie jest wystarczająco dojrzały, aby można go było wziąć pod uwagę przy wdrożeniu korporacyjnym IMHO.
symcbean
1

Wiem, że to stara historia, ale mam 2 uwagi.

Istnieje sztywny limit dla dyrektywy ServerLimit . http://httpd.apache.org/docs/2.2/mod/mpm_common.html#serverlimit zobaczysz, że jest to maksymalnie 20000 / 200K.

Istnieje sztywny limit ServerLimit 20000 wkompilowany w serwer (dla prefork MPM 200000). Ma to na celu uniknięcie nieprzyjemnych efektów spowodowanych literówkami.

2. Najwyraźniej nodybo wspomniał, że ustawienie tych 2 na jeden to bardzo zły pomysł :

net.ipv4.tcp_tw_reuse=1
net.ipv4.tcp_tw_recycle=1

oznacza to, że ponownie wykorzystujesz czas oczekiwania, zgadnij co? serwer może rozmawiać z niewłaściwym klientem pod dużym obciążeniem.

Znalazłem bardzo dobry artykuł wyjaśniający to, ale - to francuski ;-) http://vincent.bernat.im/fr/blog/2014-tcp-time-wait-state-linux.html

Nadir
źródło
0

bardzo duży z pamięcią 34 GB.

Duże żelazo nie jest sposobem na skalowanie usług internetowych, po prostu przesuwasz wąskie gardła. Ale nawet przy tak dużej pamięci podejrzewam, że 50000 połączeń naciska na to, co potrafi system, szczególnie jeśli:

W godzinach szczytu serwer dusi się przy około 300 procesach httpd

Byłoby pomocne, gdybyś wyjaśnił, co masz na myśli przez „dławiki serwera”.

Dziwnie jest też mieć tak wysoki limit połączeń, ale bardzo niski limit histerezy (min / maks zapasowe serwery).

Chociaż wyciąg z podanych błędów nie pokazuje wymownego „zbyt wielu otwartych plików”, zacznę od zbadania liczby otwartych deskryptorów plików i ustawień ulimit.

symcbean
źródło
Serwerowe dławiki, jak w nim, nie reagują nawet na normalne pliki HTML.
John Titus
Zmieniłem maxClients na 3000 teraz .. wciąż ten sam problem
John Tit
0

Być może użytkownik Apache nie ma już dozwolonych uchwytów plików? W ogóle nie wspomniałeś o nich w swoim poście. Ile uchwytów plików może mieć obecnie Apache?

Janne Pikkarainen
źródło
Uchwyty plików 128192
John Tit
0

To bardziej jak komentarz, ale tak samo nie mogę, jak mam mniej reputacji. Natknąłem się na dokładnie podobny problem, jak @John Titus.

MaxThreadsAby rozwiązać problem, złącze AJP zbliżyło się do limitu wątku Apache.

Aby to monitorować, szukaliśmy pomocy dotyczącej SYN_SENT statusu portu netstat w komendzie netstat na naszym porcie AJP.

netstat -an | grep :8102 | grep SYN_SENT | wc -l

Sprowadziło się to do 0, co zawsze było dużą liczbą przed limitem MaxThread ustawionym na złączu AJP.

Vineeth
źródło