O Apache pára de se comunicar com o memcache depois de criar muitos vhosts

3

Eu notei um problema muito peculiar com o Apache. Eu tenho um número muito alto de hosts virtuais configurados - é cerca de 501.

Problemas começaram a ocorrer após o vhost número 493. Os primeiros 493 vhosts funcionam como esperado, mas assim que eu adiciono o vhost número 494, o PHP pára de se comunicar com o memcache, e ele expira em cada acesso de leitura / gravação.

Na verdade, estou usando o memcache como armazenamento de sessões de back-end, portanto, função php:

session_start();

simplesmente expira após 30 s.

Se eu excluir o aleatório dos 494 vhosts e reiniciar o apache, ele começará a funcionar novamente.

Eu configurei o ulimit muito alto (65k), mas isso não ajuda. Eu tentei desligar os ulimits completamente, mas sem sorte.

Vocês têm alguma ideia do que mais eu poderia tentar?

Eu testei o stracing do processo httpd ao qual estou conectado, depois que acessei a entrada no navegador e depois de 30 segundos a espera começa.

Esta é a saída strace:

select(1170, [1024 1169], [], NULL, {1, 0}) = 2 (in [1024 1169], left {0, 999998})
select(1170, [1024 1169], [], NULL, {1, 0}) = 2 (in [1024 1169], left {0, 999998})
select(1170, [1024 1169], [], NULL, {1, 0}) = 2 (in [1024 1169], left {0, 999998})
select(1170, [1024 1169], [], NULL, {1, 0}) = 2 (in [1024 1169], left {0, 999998})
select(1170, [1024 1169], [], NULL, {1, 0}) = 2 (in [1024 1169], left {0, 999998})

Então, basicamente, o apache está preso em select (), e é isso, ele repete a chamada do sistema select () indefinidamente.

A próxima coisa que eu descobri é o tcpdump, para ver se o pacote realmente passa pelo apache, e realmente funciona:

22:11:28.366677 IP6 ::1.51404 > ::1.11914: Flags [S], seq 2899674987, win 32752, options [mss 16376,sackOK,TS val 1384759049 ecr 0,nop,wscale 9], length 0
22:11:28.366697 IP6 ::1.11914 > ::1.51404: Flags [S.], seq 2034630080, ack 2899674988, win 32728, options [mss 16376,sackOK,TS val 1384759049 ecr 1384759049,nop,wscale 9], length 0
22:11:28.366709 IP6 ::1.51404 > ::1.11914: Flags [.], ack 1, win 64, options [nop,nop,TS val 1384759049 ecr 1384759049], length 0
22:11:28.366752 IP6 ::1.51404 > ::1.11914: Flags [P.], seq 1:41, ack 1, win 64, options [nop,nop,TS val 1384759049 ecr 1384759049], length 40
22:11:28.366758 IP6 ::1.11914 > ::1.51404: Flags [.], ack 41, win 64, options [nop,nop,TS val 1384759049 ecr 1384759049], length 0
22:11:28.366768 IP6 ::1.51404 > ::1.11914: Flags [P.], seq 41:90, ack 1, win 64, options [nop,nop,TS val 1384759050 ecr 1384759049], length 49
22:11:28.366772 IP6 ::1.11914 > ::1.51404: Flags [.], ack 90, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 0
22:11:28.366779 IP6 ::1.51404 > ::1.11914: Flags [P.], seq 90:122, ack 1, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 32
22:11:28.366783 IP6 ::1.11914 > ::1.51404: Flags [.], ack 122, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 0
22:11:28.367063 IP6 ::1.11914 > ::1.51404: Flags [P.], seq 1:12, ack 122, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 11
22:11:28.367070 IP6 ::1.51404 > ::1.11914: Flags [.], ack 12, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 0
22:11:28.367266 IP6 ::1.11914 > ::1.51404: Flags [P.], seq 12:20, ack 122, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 8
22:11:28.367275 IP6 ::1.51404 > ::1.11914: Flags [.], ack 20, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 0
22:11:28.367477 IP6 ::1.11914 > ::1.51404: Flags [P.], seq 20:25, ack 122, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 5
22:11:28.367489 IP6 ::1.51404 > ::1.11914: Flags [.], ack 25, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 0
22:11:28.367629 IP6 ::1.51404 > ::1.11914: Flags [P.], seq 122:181, ack 25, win 64, options [nop,nop,TS val 1384759050 ecr 1384759050], length 59
22:11:28.367859 IP6 ::1.11914 > ::1.51404: Flags [P.], seq 25:33, ack 181, win 64, options [nop,nop,TS val 1384759051 ecr 1384759050], length 8
22:11:28.367869 IP6 ::1.51404 > ::1.11914: Flags [P.], seq 181:230, ack 33, win 64, options [nop,nop,TS val 1384759051 ecr 1384759051], length 49
22:11:28.368102 IP6 ::1.11914 > ::1.51404: Flags [P.], seq 33:41, ack 230, win 64, options [nop,nop,TS val 1384759051 ecr 1384759051], length 8
22:11:28.368138 IP6 ::1.51404 > ::1.11914: Flags [F.], seq 230, ack 41, win 64, options [nop,nop,TS val 1384759051 ecr 1384759051], length 0
22:11:28.368195 IP6 ::1.11914 > ::1.51404: Flags [F.], seq 41, ack 231, win 64, options [nop,nop,TS val 1384759051 ecr 1384759051], length 0
22:11:28.368206 IP6 ::1.51404 > ::1.11914: Flags [.], ack 42, win 64, options [nop,nop,TS val 1384759051 ecr 1384759051], length 0

