Back-End

14 fev, 2017

O método mais rápido para melhorar o desempenho de qualquer Servidor de Aplicações Web PHP usando MySQL ou PostgreSQL

Publicidade

No mundo do desenvolvimento Web, muitas vezes enfrentamos o problema da escolha do servidor certo para o ambiente de produção de um aplicativo Web.

Talvez precisemos comprar um novo servidor para suportar a carga esperada, ou talvez o cliente queira implantar em um servidor existente.

Em ambos os casos, se depois da implantação e execução, o aplicativo apresentar um desempenho ruim, então teremos que perguntar à equipe o que podemos fazer para tornar a aplicação mais rápida, ou usar um servidor melhor.

Portanto, precisamos determinar se o aplicativo tem uma boa performance. Leia este artigo para aprender a determinar rapidamente o desempenho de um aplicativo no servidor atual.

Introdução

Todos os desenvolvedores querem lançar suas aplicações Web e estar prontos para lidar eventualmente com grandes quantidades de tráfego quando tiverem sucesso.

O principal desafio da avaliação de desempenho do servidor é que ela precisa ser feita rapidamente, sem o uso de ferramentas especiais (leia complicadas) e, claro, antes do anúncio do lançamento do aplicativo.

Para isso, devemos ser capazes de capturar algumas métricas do servidor e multiplicar os valores pelos fatores de desempenho de aplicações conhecidas, para estimar o desempenho do aplicativo no servidor.

Na realidade, fazer isso não é para todos os desenvolvedores, e também não é todo mundo que quer fazê-lo.

Neste artigo, eu vou falar sobre as técnicas e as ferramentas que eu uso para avaliar o desempenho de um servidor.

Situações típicas

1. Escolher hospedagem e servidor

A equipe começa a se preparar para lançar o aplicativo e logo lançará a primeira versão do produto.

O próximo passo é implantar a aplicação no servidor, e podemos precisar comprar e personalizar um já existente.

Na reunião geral do projeto, o gerente de projeto responsável faz esta pergunta “simples”: “Então, quem vai escolher a hospedagem e servidor? Vou fornecer o valor necessário para orçamento do projeto na próxima etapa”. Normalmente, desejando que esse não seja um grande problema.

Além disso, tentar delegar, “Bob, você pode por favor fazer essa tarefa?” não funciona. Bob vai encontrar imediatamente e listar, pelo menos, uma dúzia de tarefas urgentes e importantes pelas quais ele é responsável agora que a entrega é para ontem.

Seguindo o bom senso de autopreservação, a equipe consistentemente diz ao gerente do projeto onde ele pode procurar um especialista nisso (e não na vizinhança mais próxima), e ele vai escolher exatamente a configuração ideal para o servidor.

2. O servidor é poderoso o suficiente?

De acordo com os requisitos iniciais fornecidos pelo cliente em relação ao servidor, parece uma situação perfeita no início do projeto, mas não é assim quando chega o lançamento do projeto.

O cliente pergunta: “O servidor é poderoso?”. A resposta esperada é: “Sim!”. Após a implantação, o líder do projeto fica triste quando ele analisa os tempos de resposta do aplicativo Web. Um pensamento desagradável surge: “De quem é a culpa?”. E “O que devo fazer?”.

Ele descobre que a configuração necessária para o servidor deve ser definida por ele mesmo, mas, por outro lado, um especialista não foi encontrado na região. Na verdade, acontece de esse servidor poderoso, um VPS barato cujos parâmetros pareciam bons, compartilha os recursos do host com um exército de clientes de hospedagem. O cliente pagou o servidor por cinco anos e não vai mudar nada.

3.  Nível avançado: o cliente tem o servidor e tem um administrador

As configurações do servidor são satisfatórias, mas depois de implantar o aplicativo vemos quedas terríveis, lags e delays. O nosso servidor de desenvolvimento é três vezes mais lento, mas a aplicação pode executar oito vezes mais rápido em um novo servidor.

