Medindo o desempenho com a sincronização do servidor

Publicados: 2022-03-10
Resumo rápido ↬ O cabeçalho Server Timing fornece uma maneira discreta e conveniente de comunicar os tempos de desempenho do servidor back-end para as ferramentas do desenvolvedor no navegador. Adicionar informações de tempo ao seu aplicativo permite monitorar o desempenho de back-end e front-end em um só lugar.

Ao realizar qualquer tipo de trabalho de otimização de desempenho, uma das primeiras coisas que aprendemos é que, antes de melhorar o desempenho, você deve primeiro medi-lo. Sem poder medir a velocidade com que algo está funcionando, não podemos dizer se as alterações feitas estão melhorando o desempenho, não surtindo efeito ou até piorando as coisas.

Muitos de nós estarão familiarizados com o trabalho em um problema de desempenho em algum nível. Isso pode ser algo tão simples quanto tentar descobrir por que o JavaScript em sua página não está funcionando em breve, ou por que as imagens estão demorando muito para aparecer no wifi ruim do hotel. A resposta para esse tipo de pergunta geralmente é encontrada em um lugar muito familiar: as ferramentas de desenvolvedor do seu navegador.

Ao longo dos anos, as ferramentas de desenvolvedor foram aprimoradas para nos ajudar a solucionar esses tipos de problemas de desempenho no front-end de nossos aplicativos. Os navegadores agora têm auditorias de desempenho integradas. Isso pode ajudar a rastrear problemas de front-end, mas essas auditorias podem mostrar outra fonte de lentidão que não podemos corrigir no navegador. Esse problema é o tempo de resposta do servidor lento.

“Tempo para o primeiro byte”

Há muito pouco que as otimizações do navegador possam fazer para melhorar uma página que é simplesmente lenta para construir no servidor. Esse custo é incorrido entre o navegador que faz a solicitação do arquivo e recebe a resposta. Estudar seu gráfico de cascata de rede nas ferramentas do desenvolvedor mostrará esse atraso na categoria "Aguardando (TTFB)". Este é o tempo que o navegador espera entre fazer a solicitação e receber a resposta.

Mais depois do salto! Continue lendo abaixo ↓

Em termos de desempenho, isso é conhecido como Tempo até o primeiro byte - a quantidade de tempo que leva antes que o servidor comece a enviar algo com o qual o navegador possa começar a trabalhar. Englobado nesse tempo de espera está tudo o que o servidor precisa fazer para construir a página. Para um site típico, isso pode envolver rotear a solicitação para a parte correta do aplicativo, autenticar a solicitação, fazer várias chamadas para sistemas de back-end, como bancos de dados e assim por diante. Pode envolver a execução de conteúdo por meio de sistemas de modelagem, fazer chamadas de API para serviços de terceiros e talvez até coisas como enviar e-mails ou redimensionar imagens. Qualquer trabalho que o servidor faça para concluir uma solicitação é esmagado nessa espera TTFB que o usuário experimenta em seu navegador.

O painel Rede no Chrome DevTools mostrando a inspeção de uma solicitação de página única
A inspeção de uma solicitação de documento mostra o tempo que o navegador gasta aguardando a resposta do servidor.

Então, como reduzimos esse tempo e começamos a entregar a página mais rapidamente ao usuário? Bem, essa é uma grande pergunta, e a resposta depende da sua aplicação. Esse é o trabalho de otimização de desempenho em si. O que precisamos fazer primeiro é medir o desempenho para que o benefício de qualquer mudança possa ser julgado.

O cabeçalho de tempo do servidor

O trabalho do Server Timing não é ajudá-lo a realmente cronometrar a atividade em seu servidor. Você precisará fazer o tempo usando qualquer conjunto de ferramentas que sua plataforma de back-end disponibilize para você. Em vez disso, o objetivo do Server Timing é especificar como essas medições podem ser comunicadas ao navegador.

A forma como isso é feito é muito simples, transparente para o usuário e tem um impacto mínimo no peso da sua página. As informações são enviadas como um conjunto simples de cabeçalhos de resposta HTTP.

 Server-Timing: db;dur=123, tmpl;dur=56

Este exemplo comunica dois pontos de tempo diferentes chamados db e tmpl . Estes não fazem parte da especificação - estes são os nomes que escolhemos, neste caso para representar alguns tempos de banco de dados e modelos, respectivamente.

A propriedade dur está informando o número de milissegundos que a operação levou para ser concluída. Se observarmos a solicitação na seção Rede das Ferramentas do desenvolvedor, podemos ver que os horários foram adicionados ao gráfico.

O painel Timings de uma solicitação de página no Chrome DevTools mostrando uma nova seção Server Timing.
Uma nova seção Server Timing é exibida, mostrando os horários definidos com o cabeçalho HTTP Server-Timing.

O cabeçalho Server-Timing pode ter várias métricas separadas por vírgulas:

 Server-Timing: metric, metric, metric

Cada métrica pode especificar três propriedades possíveis

  1. Um nome curto para a métrica (como db em nosso exemplo)
  2. Uma duração em milissegundos (expressa como dur=123 )
  3. Uma descrição (expressa como desc="My Description" )

Cada propriedade é separada com um ponto e vírgula como delimitador. Poderíamos adicionar descrições ao nosso exemplo assim:

 Server-Timing: db;dur=123;desc="Database", tmpl;dur=56;desc="Template processing"