A próxima coisa que fiz foi o processo do GDB Apache ao emitir uma chamada curl para uma página contendo session_start (), e esta é a saída:

232     *(*new)->local_addr = *sock->local_addr;
241     if (sock->local_addr->sa.sin.sin_family == AF_INET) {
238     (*new)->local_addr->pool = connection_context;
241     if (sock->local_addr->sa.sin.sin_family == AF_INET) {
238     (*new)->local_addr->pool = connection_context;
241     if (sock->local_addr->sa.sin.sin_family == AF_INET) {
245     else if (sock->local_addr->sa.sin.sin_family == AF_INET6) {
246         (*new)->local_addr->ipaddr_ptr = &(*new)->local_addr->sa.sin6.sin6_addr;
249     (*new)->remote_addr->port = ntohs((*new)->remote_addr->sa.sin.sin_port);
250     if (sock->local_port_unknown) {
256     if (apr_is_option_set(sock, APR_TCP_NODELAY) == 1) {
257         apr_set_option(*new, APR_TCP_NODELAY, 1);
266     if (sock->local_interface_unknown ||
267         !memcmp(sock->local_addr->ipaddr_ptr,
266     if (sock->local_interface_unknown ||
276         (*new)->local_interface_unknown = 1;
293     apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup,
292     (*new)->inherit = 0;
293     apr_pool_cleanup_register((*new)->pool, (void *)(*new), socket_cleanup,
296 }   
unixd_accept (accepted=0x7fff14ecddf0, lr=0x7fe93a905aa8, ptrans=<value optimized out>) at /usr/src/debug/httpd-2.2.15/os/unix/unixd.c:507
507     if (status == APR_SUCCESS) {
508         *accepted = csd;
649 }   
child_main (child_num_arg=<value optimized out>) at /usr/src/debug/httpd-2.2.15/server/mpm/prefork/prefork.c:650
650         SAFE_ACCEPT(accept_mutex_off());      /* unlock after "accept" */
652         if (status == APR_EGENERAL) {
656         else if (status != APR_SUCCESS) {
665         current_conn = ap_run_create_connection(ptrans, ap_server_conf, csd, my_child_num, sbh, bucket_alloc);
666         if (current_conn) {
667             ap_process_connection(current_conn, csd);

Neste local há uma grande pausa (~ 30 seg.), até o tempo limite do php. Depois disso, eu entendi:

668             ap_lingering_close(current_conn);
676         if (ap_mpm_pod_check(pod) == APR_SUCCESS) { /* selected as idle? */
680                  ap_scoreboard_image->global->running_generation) { /* restart? */
679         else if (ap_my_generation !=
680                  ap_scoreboard_image->global->running_generation) { /* restart? */
679         else if (ap_my_generation !=
551     while (!die_now && !shutdown_pending) {
559         apr_pool_clear(ptrans);
562              && requests_this_child++ >= ap_max_requests_per_child)) { 
561         if ((ap_max_requests_per_child > 0
562              && requests_this_child++ >= ap_max_requests_per_child)) {
561         if ((ap_max_requests_per_child > 0
562              && requests_this_child++ >= ap_max_requests_per_child)) {
561         if ((ap_max_requests_per_child > 0
566         (void) ap_update_child_status(sbh, SERVER_READY, (request_rec *) NULL);
573         SAFE_ACCEPT(accept_mutex_on());
575         if (num_listensocks == 1) {

O mais estranho é que não consigo reproduzir isso em outra máquina. Mesmo SO, mesmos pacotes, mesma configuração (fantoche) mesmo kernel, diferentes HW.

    
por Jakov Sosic 03.10.2014 / 03:06

1 resposta

2

Depois de mais algumas semanas de depuração e de procurar problemas, finalmente encontrei uma mensagem:

You MUST recompile PHP with a larger value of FD_SETSIZE.
It is set to 1024, but you have descriptors numbered at least as high as 1073.
--enable-fd-setsize=2048 is recommended, but you may want to set it to equal
the maximum number of open files supported by your system, in order to avoid
seeing this error again at a later date. 

Vou tentar essa correção, mas cara, cara, por que os caras PHP fazem isso? Isso é tão feio, hardcoding limite nofile é totalmente quebrado design. Sem mencionar que, se esta é a solução, forçar-me a recompilar cada versão menor do PHP e patch de segurança e manter meus próprios pacotes é uma grande confusão.

EDIT: após uma depuração mais extensa, parece que não é só o PHP que está 'quebrado por design', mas também há um monte de problemas com a própria extensão memcache.

link

link

Bugs estão abertos por um bom tempo agora, e nada acontece. Eu acho que um deve apenas despejar extensão memcache e encontrar uma solução independente dele: - /

    
por 02.12.2014 / 14:38