
Olá Habr! Meu nome é Timur Shagiakhmetov, sou desenvolvedor de PHP no
Badoo .
O desempenho do aplicativo é um dos critérios mais importantes para a qualidade do trabalho de um programador. Em questões de otimização de aplicativos PHP, o assistente é o criador de perfil.
Recentemente,
conversamos sobre quais ferramentas usamos para criar perfis. Deixe-me lembrá-lo: uma das ferramentas para análise de desempenho, quando não está claro quais partes do código influenciaram o aumento no tempo de geração de resposta, é o
XHProf . Essa é uma extensão do PHP que permite criar um perfil do código em um servidor de combate e melhorá-lo posteriormente.
Mas eu também gostaria de ter um histórico de alterações no desempenho para que você possa acompanhar o que e quando afetou sua deterioração, certo? Para fazer isso, há cerca de um ano, desenvolvemos o
Liveprof , uma ferramenta para a criação automática de perfil de todas as solicitações com uma interface para analisar as alterações no desempenho do aplicativo.
Nossa ferramenta permite que você analise a alteração de desempenho de qualquer parte do código, encontre os locais onde mais caiu. Ao mesmo tempo, ele não precisa ser ativado especificamente e aguardar a acumulação de estatísticas - ele está sempre ativo e coleta dados para uma determinada fração de todas as solicitações.
Neste artigo, falarei sobre os detalhes da implementação e os recursos do uso desta ferramenta.
Um pouco sobre o XHProf
Primeiro, algumas palavras sobre os recursos do próprio XHProf. Este é um criador de perfil para PHP escrito em C como uma extensão. Foi desenvolvido no Facebook e publicado em domínio público. Possui vários garfos (
uprofiler ,
Tideways ), totalmente compatíveis no nível do formato dos dados de saída.
XHProf define temporizadores em todas as chamadas de função / método. Seu uso envolve alguma sobrecarga. Mas eles não são tão grandes e permitem usá-lo na produção.
O resultado de XHProf é uma matriz de elementos no seguinte formato:
$data = [ 'parentMethodName==>childMethodName' => [ 'ct' => 1 'wt' => 8 'cpu' => 11 'mu' => 528 'pmu' => 0 ] ];
onde
parentMethodName
e
childMethodName
são os métodos pai e filho, respectivamente;
ct
- o número de chamadas no contexto da solicitação;
wt
- tempo de execução da solicitação (consiste no tempo gasto pelo processador e no tempo de espera pela E / S ou pela resposta de outro serviço);
cpu
- tempo gasto pelo processador no processamento da solicitação;
mu
- alteração no consumo de memória após uma chamada de método;
pmu
- alteração no consumo máximo de memória após uma chamada de método.
Algumas outras opções também são possíveis.
O XHProf também contém ferramentas para visualizar os resultados assim obtidos. Para cada operação de criação de perfil, obtemos uma tabela com um conjunto de parâmetros para cada método.
Por exemplo
resultado de classificação de bolhas <?php class ArrayGenerator { public function getRandomArray(int $count): array { $array = []; for ($i = 0; $i < $count; $i++) { $array[] = rand(0, 1000); } return $array; } } class BubbleSorter { public function sort(&$array): void { $len = count($array); for ($i = 0; $i < $len ; $i++) { for ($j = 0; $j < $len - $i - 1; $j++) { if ($array[$j] > $array[$j + 1]) { $this->swap($array[$j], $array[$j + 1]); } } } } private function swap(&$a, &$b): void { $tmp = $a; $a = $b; $b = $tmp; } public function isSorted(array $array): bool { $len = count($array); for ($i = 0; $i < $len - 1; $i++) { if ($array[$i] > $array[$i + 1]) { return false; } } return true; } } class ArrayPrinter { public function print(array $array, string $delimiter = ' '): void { echo implode($delimiter, $array) . PHP_EOL; } } xhprof_enable(); $n = 10; $arrayGenerator = new \ArrayGenerator(); $array = $arrayGenerator->getRandomArray($n); $sorter = new BubbleSorter(); if (!$sorter->isSorted($array)) { $sorter->sort($array); } $printer = new \ArrayPrinter(); $printer->print($array); $xhprof_data = xhprof_disable();

