← Voltar ao blog

Magento 2 Blackfire: profiling de páginas, CLI e testes

Rodrigo Biazzi

Ferramentas de APM dizem qual request do Magento 2 está lenta. Um profiler diz por quê. O Blackfire registra cada chamada de função em uma request ou comando CLI e mostra para onde vão o tempo e a memória, o que o torna a ferramenta certa quando você já sabe qual página, chamada de API ou cron job investigar. Este artigo mostra como configurar o Blackfire no Magento Open Source e no Adobe Commerce 2.4.8, como fazer profiling de páginas e comandos CLI e como ler os resultados sem se perder em um call graph com milhares de nós.

Como o Blackfire funciona

O Blackfire tem três partes:

  • O probe, uma extensão PHP. Ele fica parado nas requests normais e só instrumenta uma request quando ela carrega uma query assinada do Blackfire. Por isso ele pode ficar instalado em staging, e até em produção, sem deixar o tráfego regular mais lento.
  • O agent, um daemon no servidor que recebe os dados de profile do probe e os envia ao Blackfire.
  • O client, que pode ser a ferramenta CLI blackfire ou a extensão do navegador, que dispara os profiles e assina as requests.

Instale o agent e o probe a partir do repositório de pacotes do Blackfire, configure com suas credenciais de servidor e de client e recarregue o PHP-FPM. Depois confirme que o probe está carregado tanto no FPM quanto no CLI:

php -m | grep -i blackfire
blackfire version

Desative o Xdebug em qualquer ambiente onde você faz profiling. Ele se engancha nos mesmos pontos internos e distorce os tempos, às vezes bastante.

Faça profiling em production mode

Faça profiling em uma loja que se comporte como produção. No developer mode o Magento gera código na hora, compila LESS no caminho do navegador, não assina arquivos estáticos e escreve mais logs. Um profile tirado em developer mode mostra esses custos e esconde os reais.

Antes de fazer o profiling:

  • Mude para production mode, ou pelo menos garanta que o DI esteja compilado e o conteúdo estático publicado.
  • Use um banco realista. Uma cópia de staging com cinco produtos não vai reproduzir uma página de categoria lenta com 3.000.
  • Decida se você quer cache frio ou quente e seja consistente.

A questão do cache importa. Um profile com todos os caches quentes mostra o custo de uma request normal. Um profile logo depois de um cache clean mostra a geração de config e layout, que é outro problema. Os dois são úteis, mas compare coisas equivalentes.

Profiling de uma página

O jeito mais simples é a extensão do navegador. Abra a página, clique no ícone do Blackfire e ele recarrega a página várias vezes e agrega os resultados. Para páginas atrás de login, como a conta do cliente ou o carrinho, a extensão é a escolha mais fácil porque usa a sua sessão.

Pela linha de comando, blackfire curl funciona para páginas públicas e chamadas de API:

blackfire curl https://staging.example.com/women/tops.html

blackfire --samples 10 curl https://staging.example.com/women/tops.html

Se houver Varnish ou uma CDN na frente do site, uma página em cache nunca chega ao PHP e o Blackfire não tem nada para analisar. Ou você faz o profiling direto no backend, ou adiciona uma query string que fure o cache, ou roda o profile temporariamente contra um host que pule o Varnish. O full page cache é o caminho de código mais rápido que você tem, e não é isso que você está investigando aqui.

Profiling de comandos CLI

Muitos problemas de performance do Magento estão no CLI: indexers, cron jobs, importações e queue consumers. O Blackfire consegue envolver qualquer comando PHP:

blackfire run php bin/magento indexer:reindex catalog_category_product

blackfire run php bin/magento cron:run --group=default

Para um cron job específico, muitas vezes é mais fácil chamar a classe do job diretamente por um pequeno comando CLI seu, de modo que o profile contenha só aquele job. O guia de comando CLI customizado mostra como montar. Para um consumer de longa duração, faça o profiling de uma execução que processe um número limitado de mensagens, por exemplo com a opção --max-messages do queue:consumers:start.

Lendo o profile

Um profile do Magento pode conter dezenas de milhares de chamadas de função. Comece pelo resumo e vá descendo.

Números de nível superior

O cabeçalho do profile mostra wall time, I/O wait, tempo de CPU, memória e rede. Wall time menos tempo de CPU é, grosso modo, o tempo gasto esperando. Uma request com 2 segundos de wall time e 300 ms de CPU está esperando alguma coisa: SQL, Redis, uma chamada HTTP, um lock. Uma request em que a CPU fica perto do wall time está fazendo trabalho demais em PHP.

A lista de funções

Ordene primeiro por tempo exclusivo. Tempo exclusivo é o tempo gasto dentro da própria função, sem contar as filhas. As primeiras entradas costumam ser de baixo nível: PDOStatement::execute, curl_exec, chamadas ao Redis ou funções de array. Isso diz o tipo de problema.

