Como solucionar problemas de desempenho de PHP, MySQL e E / S genérica

4

Eu tenho um site baseado em WordPress rodando em uma hospedagem compartilhada. Seu tempo de resposta é muito decente (cerca de 2s para recuperar a página HTML e 5s para carregar todos os recursos).

Eu estava planejando movê-lo para um servidor virtual dedicado (Ubuntu 12.04 LTS), que teoricamente melhoraria as coisas e as tornaria mais consistentes, já que não são compartilhadas. No entanto, observei grave degradação do desempenho, com a página levando 10 segundos a ser gerada.

Eu excluí problemas de rede editando /etc/hosts no servidor e mapeando o domínio para 127.0.0.1 . Eu usei o testador de carga do Apache ab para obter o HTML, para que JS, CSS e imagens sejam excluídos. Ainda demorou 10 segundos.

Eu tenho o Zpanel instalado no servidor, que também usa o MySQL, e suas páginas são bem rápidas (1.5s) e também phpMyAdmin. Realizar algumas consultas no banco de dados wordpress diretamente através do phpMyAdmin também os retorna rapidamente, com tempos de consulta na região de 10 a 30 milissegundos.

A memória também é suficiente, com apenas 800Mb sendo usado da memória física de 1Gb disponível, então não parece ser um problema de troca. Eu também instalei a APC para tentar melhorar o desempenho do PHP, mas isso não teve nenhum efeito.

O que mais eu devo procurar? O que poderia estar causando essa degradação no desempenho? Poderia ser algum tipo de problema de I / O desde que eu estou executando em um servidor virtual baseado em nuvem?

Gostaria de poder levantar o problema com meu provedor, mas sem mostrar dados reais de algum diagnóstico, tenho medo de que ele apenas culpe meu aplicativo.

UPDATE com sar output (a cada segundo) quando fiz uma solicitação HTTP:

02:31:29        CPU     %user     %nice   %system   %iowait    %steal     %idle
02:31:30        all      0.00      0.00      0.00      0.00      0.00    100.00
02:31:31        all      2.22      0.00      2.22      0.00      0.00     95.56
02:31:32        all     41.67      0.00      6.25      0.00      2.08     50.00
02:31:33        all     86.36      0.00     13.64      0.00      0.00      0.00
02:31:34        all     75.00      0.00     25.00      0.00      0.00      0.00
02:31:35        all     93.18      0.00      6.82      0.00      0.00      0.00
02:31:36        all     90.70      0.00      9.30      0.00      0.00      0.00
02:31:37        all     71.05      0.00      0.00      0.00      0.00     28.95
02:31:38        all     14.89      0.00     10.64      0.00      2.13     72.34
02:31:39        all      2.56      0.00      0.00      0.00      0.00     97.44
02:31:40        all      0.00      0.00      0.00      0.00      0.00    100.00
02:31:41        all      0.00      0.00      0.00      0.00      0.00    100.00

UPDATE 2 Após as sugestões de josten.

E / S:

iotop falha com OSError: Netlink error: No such file or directory (2) e sar -d também falha com Requested activities not available in file /var/log/sysstat/sa14 . Eu acho que isso é porque esta é uma máquina virtual, assim como iostat também falha. Poderia ser a razão pela qual %iowait relatado por sar 1 10 é sempre 0%?

Carga da CPU:

O processo que está superando a% da CPU em htop é, na verdade, apache2 . Eu estava esperando isso talvez seja o banco de dados, mas não é. Ele vai até 94% por alguns segundos quando eu faço uma nova requisição HTTP. Parece que este é o culpado.

Eu fiz um strace -f -t e um resumo strace -c -f . Parece haver uma enorme quantidade de lstat chamadas (57786), com 2455 resultando em erros. Não faço ideia se isso é normal. Além disso, a chamada mais importante foi wait4 , o que presumo ser normal (está apenas esperando) e munmap . Top 5 abaixo.

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 51.06    0.124742         897       139         6 wait4
 14.90    0.036388           1     57786      2455 lstat
  9.67    0.023622          13      1857           munmap
  7.69    0.018790          37       514           brk
  6.70    0.016361         481        34           clone
  2.87    0.006999          74        94        12 select

