Ajustando o desempenho de um servidor Apache de alta carga


12

Estou procurando entender alguns problemas de desempenho do servidor que estou vendo com um servidor da Web (para nós) muito carregado. O ambiente é o seguinte:

  • Debian Lenny (todos os pacotes estáveis ​​+ corrigidos para atualizações de segurança)
  • Apache 2.2.9
  • PHP 5.2.6
  • Instância grande do Amazon EC2

O comportamento que observamos é que a Web normalmente se sente responsiva, mas com um pequeno atraso para começar a lidar com uma solicitação - às vezes uma fração de segundo, às vezes 2-3 segundos nos nossos horários de pico. A carga real no servidor está sendo relatada como muito alta - geralmente 10.xx ou 20.xx, conforme relatado por top. Além disso, a execução de outras coisas no servidor durante esses períodos (pares vi) é muito lenta, portanto a carga está definitivamente lá em cima. Curiosamente, o Apache permanece muito responsivo, além do atraso inicial.

Temos o Apache configurado da seguinte maneira, usando o prefork:

StartServers          5
MinSpareServers       5
MaxSpareServers      10
MaxClients          150
MaxRequestsPerChild   0

E KeepAlive como:

KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

Observando a página de status do servidor, mesmo nesses momentos de carga pesada, raramente atingimos o limite do cliente, geralmente atendendo entre 80 a 100 solicitações e muitas daquelas no estado de manutenção de atividade. Isso me diz para descartar a lentidão inicial da solicitação como "aguardando um manipulador", mas posso estar errado.

O monitoramento CloudWatch da Amazon me diz que, mesmo quando nosso sistema operacional está relatando uma carga> 15, nossa utilização da CPU da instância está entre 75 e 80%.

Exemplo de saída de 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

A maioria dos processos se parece com:

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            

Exemplo de saída vmstatao mesmo tempo que o acima:

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

E, finalmente, saída do 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..........................................
................................................................

Da minha experiência limitada, tiro as seguintes conclusões / perguntas:

  • Podemos estar permitindo KeepAlivepedidos demais

  • Eu vejo algum tempo gasto esperando E / S no vmstat, embora não seja consistente e nem muito (eu acho?), Por isso não tenho certeza se isso é uma grande preocupação ou não, tenho menos experiência com o vmstat

  • Também no vmstat, vejo em algumas iterações vários processos aguardando para serem atendidos, que é o que eu atribuo ao atraso inicial do carregamento da página em nosso servidor da Web, possivelmente erroneamente

  • Servimos uma mistura de conteúdo estático (75% ou superior) e conteúdo do script, e o conteúdo do script geralmente é bastante intensivo em processador, portanto, é importante encontrar o equilíbrio certo entre os dois; a longo prazo, queremos mudar a estática para outro lugar para otimizar os dois servidores, mas nosso software não está pronto para isso hoje

Fico feliz em fornecer informações adicionais, se alguém tiver alguma idéia, a outra observação é que esta é uma instalação de produção de alta disponibilidade, por isso tenho receio de fazer ajustes após ajustes, e é por isso que não brinquei com coisas como o KeepAlivevalor ainda.


Uma ótima pergunta sangrenta, bem formulada e pensada. Espero que você tenha a resposta que merece!
Dave Rix

Respostas:


7

Começarei admitindo que não gosto muito de executar coisas nas nuvens - mas com base na minha experiência em outro lugar, diria que essa configuração de servidor da web reflete um volume de tráfego bastante baixo. O fato de a fila de execução ser tão grande sugere que simplesmente não há CPU suficiente disponível para lidar com isso. O que mais há na fila de execução?

Podemos estar permitindo muitas solicitações KeepAlive

O KeepPlive ainda melhora o desempenho, os navegadores modernos são muito inteligentes em saber quando canalizar e quando executar solicitações em paralelo, embora um tempo limite de 5 segundos ainda seja bastante alto e você tenha MUITOS servidores aguardando - a menos que você ' Se você tiver grandes problemas de latência, recomendo aumentar para 2-3. Isso deve diminuir um pouco a fila de execução.

Se você ainda não possui o mod_deflate instalado no servidor da Web - recomendo que faça isso - e adicione o ob_gzhandler () aos seus scripts PHP. Você pode fazer isso como uma pré-adição automática:

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

(sim, a copressão usa mais CPU - mas você deve economizar a CPU em geral, tirando os servidores da fila de execução mais rapidamente / lidando com menos pacotes TCP - e, como bônus, seu site também é mais rápido).

Eu recomendo definir um limite superior no MaxRequestsPerChild - digamos algo como 500. Isso apenas permite alguma rotatividade nos processos, caso você tenha um vazamento de memória em algum lugar. Seus processos httpd parecem ENORMES - verifique se você removeu todos os módulos apache de que não precisa e verifique se está fornecendo conteúdo estático com boas informações de armazenamento em cache.

Se você ainda estiver tendo problemas, provavelmente o problema está no código PHP (se você usar o fastCGI, isso deve ser evidente sem grandes penalidades de desempenho).

atualizar

Se o conteúdo estático não variar muito entre as páginas, também vale a pena experimentar:

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

nos scripts PHP também.