Nenhuma das nossas propostas para a substituição ou a compra de um novo servidor é aceita, já que, na opinião do administrador, vai travar “sua” aplicação.

O cliente não sabe em quem acreditar. E também não gosta da ideia de ter uma nova despesa, então o argumento do administrador conta mais.

O gerente do projeto exige que a equipe forneça uma explicação clara de “por que o aplicativo está lento”, e números que mostrem a “culpa” do servidor. A equipe, como sempre, tem muito tempo livre, então todos ficam felizes em assumir a resolução do problema e dar uma cerveja para o especialista de outro departamento pela dica sobre “onde encontrar o especialista”.

  • Escolha de um servidor de aplicação e da carga;
  • Avaliação da capacidade do servidor existente;
  • Ser capaz de responder à pergunta “Por que está tão lento?”

Concluindo, temos de enfrentar algumas situações e determinar quais tarefas precisamos ser capazes de resolver.

Requisitos para realizar medições

A forma mais precisa de medir o desempenho do servidor também é a mais óbvia: você precisa instalar uma aplicação no servidor e executar uma aplicação que cause uma carga real. Embora esse processo dê um resultado preciso, é inútil, por diversas razões:

  • Queremos saber as capacidades do servidor antes de colocar em produção;
  • O método de medição deve ser rápido e barato;
  • A ferramenta de medição deve ser fácil de usar e instalar no servidor;
  • O resultado da medição deve ser fácil de interpretar e comparar.

O alvo da medição

O servidor é comprado, o sistema operacional está instalado, e sshd daemon está em execução. Abra o console e acesse o servidor. Console preto, letras verdes e um cursor intermitente silencioso perguntando: “E agora?”. É hora de pensar no que será medido e o que constitui a performance.

Até agora, a pergunta parecia simples: “Começar com qualquer referência, e tudo vai ficar claro”. Agora, com o cursor piscando, o pensamento trava e você não consegue nem inserir os comandos necessários.

O que influencia no desempenho depende muito de:

  • Velocidade da CPU + memória RAM;
  • Velocidade do subsistema de disco;
  • Desempenho do tempo de execução da linguagem da aplicação (nesse caso, o PHP);
  • Configuração do banco de dados (temos MySQL ou PostgreSQL);
  • E, claro, a aplicação (quais recursos está utilizando);

Precisamos ter quatro ferramentas que possam medir a velocidade individualmente:

  • Para os componentes do servidor: CPU + RAM e subsistema de disco;
  • Para os componentes de software: MySQL e PHP

Tendo os resultados das medições, podemos falar do complexo desempenho de um servidor como um todo, e podemos prever a carga das aplicações Web.

Ferramentas de medição

O que é o sysbench?

Eu não posso descrever melhor essa ferramenta que o seu autor, por isso cito sua descrição:

SysBench é uma ferramenta multiplataforma, modular e multithreaded para avaliar os parâmetros do sistema operacional que são importantes para executar um sistema de banco de dados sob carga intensa.
A ideia desse pacote de análise de referência é obter rapidamente informações sobre o desempenho do sistema sem a criação de pontos de medida complexos no banco de dados ou mesmo sem a instalação de um banco de dados.

É disso que você precisa. Sysbench permite ter rapidamente uma ideia do desempenho do sistema sem ter que instalar pontos de referência e ferramentas complexas.

Instale o Sysbench

É muito simples.

apt-get install sysbench

Você pode compilar:

$ ./autogen.sh
$ ./configure
$ make

Verifique o desempenho da CPU

Para isso, precisamos executar um cálculo de vinte mil primos.

$ sysbench --test=cpu --cpu-max-prime=20000 run

Como padrão, o cálculo será realizado em um único núcleo. Usamos –num-threads = N Key, se quisermos tirar proveito dos cálculos paralelos.

O resultado do teste:

Test execution summary:
 total time:                           17.3915s
 total number of events:               10000

 total time taken by event execution:  17.3875
 per-request statistics:
   min:                    1.66ms
   avg:                    1.74ms
   max:                    4.00ms
   approx.  95 percentile: 2.03ms

O interessante sobre esse teste é o valor do tempo total. Iniciando o teste em vários servidores, podemos comparar as medidas.

Aqui está um exemplo desse teste executado em servidores que eu administrava no momento da preparação deste artigo.

Obs.:

  • G2 é aproximadamente três vezes mais rápido do que o A3;
  • VPS’ka simples no Reg.Ru por US$ 4/mês comparável a um G2 :);
  • Xeon X3440 funcionou tão bem como o NUC i5;
  • Surpreendentemente os mesmos resultados foram obtidos nos quatro servidores;
  • Talvez ela deixe cálculo ocorrer nos mesmos blocos da CPU que não refletem o desempenho geral do processador.

Testando o desempenho do disco

A verificação do subsistema de disco é realizada em três etapas:

  • Preparar (gerar) um conjunto de arquivos de texto;
  • Realizar o teste, remover os indicadores;
  • Limpar o lixo.

Preparando arquivos de texto:

$ sysbench --test=fileio --file-total-size=70G prepare

A equipe irá criar um conjunto de arquivos com um tamanho total de 70 gigabytes. O tamanho deve exceder significativamente a quantidade de memória RAM para que o resultado do teste não afete o cache do sistema operacional.

A execução do teste:

$ sysbench --test=fileio --file-total-size=70G --file-test-mode=rndrw
--init-rng=on --max-time=300 --max-requests=0 run

O teste será feito em modo de leitura aleatória (rndw) para 300 segundos, depois os resultados serão mostrados. Novamente, o teste padrão será executado em um único segmento (número de threads: 1).

Limpe os arquivos temporários:

$ sysbench --test=fileio cleanup

Um exemplo do resultado do teste:

Operations performed:  249517 Read, 166344 Write, 532224 Other = 948085
Read 3.8073Gb  Written 2.5382Gb  Total transferred 6.3455Gb  (21.659Mb/sec)
 1386.18 Requests/sec executed

Test execution summary:
    total time:                          300.0045s
    total number of events:              415861
    total time taken by event execution: 178.9646
    per-request statistics:
         min:                                  0.00ms
         avg:                                  0.43ms
         max:                                205.67ms
         approx.  95 percentile:               0.16ms

Threads fairness:
    events (avg/stddev):           415861.0000/0.00
    execution time (avg/stddev):   178.9646/0.00

Como uma medida de desempenho do subsistema de disco, você pode usar o valor da taxa de dados média (neste exemplo, 21.659Mb/seg).

Vamos ver o que esse teste apresentou nos meus servidores:

Obs.:

  • Valores de consumo de velocidade de forma suspeita baixos em todos os servidores testados;
  • O NUC i5 utiliza drive SSD, não importa quantas vezes eu execute o teste, o valor da taxa de dados tem sido sempre na faixa de 1,5 a 2 Mb/seg.

Teste de performance MySQL OLTP

O teste verifica a velocidade das transações do servidor MySQL, cada transação consiste de pedidos de leitura e escrita.

É muito conveniente alterar as configurações do servidor no my.cnf, reiniciar e executar uma série de testes – imediatamente melhora a performance.

Preparando-se para o teste:

$ sysbench --test=oltp --oltp-table-size=1000000 --mysql-db=test
 --mysql-user=root --mysql-password=pass prepare

Teste rodando:

$ sysbench --test=oltp --oltp-table-size=1000000 --mysql-db=test
 --mysql-user=root --mysql-password=pass --max-time=60 --oltp-read-only=off --max-requests=0 --num-threads=8 run

O parâmetro –oltp-read-only pode ser ativado. Em seguida, serão executados apenas pedidos de leitura, permitindo que a base de dados estime o modo de velocidade, por exemplo, servo-base.

O resultado do teste:

OLTP test statistics:
    queries performed:
        read:                            564158
        write:                           0
        other:                           80594
        total:                           644752
    transactions:                        40297  (671.57 per sec.)
    deadlocks:                           0      (0.00 per sec.)
    read/write requests:                 564158 (9402.01 per sec.)
    other operations:                    80594  (1343.14 per sec.)

Test execution summary:
    total time:                          60.0040s
    total number of events:              40297
    total time taken by event execution: 479.8413
    per-request statistics:
         min:                                  1.14ms
         avg:                                 11.91ms
         max:                                 70.93ms
         approx.  95 percentile:              15.54ms

A opção mais interessante do relatório é o número de transações por segundo (transações por segundo).

O que esse teste mostrou nos servidores:

Obs.:

  • A configuração do MySQL foi a mesma em todos os servidores;
  • A ausência de diferenças significativas entre A3 e servidores G2 é surpreendente;
  • NUC i5 comparado com G2;

Como medir o desempenho do PostgreSQL?

Infelizmente, a ferramenta sysbench tem ferramentas embutidas para testes em PostgreSQL. Mas isso não nos impede inteiramente, porque podemos usar o utilitário pgbench.

Cenários padrão de benchmark executam repetidamente a seguinte transação:

BEGIN;
UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;
UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;
INSERT INTO pgbench_history (tid, bid, aid, delta, mtime)
VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
END;

Para criar um caso de teste, rode:

$ pgbench -h localhost -U test_user -i -s 100 test

Realizamos os testes:

$ pgbench -h localhost -U test_user -t 5000 -c 4 -j 4 test

 O comando Keys significa que o cliente irá executar 4 5000 4 transações por segmento. Como resultado, 20000 transações serão executadas.

Resultado…

starting vacuum...end.
transaction type: TPC-B (sort of)
scaling factor: 10
query mode: simple
number of clients: 4
number of threads: 4
number of transactions per client: 5000
number of transactions actually processed: 20000/20000
latency average: 0.000 ms
tps = 3350.950958 (including connections establishing)
tps = 3357.677756 (excluding connections establishing)

O mais importante aqui é tps.

Testes comparativos em diferentes servidores, infelizmente, não.

E o desempenho do PHP?

Com sysbench e uma abundância de quilowatts de energia para a CPU de muitos servidores, aprendemos muito rapidamente e de forma adequada a forma de avaliar o desempenho do servidor. Consequentemente, isso nos permite fornecer uma previsão especializada do desempenho de aplicativos Web nesse servidor.

No entanto, há situações em que sysbench mostrou um bom resultado, e a aplicação PHP no servidor demonstra métricas de desempenho bastante medíocres.

É claro que o resultado é influenciado por parâmetros como:

  • Versão do PHP
  • A presença do acelerador
  • Como e o que é compilado no PHP
  • Quais extensões são ativadas

Eu adoraria ter uma ferramenta que fosse fácil de instalar e, depois de iniciar, desse métricas claras de desempenho do PHP atual no servidor.

E como essa ferramenta não afeta o desempenho do subsistema de disco (ou rede), meça apenas o trabalho do intérprete PHP em um grupo de CPU e memória.

Uma simples reflexão levou à conclusão de que:

  • Os instrumentos existentes ainda estão lá;
  • É possível escolher o algoritmo adequado;
  • Enquanto não há imutabilidade no algoritmo, podemos comparar os resultados obtidos.

Eu encontrei um script que pode ser usado para isso. O script é compilado como arquivo phar, que se torna significativamente mais fácil para baixar e executar em qualquer servidor. A versão mínima do PHP para executar é a 5.4.

Para começar:

$ wget github.com/florinsky/af-php-bench/raw/master/build/phpbm.phar
$ php phpbm.phar

 O script executa 10 testes, divididos em três grupos:

  • O primeiro grupo é de operações comuns (ciclos, margem, criação/exclusão de objetos);
  • O segundo grupo é de testes: verifica funções de string, implosão/explosão, hashes de cálculo;
  • O terceiro é trabalhar com arrays;
  • Todas as medições são feitas em segundos.