strace em si diminuiu o apache por um fator de 2. Estou tentando entender o traço longo agora para ver se há algo indicativo do que estava causando o aumento da CPU por alguns segundos.

Qual é a hora típica de lstat para um servidor com bom desempenho? Desejo coletar algumas informações para que eu possa reclamar de maneira construtiva para o provedor se for a falha de acesso ao armazenamento.

UPDATE Saída do teste de leitura aleatória fio :

random-read: (g=0): rw=randread, bs=4K-4K/4K-4K, ioengine=sync, iodepth=1
fio 1.59
Starting 1 process
random-read: Laying out IO file(s) (1 file(s) / 128MB)
Jobs: 1 (f=1): [r] [100.0% done] [12185K/0K /s] [2975 /0  iops] [eta 00m:00s]
random-read: (groupid=0, jobs=1): err= 0: pid=24264
  read : io=131072KB, bw=10298KB/s, iops=2574 , runt= 12728msec
    clat (usec): min=119 , max=162219 , avg=380.34, stdev=957.37
     lat (usec): min=119 , max=162219 , avg=380.89, stdev=957.40
    bw (KB/s) : min= 7200, max=13424, per=99.89%, avg=10285.72, stdev=1608.68
  cpu          : usr=2.80%, sys=18.65%, ctx=33511, majf=0, minf=23
  IO depths    : 1=100.0%, 2=0.0%, 4=0.0%, 8=0.0%, 16=0.0%, 32=0.0%, >=64=0.0%
     submit    : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     complete  : 0=0.0%, 4=100.0%, 8=0.0%, 16=0.0%, 32=0.0%, 64=0.0%, >=64=0.0%
     issued r/w/d: total=32768/0/0, short=0/0/0
     lat (usec): 250=45.57%, 500=37.17%, 750=3.41%, 1000=7.83%
     lat (msec): 2=5.67%, 4=0.27%, 10=0.08%, 20=0.01%, 250=0.01%

Run status group 0 (all jobs):
   READ: io=131072KB, aggrb=10297KB/s, minb=10545KB/s, maxb=10545KB/s, mint=12728msec, maxt=12728msec

A única dica que tenho agora é que a linha de CPU da saída fio parece mostrar um pouco de atividade quando comparada a outros sistemas. Eu corri na minha máquina Ubuntu local e a saída era:

cpu          : usr=0.19%, sys=0.59%, ctx=32923, majf=0, minf=23

A porcentagem usr parece ser uma pequena fração do que está sendo reportado no meu servidor.

UPDATE Re PHP APC. Sim está instalado. Saída do phpinfo:

APC Support enabled
Version 3.1.7
APC Debugging   Disabled
MMAP Support    Enabled
MMAP File Mask  no value
Locking type    pthread mutex Locks
Serialization Support   php
Revision    $Revision: 307215 $
Build Date  May 2 2011 19:00:42

Existe alguma configuração específica que devo verificar? Estas são as configurações que eu tenho (valor local, valor mestre):

apc.cache_by_default    On  On
apc.canonicalize    On  On
apc.coredump_unmap  Off Off
apc.enable_cli  Off Off
apc.enabled On  On
apc.file_md5    Off Off
apc.file_update_protection  2   2
apc.filters no value    no value
apc.gc_ttl  3600    3600
apc.include_once_override   Off Off
apc.lazy_classes    Off Off
apc.lazy_functions  Off Off
apc.max_file_size   1M  1M
apc.mmap_file_mask  no value    no value
apc.num_files_hint  1000    1000
apc.preload_path    no value    no value
apc.report_autofilter   Off Off
apc.rfc1867 Off Off
apc.rfc1867_freq    0   0
apc.rfc1867_name    APC_UPLOAD_PROGRESS APC_UPLOAD_PROGRESS
apc.rfc1867_prefix  upload_ upload_
apc.rfc1867_ttl 3600    3600
apc.serializer  default default
apc.shm_segments    1   1
apc.shm_size    32M 32M
apc.slam_defense    On  On
apc.stat    On  On
apc.stat_ctime  Off Off
apc.ttl 0   0
apc.use_request_time    On  On
apc.user_entries_hint   4096    4096
apc.user_ttl    0   0
apc.write_lock  On  On