Depois ordene por tempo inclusivo e procure a função do Magento ou de vendor mais alta que não seja infraestrutura do framework. Algo como o _toHtml de um block, um plugin around em getPrice ou um observer em catalog_product_load_after. Geralmente essa é a função a corrigir.

O call graph

O call graph destaca o hot path, a cadeia de chamadas em que está a maior parte do tempo. Siga por ele desde o topo. Preste atenção na contagem de chamadas nas arestas. Um método chamado 4.000 vezes em uma página com 40 produtos significa que algo roda 100 vezes por produto, muitas vezes um load de collection ou uma chamada de repository dentro de um loop.

Abas de SQL e HTTP

A visão de SQL lista cada query com contagem de chamadas e tempo. No Magento, o padrão útil de procurar é a mesma forma de query com IDs diferentes, repetida dezenas ou centenas de vezes. Isso é um N+1, e a correção é carregar os dados uma vez para todos os itens, normalmente adicionando-os à collection ou usando um batch loader.

A visão de HTTP mostra as requests de saída. Qualquer chamada externa durante a renderização de uma página da storefront merece uma olhada séria.

Achados comuns em profiles do Magento

  • Plugins em métodos quentes. Um plugin em um método chamado milhares de vezes por página, como preço de produto ou getters de atributo, soma rápido. O overhead do interceptor é pequeno por chamada, mas o código do próprio plugin geralmente não é.
  • Collections sem limite. Um block carrega uma collection inteira só para contar ou para escolher um item.
  • Leitura de config em loops. ScopeConfigInterface::getValue é cacheado, mas chamá-lo milhares de vezes ainda custa. Leia uma vez e guarde o valor.
  • Criação de objetos pelo object manager em loops apertados, principalmente para models pesados.
  • Blocks sem cache que reconstroem HTML caro a cada request, mesmo que o conteúdo mude uma vez por dia.

O guia de plugins, observers e preferences explica como cada ponto de extensão afeta a performance.

Comparando profiles

O Blackfire consegue comparar dois profiles e mostrar o que mudou em tempo, memória e contagem de chamadas. Essa é a forma correta de validar uma correção. Faça o profile antes da mudança, aplique a correção, faça o profile de novo e compare. A comparação mostra se a correção ajudou e se outra coisa piorou. É muito mais confiável do que recarregar a página e olhar a aba de rede.

Testes de performance com .blackfire.yaml

O Blackfire também suporta asserções guardadas no projeto. Um arquivo .blackfire.yaml na raiz do projeto define testes que rodam em todo profile que case com um caminho:

tests:
  "Category pages stay lean":
    path: "/.*\\.html"
    assertions:
      - "metrics.sql.queries.count < 200"
      - "main.wall_time < 1s"

  "No outgoing HTTP calls on storefront pages":
    path: "/.*"
    assertions:
      - "metrics.http.requests.count == 0"

Os números deste exemplo são placeholders. Defina os limites a partir de profiles da sua própria loja e vá apertando conforme você corrige as coisas. Usado assim, o Blackfire vira uma proteção contra regressões, e não só uma ferramenta de debug. Consulte a documentação do Blackfire para os nomes de métricas disponíveis no seu plano.

Blackfire e New Relic juntos

As duas ferramentas respondem perguntas diferentes. O New Relic roda em toda request e mostra tendências, então você sabe qual transaction olhar. O Blackfire faz o profile de uma única request em profundidade, então você sabe o que mudar. Um ciclo típico é achar a transaction no New Relic, reproduzir em staging, fazer o profile com o Blackfire, corrigir e comparar.

FAQ

O probe do Blackfire deixa o Magento mais lento quando não estou fazendo profiling?

O probe só instrumenta requests que carregam uma query assinada do Blackfire. As requests normais rodam sem profiling, então o overhead no tráfego regular é pequeno.

Por que o Blackfire não mostra nada na minha página de categoria?

Provavelmente a página foi servida pelo Varnish ou por uma CDN e nunca chegou ao PHP. Faça o profiling direto no backend ou fure o full page cache na request analisada.

Devo fazer profiling do Magento em developer mode?

Não. O developer mode adiciona geração de código e outros custos que não existem em produção. Faça o profiling em production mode com DI compilado e conteúdo estático publicado.

Posso fazer profiling de comandos bin/magento com o Blackfire?

Pode. Coloque blackfire run na frente do comando, por exemplo blackfire run php bin/magento indexer:reindex seguido do código do indexer.

Atendo como freelancer em Magento e Adobe Commerce, incluindo profiling e correção de páginas lentas. Se precisar de ajuda com isso, fale comigo.

Artigos relacionados