Sobre a implementação do relatório de teste:

[GENERAL]
 1/10 Cycles (if, while, do)  ...................... 6.72s
 2/10 Generate Random Numbers  ..................... 3.21s
 3/10 Objects  ..................................... 4.82s
Time: .. 14.76

[STRINGS]
 4/10 Simple Strings Functions  ................... 13.09s
 5/10 Explode/Implode  ............................ 15.90s
 6/10 Long Strings  ............................... 30.37s
 7/10 String Hash  ................................ 23.57s
Time: .. 82.93

[ARRAYS]
 8/10 Fill arrays  ................................ 22.32s
 9/10 Array Sort (Integer Keys and Values)  ....... 17.17s
10/10 Array Sort (String Keys and Values)  ........ 14.29s
Time: .. 53.79

TOTAL TIME: . 151.47

O script permite não só avaliar o desempenho geral do PHP no servidor (tempo total), mas também verificar o que é mais lento. Repetidamente eu vi resultados globais medíocres apenas para um teste: em algum lugar que pode ser uma operação lenta do gerador de números aleatórios, e em alguns casos trabalhar com longas cadeias.

Conclusão

Gostaria de acrescentar que as ferramentas acima nos permitem estimar o desempenho do servidor apenas no momento da medição. Deve ser entendido que o servidor pode afetar os processos executados em paralelo. E se os seus testes mostraram bons resultados, isso não significa que sempre será assim.

Em particular, esse problema se manifesta quando você analisa o servidor do cliente, que já está em pleno funcionamento. Você não sabe o que as tarefas do cron fazem, quais processos estão à espera de seus eventos de processamento de tarefas, se eles executam longas atividades de processamento de arquivos gzip/tar, se eles estão trabalhando com filtros antivírus ou spam, e muitos outros tipos de tarefas que poderiam ser desconhecidas para você.

Para analisar o comportamento do servidor, atop e iostat podem ajudar. Se processarmos as estatísticas para alguns dias (ou mais), você pode ver quase tudo o que estiver acontecendo.

Atop

Gravar os dados em um arquivo:

$ atop -w /tmp/atop.raw 1 60

 Ler o registro:

$ atop -r /tmp/atop.raw

 iostat

 Medindo o uso da CPU:

$ iostat -c 1

Conclusão:

%user     %nice    %system    %iowait    %steal    %idle
82.21      0.00      17.79       0.00      0.00     0.00
79.05      0.00      20.70       0.00      0.00     0.25
80.95      0.00      19.05       0.00      0.00     0.00
80.95      0.00      19.05       0.00      0.00     0.00
80.85      0.00      18.91       0.25      0.00     0.00
...

Medindo o subsistema de disco de inicialização:

$ iostat -xd /dev/sda 1

Conclusão:

rkB/s    wkB/s  await    r_await      w_await    svctm     %util
0.00   2060.00   4.05       0.00         4.05     3.98     95.60
0.00   2000.00   3.97       0.00         3.97     3.95     96.40
0.00   1976.00   3.92       0.00         3.92     3.92     95.60
0.00   2008.00   3.95       0.00         3.95     3.93     96.00
0.00   2008.00   3.92       0.00         3.92     3.92     96.80
0.00   2020.00   4.03       0.00         4.03     4.00     97.60
0.00   2016.00   3.97       0.00         3.97     3.97     97.20
...

E, claro, você pode usar Munin ou programas similares para coletar estatísticas de um servidor por um longo tempo.

Se você gostou deste artigo, compartilhe com seus colegas desenvolvedores. Se você tiver dúvidas sobre a avaliação e a melhora no desempenho, poste um comentário aqui.

***

Dmitry Mamontov faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: https://www.phpclasses.org/blog/post/514-php-mysql-postgresql-performance-evaluating-and-tuning.html.