UPDATE Aumentou apc.shm_size para 96M. A contagem total do cache agora é 0 e há 96,5% de acertos no cache após algumas atualizações do site aqui e ali. O uso de memória da APC é de 25,4 MB grátis.

Parece ter reduzido o tempo de carregamento em 3 segundos ou mais, agora para cerca de 4 a 5 segundos se eu fizer um wget puro do próprio servidor sem obter nenhuma imagem, etc. Ainda mais que duas vezes mais lento que o outra hospedagem, mas definitivamente foi uma melhoria.

Eu ainda estou achando estranho porque estava demorando tanto para renderizar essas páginas quando o servidor está totalmente ocioso (eu não tenho o APC instalado no meu PC de desenvolvimento e ele não tem esse tipo de comportamento). E ainda é estranho onde esses segundos extras restantes estão sendo desperdiçados.

    
por jbx 23.11.2013 / 00:34

4 respostas

2

Isso parece com outros casos que vi onde o Apache está gastando muito tempo compilando o PHP. Você se certificou de que um cache opcode (por exemplo, APC) está instalado? Ele será mostrado como um módulo carregado na saída de phpinfo() , se isso ajudar. Caso contrário, para acompanhar o que o Apache está fazendo dentro de mod_php, sua melhor aposta será o XHProf.

Para qualquer pessoa que não seja jbx chegando aqui via Google: as outras respostas são excelentes, a propósito. Vá lê-los. Mas essas respostas e as respostas do jbx a elas me ajudaram a chegar a essa conclusão.

    
por 18.11.2013 / 21:37
10

Você precisa primeiro determinar qual é o problema primeiro; se é PHP, MySQL, E / S, carga, memória, CPU, kernel, etc. sar registra as métricas dos sistemas; você terá que pegá-lo no ato. Você pode configurar o atop para processar a contabilidade, o que definitivamente ajuda.

Para determinar se é E / S

Use ferramentas como iotop e atop para ver qual é o uso do disco; Essas ferramentas também informam o que está causando o IO. Geralmente, se o iowait é sustentado acima de 10%, esse poderia ser o problema.

sar registra o disco IO; então você pode executar sar -d para ver (veja em %util column).

Para determinar se é a carga

Use ferramentas como htop , top , uptime ; novamente amarre isso ao processo em execução e descubra mais detalhes sobre o que o processo está fazendo. Observe que isso informa a carga no agendador; isso não reflete o uso da CPU.

Para determinar se é uma CPU

sar mais uma vez entra para salvar o dia; você pode ver essas informações com sar -P ALL . Você também pode usar mpstat -P ALL para dados em tempo real. Geralmente, a CPU é apenas um problema se todas as CPUs estiverem em 100%; 80% + significa que estão sendo utilizados (mas não necessariamente saturados).

Para determinar se é a memória (VM)

Você vai querer usar vmstat ; vmstat -S M 1 e observe as colunas swap , io e system . Obviamente, uma grande quantidade de troca pode afetar o desempenho. Há também a seção system ; uma grande quantidade de interrupções também pode fazer o mesmo.

Para determinar se é interrompido

Você pode usar vmstat -S M 1 . Infelizmente, é difícil dizer se as interrupções são o problema se o seu sistema não tiver uma linha de base sobre o que é normal. Uma grande quantidade de interrupções (que são causadas pelo hardware que requer ação do kernel) fará o sistema rastrear. NICs com falha são notórias por fazer isso.

Para determinar se é o kernel

Isso é mais complicado, mas geralmente requer as ferramentas strace , perf ou sysdig . Uma dessas ferramentas é perf top . strace com um resumo ( -c ) é bom, mas não o divide em relação aos recursos do sistema (portanto, os dados fornecidos são apenas especulações); É ideal usar perf top para chegar à conclusão de que é o kernel. Você também pode usar stap (SystemTap) se a sua máquina suportar isso. Também devo observar que strace afetará o desempenho; você deve usar sysdig se o sistema for importante.