Você pode entrar em cada método para descobrir quais métodos utilizaram quantos recursos.
Você também pode ver o gráfico de chamadas destacando os métodos que mais consomem recursos:

XHProf é útil para analisar manualmente o desempenho de cada solicitação. Mas também é importante vermos o quadro geral. Você precisa entender como o desempenho mudou ao longo do tempo. Para isso, foi desenvolvida uma ferramenta que perfila as consultas no modo automático e permite analisá-las na interface da web.
Liveprof: agregue resultados e mantenha o histórico
Como obter o histórico de criação de perfil?
Primeiro, você precisa configurar o início automático do criador de perfil e salvar os resultados. O desempenho não é constante e varia de um lançamento para o outro. Para evitar a influência de tais flutuações, usamos os dados médios de várias consultas. Como resultado, obtemos resultados agregados para cada consulta, por exemplo, mínimo, máximo, média e percentil 95. Isso ajuda a encontrar coisas difíceis que podem não ser necessárias para cada solicitação.
Nossa ferramenta tem vantagens e algumas limitações.
O que o agregador pode fazer:
- Perfil automático de cada enésima solicitação.
- Agregação diária de perfis coletados.
- A capacidade de ver gráficos de alterações em cada parâmetro medido pelo criador de perfil. Por exemplo, wt, cpu, mu, pmu descritos acima.
- Veja a alteração no desempenho de qualquer método por um determinado intervalo.
- Gráfico de chama com base nos dados agregados mais recentes.
- Encontre consultas que chamam um método específico
Limitações:
- Como nossa ferramenta é agregada, não é possível descobrir o desempenho de uma consulta (por exemplo, a mais lenta) - obtemos a média dos resultados no último dia. Mas isso é suficiente para avaliar a dinâmica geral do desempenho. Se alguma solicitação caiu na velocidade de execução, o valor médio, o percentil 95 e o tempo máximo de execução serão alterados.
- Você não pode restaurar inequivocamente a pilha de chamadas completa, pois XHProf retorna apenas pares pai-filho exclusivos com a soma dos valores dos recursos gastos.
- Solicite um erro de tempo de execução relacionado à sobrecarga do XHProf. A diferença não é tão grande, mas deve ser levada em consideração ao medir o tempo de execução da consulta.
Como usar o profiler
- Primeiro, o criador de perfil precisa estar conectado ao site ou script. A maneira mais conveniente de usar a ferramenta é iniciar automaticamente o criador de perfil :
php composer.phar require badoo/liveprof # Run a script to configure database LIVE_PROFILER_CONNECTION_URL=mysql://db_user:db_password@db_mysql:3306/Profiler?charset=utf8 php vendor/badoo/liveprof/bin/install.php
Ele suporta versões do PHP a partir da 5.4, e seu uso é repleto de sobrecarga mínima, o que permite usá-lo em um ambiente de combate. A ferramenta detecta automaticamente a extensão do criador de perfil usada: XHProf , uprofiler ou Tideways . Na inicialização, você precisa especificar parâmetros para conectar-se ao banco de dados e às configurações de perfil.
Exemplo de uso no código com configurações padrão:
<?php include 'vendor/autoload.php'; \Badoo\LiveProfiler\LiveProfiler::getInstance()->start();
Os resultados da criação de perfil são salvos no banco de dados. Uma vez por dia, ocorre um processo de agregação. Para fazer isso, selecione todos os registros para uma solicitação específica por dia e calcule as funções agregadas para cada um dos parâmetros. As funções de agregação podem ser expandidas ou redefinidas.
Agora estão disponíveis os seguintes:
- pelo menos por dia;
- máximo por dia;
- média diária
- Percentil 95 do dia.
- O web client agregador é usado para configurar a agregação e visualizar os resultados. A maneira mais fácil de instalá-lo em um contêiner de docker:
git clone https:
- Antes do primeiro início, você precisa configurar os parâmetros de conexão com o banco de dados, uma lista de campos e funções agregadas usadas no arquivo de configuração src / config / services.yaml. Em seguida, execute o script de instalação:
docker-compose exec web bash install.sh
- É necessário registrar automaticamente scripts de agregação e limpeza de dados antigos em coroas:
- Para preencher com dados de teste, você pode executar o script:
docker-compose exec web php /app/bin/cli.php example:a-week-degradation
Descrição da interface
A interface da web está disponível em: 127.0.0.1:8000.
Por padrão, uma página com uma lista de consultas agregadas é aberta. Torna mais fácil encontrar uma consulta de interesse, classificar todas as consultas por qualquer um dos parâmetros e também agregar novamente uma consulta específica para ver os resultados mais recentes:

Uma página com uma lista de métodos e gráficos de alterações de desempenho é a mais usada ao trabalhar com a ferramenta. Ele permite que você percorra a pilha de chamadas, observe o consumo de cada parâmetro, bem como gráficos de alterações de desempenho por um determinado intervalo:
Uma página com uma lista completa dos métodos chamados permite encontrar rapidamente o método de interesse e ver os gráficos, indo para a página de gráficos:
A página com o gráfico de chama da última consulta agregada permite identificar visualmente as partes mais pesadas.O uso do XHProf impõe algumas limitações na precisão do resultado. Isso ocorre porque o criador de perfil não retorna uma árvore de chamadas completa, mas apenas os pares pai-filho. Além disso, se algum par de métodos foi chamado de diferentes locais do aplicativo, como resultado, obtemos a quantidade de tempo gasto. Para um gráfico de chama, você precisa ter uma árvore de chamadas completa. Ao restaurar essa árvore, os valores dos parâmetros são normalizados, levando em consideração o tempo gasto pelos pais.
Uma página com uma lista de métodos que se tornaram mais lentos durante o intervalo selecionado.Além disso, para cada método, você pode ver quais chamadas secundárias afetaram mais o desempenho. Por exemplo, na captura de tela abaixo, você pode ver que o método
ServiceApi::getAvailableServices()
começou a executar 116 ms mais lentamente. O motivo disso foi a adição de uma chamada ao
ServiceApi::getGifts()
(alteração de 56 ms) e um aumento no número de chamadas para o método
ServiceApi::getConfigForList()
de 1 para 5 (outros 50 ms):

Se não for conhecido antecipadamente qual consulta o desempenho mudou mais visivelmente, uma página com uma lista de métodos que se tornou mais lenta sem referência a uma consulta específica ajudará:
Uma página que pesquisa consultas que invocam um método específico.Permite comparar o tempo de execução em diferentes solicitações. Também é útil para encontrar código não utilizado:

Recursos de personalização
A ferramenta possui amplas oportunidades para personalização:
Conclusão
Espero que nossa ferramenta seja útil para outros desenvolvedores. Isso permitirá verificar a alteração de desempenho de qualquer parte do código sem o uso de temporizadores adicionais. Isso também facilitará o processo de otimização, pois agora você pode ver o que afetou a degradação do desempenho do aplicativo ao longo do tempo.
Está disponível no GitHub:
github.com/badoo/liveprof , a interface da web é
github.com/badoo/liveprof-ui .
A ferramenta está em desenvolvimento ativo e pode conter alguns erros. Espero que com a participação da comunidade, fique ainda melhor. Os planos incluem adicionar suporte a outros criadores de perfil além do XHProf, além de expandir a lista de bancos de dados suportados.
Envie-nos comentários e perguntas sobre o uso no
Telegram , bugs e solicitações pull - diretamente para o
GitHub . Agradecemos comentários e sugestões!
Agradecimentos especiais a
Gregory pela idéia e primeira implementação.