Entre uma variedade de boas respostas, eu estou marcando isso como o aceito, porque você afirmou claramente que este era um problema associado à CPU (em grande parte devido ao mau aplicativo que estamos executando) e esse certamente era o caso. Reimplantei tudo nas instâncias 2x2 grandes do EC2 (acima do grande) e a maioria dos problemas desapareceu, embora muitas das outras características de desempenho ainda estejam lá. Temos apenas o aplicativo único em execução nesses servidores, e é simplesmente feio.
futureal 21/02

4

Você deve considerar a instalação de um proxy reverso assíncrono, porque vários processos no estado W também são bastante altos. Seus processos Apache parecem gastar muito tempo enviando conteúdo para diminuir a velocidade de bloqueio de clientes na rede. O Nginx ou o lighttpd como interface para o servidor Apache pode reduzir drasticamente vários processos no estado W. E sim, você deve limitar uma série de solicitações de manutenção de atividade. Provavelmente vale a pena tentar desativar a manutenção de atividade.

BTW, 107 processos Apache são altos demais para 22 rps; pude atender 100-120 rps usando apenas 5 processos Apache. Provavelmente, o próximo passo é criar um perfil do seu aplicativo.


Sim, definitivamente concordo que o aplicativo é uma grande parte do problema. Ele foi terceirizado e, desde então, está sujeito a muitos patches e outros enfeites que apenas pioraram, e um esforço de redesenho está em andamento. Esta noite tentei desativar o KeepAlive sem nenhum efeito real, e meu próximo passo é tentar esse proxy reverso, provavelmente com o nginx com base em tudo que li desde então.
futureal 4/02

Para acompanhar, comecei a experimentar o proxy reverso e provavelmente o implantarei na produção em um futuro próximo. Obrigado (e aos outros que a sugeriram) pela idéia, não é algo com o qual eu tenha mexido antes, mas acho que isso terá um impacto até que possamos fazer um redesenho completo.
futureal 21/02

1

Você tem duas linhas em seu vmstat que mostram que o tempo de espera da CPU é bastante alto e, em torno delas, você faz um número razoável de gravações (io-bo) e alternância de contexto. Eu examinaria o que está escrevendo blocos e como eliminar essa espera. Eu acho que a maior melhoria pode ser encontrada na melhoria da IO do disco. Verifique syslog - defina-o para escrever assíncrono. Verifique se o cache de gravação do seu controlador está funcionando (verifique - você pode ter uma bateria com defeito).

O Keepalive não está causando seu problema de desempenho, economiza tempo na configuração da conexão se você não estiver executando um cache na frente. Você pode bater um pouco no MaxSpareServers para que, em uma crise, não esteja esperando todos os garfos.


Não estou familiarizado o suficiente com o syslog para saber como configurá-lo para gravações assíncronas no Apache, embora eu certamente procure e procure por isso. Fiz algumas alterações hoje à noite relacionadas ao KeepAlive e MaxSpareServers sem nenhum efeito real; concordo em deixar mais peças de reposição, pois tinha perdido isso. Uma qualidade (ruim) do nosso aplicativo é que ele grava muito em arquivos de sessão do usuário (sim, arquivos), e é aí que começo a pensar que estamos sofrendo. Tenho a opção de mover o gerenciamento de sessões para o banco de dados, o que provavelmente tentarei a seguir.
futureal 4/04

Sim, eu concordo que as gravações da sua sessão são a fonte do problema. Você pode perder as gravações do disco da sessão se estiver usando sessões php - instale o memcache e defina session.save_handler do PHP como memcache e session.save_path como tcp : //127.0.0.1: 11211 (ou onde quer que você configure o memcache). O log do Apache é assíncrono por padrão, mas às vezes os aplicativos da Web podem usar o syslog, ou o syslog pode ser falador e está fazendo uma sincronização para cada linha. Afinal, não parece que seria o seu problema. Você pode prefixar as linhas de entrada do arquivo com '-' no syslog.conf para omitir a sincronização.
beans

0

considere desativar a manutenção de atividade como primeira tentativa ...

com 107 pedidos processados, manteria o MaxSpareServers superior ao que você definiu ...

IMHO a longo prazo nginx como proxy reverso para conteúdo estático deve ser levado em consideração


0

Primeira sugestão: desative os keepalives. Eu só precisei disso quando consegui identificar uma situação específica em que o desempenho aumentou, mas, em geral, as solicitações / s diminuíram com o Keepalive ativado.

Segunda sugestão: defina um MaxRequestsPerChild. Eu echo o symcbean aqui, ele ajudará na rolagem do processo no caso de um vazamento de memória. 500 é um bom ponto de partida.

Terceira sugestão: aumente o MaxClients. Um cálculo aproximado para isso é (memória física - memória usada pelo processo não httpd) / tamanho de cada processo httpd. Dependendo de como o httpd foi compilado, esse número chega a 255. Uso 250 nos meus servidores públicos para lidar com o rastreamento de sistemas do google / yahoo / MS.

Quarta sugestão: Aumente o MaxSpareServers: algo como 4-5x MinSpareServers.

Se essas sugestões falharem, eu examinaria o balanceamento de carga com proxy reverso ou memcache para DB.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.