Para determinar se é o MySQL / PHP

Você basicamente tem que seguir o que eu postei acima ( perf , por exemplo, pode fornecer informações sobre qual comando está causando alto tempo no kernel, iotop , atop , htop pode fornecer informações relativas aos recursos do sistema está usando-os); basicamente, você está usando as ferramentas acima para determinar o que está causando a carga.

Depois de determinar que é o MySQL

Pode ser uma consulta que você está executando (então você vai querer usar EXPLAIN nessa consulta no MySQL). Você também precisará garantir que seu banco de dados seja otimizado e que as consultas que você está executando sejam otimizadas. Você também precisa ter certeza de que o mecanismo de tabela que você está usando é ideal para o que você está fazendo (eu vi muitas tabelas grandes que MyISAM quando deveriam ser InnoDB). Se você determinou que nenhum dos itens acima é o problema e ainda suspeita que o MySQL você queira arquivar dados nas tabelas afetadas para reduzir o acesso (varredura de tabela) àquela tabela. Você também pode verificar a consistência da restrição, ativar o armazenamento em cache e garantir que os índices estejam ótimos.

Uma boa ferramenta para ajudar nesse processo é mytop ; mas todas as informações que mytop fornece são facilmente acessíveis no cliente mysql . Algumas instruções úteis para executar:

  • SHOW FULL PROCESSLIST\G para obter uma lista completa das instruções SQL atualmente em execução, bem como seu status para o servidor.
  • SHOW ENGINE INNODB STATUS\G (apenas InnoDB)
  • EXPLAIN EXTENDED <QUERY> para explicar uma consulta que você vê executando o MySQL.
  • SHOW GLOBAL STATUS\G para um status de todo o servidor

Depois de determinar que é PHP

Você pode usar ferramentas para criar um perfil do seu código PHP (como xdebug ) e, em seguida, abrir o perfil gerado em KCacheGrind para ver uma análise de desempenho do código PHP no perfil.

Se você achar que não é nada disso, talvez seja necessário atualizar seu servidor.

    
por 13.11.2013 / 05:25
2

Veja a resposta que eu deu a outra pergunta semelhante a esta para pistas.

A coisa é, se outras páginas fora da área do WordPress estão carregando bem, mas o próprio WordPress está entupido, três coisas vêm à mente fora das coisas genéricas que eu recomendo.

  1. Quando você migrou seu código do WordPress para a nova configuração, você definiu corretamente todos os caminhos no sistema de arquivos em wp-config.php ? O motivo é que, às vezes, o WordPress pode funcionar apesar dos caminhos incorretos, se esses forem configurados nas opções do banco de dados MySQL para WordPress. Certificar-se de que eles estão em wp-config.php forçam o WordPress a usar os diretórios corretos & garante temp & as pastas de cache funcionam conforme o esperado.
  2. Desaceleração do banco de dados? Essa é a única outra coisa que posso imaginar que seria idiossincrática para o WordPress, mas permitir que outras páginas sejam carregadas. Tem certeza de que o seu MySQL my.cnf está funcionando como deveria para as necessidades de banco de dados do seu site?
  3. Você tem um plug-in ou configuração em seu código do WordPress que permite a compactação Gzip? Em geral, a compressão Gzip deve acontecer no lado do servidor via Apache ou Ngnix, uma vez que eles podem entregar a compressão Gzip de forma mais eficiente que o código PHP. Portanto, se você tiver o cache ativado no WordPress, desabilite-o, pois o PHP (que é o que o WordPress usa) não é excelente em compactação Gzip.

Em geral, configurei vários sites CMS - mais recentemente o WordPress - em servidores de nuvem sem problemas. um carregamento de página de 10 segundos não é um sintoma do host da nuvem sendo inadequado. Eu recomendaria olhar sobre as coisas que eu recomendo aqui & na minha outra resposta. E eu também recomendaria a depuração, fazendo uma instalação limpa do WordPress na configuração que é um problema & veja como isso reage. Se isso funcionar bem em comparação com o site completo, é claro que há algum problema de configuração no código específico de seu site.