O painel Tempos de uma solicitação de página no Chrome DevTools mostrando as descrições usadas para métricas de tempo do servidor.
Os nomes são substituídos por descrições quando fornecidos.

A única propriedade necessária é name . Tanto dur quanto desc são opcionais e podem ser usados ​​opcionalmente quando necessário. Por exemplo, se você precisar depurar um problema de tempo que estava acontecendo em um servidor ou data center e não em outro, pode ser útil adicionar essas informações à resposta sem um tempo associado.

 Server-Timing: datacenter;desc="East coast data center", db;dur=123;desc="Database", tmpl;dur=56;desc="Template processing”

Isso então apareceria junto com os horários.

O painel Timings de uma solicitação de página no Chrome DevTools mostrando um Server Timing sem tempo definido.
O valor "Centro de dados da costa leste" é mostrado, mesmo que não tenha horários.

Uma coisa que você pode notar é que as barras de tempo não aparecem em um padrão em cascata. Isso ocorre simplesmente porque o Server Timing não tenta comunicar a sequência de timings, apenas as próprias métricas brutas.

Implementando o tempo do servidor

A implementação exata em seu próprio aplicativo dependerá de sua circunstância específica, mas os princípios são os mesmos. Os passos serão sempre:

  1. Tempo algumas operações
  2. Reúna os resultados de tempo
  3. Saída do cabeçalho HTTP

Em pseudocódigo, a geração de resposta pode ser assim:

 startTimer('db') getInfoFromDatabase() stopTimer('db') startTimer('geo') geolocatePostalAddressWithAPI('10 Downing Street, London, UK') endTimer('geo') outputHeader('Server-Timing', getTimerOutput())

O básico da implementação de algo nesse sentido deve ser direto em qualquer linguagem. Uma implementação PHP muito simples pode usar a função microtime() para operações de temporização e pode parecer algo como o seguinte.

 class Timers { private $timers = []; public function startTimer($name, $description = null) { $this->timers[$name] = [ 'start' => microtime(true), 'desc' => $description, ]; } public function endTimer($name) { $this->timers[$name]['end'] = microtime(true); } public function getTimers() { $metrics = []; if (count($this->timers)) { foreach($this->timers as $name => $timer) { $timeTaken = ($timer['end'] - $timer['start']) * 1000; $output = sprintf('%s;dur=%f', $name, $timeTaken); if ($timer['desc'] != null) { $output .= sprintf(';desc="%s"', addslashes($timer['desc'])); } $metrics[] = $output; } } return implode($metrics, ', '); } }

Um script de teste o usaria como abaixo, aqui usando a função usleep() para criar artificialmente um atraso na execução do script para simular um processo que leva tempo para ser concluído.

 $Timers = new Timers(); $Timers->startTimer('db'); usleep('200000'); $Timers->endTimer('db'); $Timers->startTimer('tpl', 'Templating'); usleep('300000'); $Timers->endTimer('tpl'); $Timers->startTimer('geo', 'Geocoding'); usleep('400000'); $Timers->endTimer('geo'); header('Server-Timing: '.$Timers->getTimers());

A execução deste código gerou um cabeçalho que se parecia com isso:

 Server-Timing: db;dur=201.098919, tpl;dur=301.271915;desc="Templating", geo;dur=404.520988;desc="Geocoding"
O painel Timings de uma solicitação de página no Chrome DevTools mostrando os valores de teste exibidos corretamente.
Os Tempos do Servidor definidos no exemplo aparecem no painel Tempos com os atrasos configurados em nosso script de teste.

Implementações existentes

Considerando o quão útil é o Server Timing, existem relativamente poucas implementações que eu poderia encontrar. O pacote NPM de sincronização do servidor oferece uma maneira conveniente de usar a sincronização do servidor a partir de projetos do Node.

Se você usa um framework PHP baseado em middleware, tuupola/server-timing-middleware também fornece uma opção útil. Estou usando isso em produção no Notist há alguns meses e sempre deixo alguns horários básicos ativados se você quiser ver um exemplo na natureza.

Para suporte ao navegador, o melhor que vi está no Chrome DevTools, e foi isso que usei para as capturas de tela deste artigo.

Considerações

O próprio Server Timing adiciona sobrecarga mínima à resposta HTTP enviada de volta pela rede. O cabeçalho é muito mínimo e geralmente é seguro enviar sem se preocupar em direcionar apenas para usuários internos. Mesmo assim, vale a pena manter nomes e descrições curtos para não adicionar sobrecarga desnecessária.

Mais preocupante é o trabalho extra que você pode estar fazendo no servidor para cronometrar sua página ou aplicativo. A adição de tempo extra e registro em log pode ter um impacto no desempenho, portanto, vale a pena implementar uma maneira de ativar e desativar isso quando necessário.

Usar um cabeçalho Server Timing é uma ótima maneira de garantir que todas as informações de tempo do front-end e do back-end do seu aplicativo estejam acessíveis em um único local. Desde que seu aplicativo não seja muito complexo, pode ser fácil de implementar e você pode estar pronto e funcionando em um período de tempo muito curto.

Se você quiser ler mais sobre o tempo do servidor, tente o seguinte:

  • A especificação de tempo do servidor W3C
  • A página MDN no Server Timing tem exemplos e detalhes atualizados de suporte ao navegador
  • Um artigo interessante da equipe do BBC iPlayer sobre o uso do Server Timing.