EDIT: Aqui está outra ideia. Você tem autorização do Apache (htaccess) em qualquer lugar da sua configuração? Você tem definido para permitir a partir de localhost ? Ver abaixo. Às vezes, essa configuração funciona, mas se Allow from localhost for o primeiro da lista de Allow ou o único item na lista de Allow , ele poderá se engasgar com a estranheza do DNS reverso. Eu recomendaria tentar desabilitar isso, se possível, e ver a velocidade com que o site é carregado em comparação com a ativação.

Order Deny,Allow
Deny from all
Allow from 127.0.0.1 ::1
Allow from localhost
    
por 11.11.2013 / 02:51
2

Uma das maiores origens de E / S, para sites com tráfego intenso, é /tmp I / O, que ocorre em:

  1. /tmp é lido para dados de sessão do php, para muitos sistemas CMS, como o WordPress em cada transição de página para determinar se o visitante tem autoridade para acessar uma nova página

  2. /tmp é gravado / lido muitas vezes para qualquer SQL SELECT em que os dados retornados ou quaisquer conjuntos de seleção temporários criados residam em / tmp

A primeira coisa que faço ao migrar um cliente de uma máquina lenta para uma nova (esperançosamente mais rápida) máquina é a memória de tamanho. Meus 30 segundos rápidos são:

(memória superior usada + troca usada) * 2

Então na nova máquina eu configurei /tmp para rodar em tmpfs (memória) + use mysqltuner (a cada poucos dias) + sintonize mysql (realmente mariadb) até < em> mysqltuner é principalmente silencioso.

Às vezes, esse truque simples é tudo o que é necessário para dar uma nova vida a um servidor de desempenho lento.

Uma vez que isso é feito, se a máquina ainda estiver lenta, começo a sintonizar cada subsistema.

Quando sintonizo, sempre inicio com uma ferramenta que me informa o estado atual.

Assim, para o redimensionamento da memória, use top (memory + swap + load).

Para o Apache , verifique os logs para garantir que não haja mensagens como MaxRequestWorkers sendo excedidos.

Para as versões antigas do PHP , use um monitor APC para garantir que o APC esteja realmente funcionando + tem muita memória de sobra + a taxa de acertos é alta - 90% + é um bom alvo.

Para versões modernas do PHP, faça o mesmo com o Opcache, que substituiu a APC há vários anos.

Para o MySQL , primeiro mude para o MariaDB (muito mais rápido na minha experiência) + use o mysqltuner a cada poucos dias até que você tenha uma saída bastante tranquila.

Para CMSs como o WordPress, nunca aceite a palavra de ninguém sobre o funcionamento do plugin de armazenamento em cache. Use ab para testar a velocidade do site, primeiro sem armazenamento em cache + adicione um plug-in de cache + reteste.

Dica: Comece com o ZenCache + você ficará surpreso.

Por fim, simulo um ataque DDOS de slowloris contra cada novo servidor que eu configurei, pois o comportamento do DDOS funciona de maneira diferente dependendo do layout da rede + velocidade do adaptador + recursos da máquina. Eu tento sistemas para sobreviver a ataques DDOS por tempo suficiente para que os códigos de status do Apache 4xx (geralmente 400 + 408) apareçam nos logs do Apache + use o fail2ban para bloquear esses IPs.

Uma grande parte do ajuste de i / o é gerar situações incomuns de carga, como o DDOS do slowloris, antes de implantar qualquer site em uma máquina. Desta forma, você pode sintonizar em seu próprio lazer, ao invés de tentar sintonizar sob carga real, como um Ad Spend ou recebendo Slashdotted ... ou sob carga de ataque como DDOS ou um High Value Attack ou apenas um malvado scrapper que ignora seu robots.txt + suga todos os recursos da sua máquina.

    
por 14.07.2015 / 16:16