Resolver problemas de latência elevada nos apps do App Engine

Em muitos casos, a latência elevada no aplicativo resulta em erros de servidor 5xx. Como a causa raiz do erro e dos picos de latência pode ser a mesma, aplique as seguintes estratégias para resolver problemas de latência:

  1. Definir o escopo do problema de latência
  2. Identificar a causa
  3. Resolver problemas

Definir o escopo do problema de latência

Para definir o escopo do problema, faça as seguintes perguntas:

  • Quais aplicativos, serviços e versões são afetados por esse problema?
  • Quais endpoints específicos do serviço são afetados por esse problema?
  • Isso afetou todos os clientes ou um subconjunto específico de clientes?
  • Qual é o horário de início e término do incidente? Considere especificar o fuso horário.
  • Quais são os erros específicos?
  • Qual é o delta de latência observado, que geralmente é especificado como um aumento em um percentil específico? Por exemplo, a latência aumentou em 2 segundos no 90º percentil.
  • Como você mediu a latência? Em particular, você mediu no cliente ou ele está visível no Cloud Logging ou nos dados de latência do Cloud Monitoring fornecidos pela infraestrutura de exibição do App Engine?
  • Quais são as dependências do serviço e alguma delas teve incidentes?
  • Você fez alterações recentes no código, na configuração ou na carga de trabalho que acionaram esse problema?

Um serviço pode ter o próprio monitoramento e geração de registros personalizados que podem ser usados para restringir ainda mais o escopo do problema. Definir o escopo do problema orientará você na causa raiz provável e determinará as próximas etapas de solução de problemas.

Identificar a causa

Determine qual componente do caminho de solicitação tem mais probabilidade de causar a latência ou os erros. Os principais componentes no caminho da solicitação são os seguintes:

Cliente --> Internet --> Google Front End (GFE) --> Infraestrutura de exibição do App Engine --> Instância do serviço

Se as informações anteriores não apontarem para a origem da falha, aplique as seguintes estratégias ao analisar a integridade e o desempenho da instância do serviço:

  1. Monitore os registros de solicitação do App Engine. Se você encontrar erros de código de status HTTP ou latência elevada nesses registros, o problema provavelmente está na instância que executa seu serviço.

  2. Se o número de instâncias de serviço não for escalonado para corresponder aos níveis de tráfego, elas poderão ficar sobrecarregadas, resultando em erros e latência elevados.

  3. Se houver erros ou latência elevada no Cloud Monitoring, o problema pode estar no upstream do balanceador de carga, que registra as métricas do App Engine. Na maioria dos casos, isso indica um problema nas instâncias do serviço.

  4. Se você notar erros ou latência elevada nas métricas de monitoramento, mas não nos registros de solicitação, isso indica uma falha no balanceamento de carga ou uma falha grave na instância que impede o balanceador de carga de rotear solicitações. Para diferenciar esses casos, analise os registros de solicitações antes do início do incidente. Se os registros de solicitação mostrarem uma latência crescente antes da falha, as instâncias do aplicativo começaram a falhar antes que o balanceador de carga interrompesse o roteamento de solicitações para elas.

Resolver problemas

Esta seção descreve estratégias de solução de problemas de latência elevada dos seguintes componentes no caminho da solicitação:

  1. Internet
  2. Google Front End (GFE)
  3. Infraestrutura de exibição do App Engine
  4. Instância do aplicativo
  5. Dependências do aplicativo

Internet

O aplicativo pode ter problemas de latência devido à conectividade ruim ou à largura de banda menor.

Conexão de Internet ruim

Para determinar se o problema é a conectividade de Internet, execute o seguinte comando no cliente:

$ curl -s -o /dev/null -w '%{time_connect}\n' <hostname>

O valor de time_connect representa a latência da conexão do cliente com o Google Front End mais próximo. Para conexões lentas, resolva o problema usando traceroute para determinar qual salto na rede causa o atraso.

Executar testes de clientes em diferentes localizações geográficas. O App Engine encaminha automaticamente as solicitações para o data center do Google mais próximo, que varia de acordo com a localização do cliente.

Baixa largura de banda

O aplicativo pode estar respondendo rapidamente, mas os gargalos de rede atrasam a infraestrutura de exibição do App Engine de enviar pacotes pela rede rapidamente, o que desacelera as respostas.

Google Front End (GFE)

Seu aplicativo pode ter problemas de latência devido a roteamento incorreto, solicitações paralelas enviadas de clientes HTTP/2 ou encerramento de conexões SSL.

Mapear um IP do cliente para uma região geográfica

O Google resolve o nome do host do aplicativo do App Engine para o GFE mais próximo do cliente com base no endereço IP do cliente usado na pesquisa DNS. Se o resolvedor de DNS do cliente não estiver usando o protocolo EDNS0, o Google poderá não rotear as solicitações do cliente para o GFE mais próximo.

Bloqueio de linha do cabeçalho HTTP/2

Os clientes HTTP/2 que enviam várias solicitações em paralelo podem ter latência elevada devido ao bloqueio de cabeça de linha no GFE. Para resolver esse problema, os clientes precisam usar o protocolo QUIC.

Encerramento de SSL em domínios personalizados

O GFE pode encerrar a conexão SSL. Se você estiver usando um domínio personalizado em vez de um domínio appspot.com, o encerramento de SSL vai exigir um salto extra. Isso pode adicionar latência em aplicativos executados em algumas regiões. Para mais informações, consulte Como mapear domínios personalizados.

Infraestrutura de exibição do App Engine

Talvez você note uma latência elevada no seu aplicativo devido a incidentes em todo o serviço ou autoescalonamento.

Incidentes no serviço

O Google publica detalhes de um problema grave em todo o serviço no painel Integridade do serviço. No entanto, o Google faz lançamentos gradualmente, então é improvável que um incidente em todo o serviço afete todas as instâncias de uma só vez.

Escalonamento automático

A latência elevada ou erros podem resultar dos seguintes cenários de escalonamento automático:

  • Escalonamento vertical muito rápido: o escalonamento automático do App Engine pode não escalonar suas instâncias tão rápido quanto o tráfego aumenta, levando a sobrecarga temporária. Normalmente, a sobrecarga ocorre quando o tráfego é gerado por um programa de computador em vez de usuários finais. Para resolver esse problema, limite o sistema que gera o tráfego.

  • Picos no tráfego: picos no tráfego podem causar latência elevada nos casos em que um serviço com escalonamento automático precisa escalonar verticalmente mais rapidamente do que é possível sem afetar a latência. O tráfego de usuários finais geralmente não gera picos de tráfego frequentes. Se você notar picos de tráfego, investigue a causa. Se um sistema em lote estiver em execução em intervalos, talvez seja possível suavizar o tráfego ou usar diferentes configurações de escalonamento.

  • Configurações do escalonador automático: o escalonador automático pode ser configurado com base nas características de escalonamento do serviço. Os parâmetros de escalonamento podem se tornar não ideais nos seguintes cenários:

    • As configurações de escalonamento do ambiente padrão do App Engine podem causar latência se forem definidas de forma muito ousada. Se você encontrar respostas do servidor com o código de status 500 e a mensagem "A solicitação foi abortada após esperar muito tempo para tentar atender sua solicitação" nos registros, significa que a solicitação expirou na fila pendente enquanto aguardava uma instância ociosa.

    • Talvez você veja um aumento do tempo pendente com o escalonamento manual, mesmo quando provisionar instâncias suficientes. Recomendamos que você não use o escalonamento manual se o aplicativo atender ao tráfego do usuário final. O escalonamento manual é melhor para cargas de trabalho como filas de tarefas.

    • A escalação básica minimiza os custos à custa da latência. Recomendamos que você não use o dimensionamento básico para serviços sensíveis à latência.

    • A configuração de escalonamento padrão do App Engine oferece latência ideal para a maioria dos serviços. Se ainda houver solicitações com tempo pendente alto, especifique um número mínimo de instâncias. Se você ajustar as configurações de escalonamento para reduzir custos minimizando as instâncias inativas, correrá o risco de picos de latência se a carga aumentar repentinamente.

Recomendamos que você compare o desempenho com as configurações de escalonamento padrão e execute uma nova comparação após cada alteração nessas configurações.

Implantações

A latência elevada logo após uma implantação indica que você não aumentou suficientemente antes de migrar o tráfego. Instâncias mais recentes podem não ter aquecido caches locais e, portanto, podem ser exibidas mais lentamente do que instâncias mais antigas.

Para evitar picos de latência, não implante um serviço do App Engine usando o mesmo nome de versão de uma versão atual do serviço. Se você reutilizar um nome de versão existente, não será possível migrar lentamente o tráfego para a nova versão. As solicitações podem ser mais lentas porque o App Engine reinicia cada instância em um curto período. Também será preciso reimplantar se você quiser reverter para a versão anterior.

Instância do aplicativo

Esta seção descreve as estratégias comuns que podem ser aplicadas às instâncias do aplicativo e ao código-fonte para otimizar o desempenho e reduzir a latência.

Código do aplicativo

Os problemas no código do aplicativo podem ser difíceis de depurar, principalmente se forem intermitentes ou não forem reproduzíveis.

Para resolver problemas, faça o seguinte:

  • Para diagnosticar seus problemas, recomendamos instrumentar seu aplicativo usando geração de registros, monitoramento e rastreamento. Também é possível usar o Cloud Profiler.

  • Tente reproduzir o problema em um ambiente de desenvolvimento local, o que pode permitir a execução de ferramentas de depuração específicas da linguagem que talvez não possam ser executadas no App Engine.

  • Para entender melhor como seu app falha e quais gargalos ocorrem, carregue o aplicativo de teste até a falha. Defina uma contagem máxima de instâncias e aumente a carga gradualmente até o aplicativo falhar.

  • Se o problema de latência estiver relacionado à implantação de uma nova versão do código do aplicativo, reverter para determinar se a nova versão causou o incidente. No entanto, se você implantar continuamente, as implantações frequentes dificultam a determinação se a implantação causou o incidente com base no horário de início.

  • O aplicativo pode armazenar configurações no Datastore ou em outro lugar. Crie uma linha do tempo de mudanças de configuração para determinar se alguma delas se alinha com o início de latência elevada.

Mudança de carga de trabalho

Uma alteração de carga de trabalho pode causar latência elevada. Algumas métricas de monitoramento que indicam mudanças na carga de trabalho incluem qps, uso da API e latência. Verifique também se há mudanças nos tamanhos de solicitação e resposta.

Pressão da memória

Se o monitoramento mostrar um padrão de serrilhado no uso da memória ou uma queda no uso da memória que se relaciona com as implantações, um vazamento de memória pode ser a causa de problemas de desempenho. Um vazamento de memória também pode causar coleta de lixo frequente, levando a uma latência maior. Se você não conseguir rastrear esse problema para um problema no código, tente provisionar instâncias maiores com mais memória.

Vazamento de recursos

Se uma instância do seu aplicativo mostrar uma latência crescente que se correlaciona à idade da instância, é possível que haja um vazamento de recursos que causa problemas de desempenho. A latência diminui após a conclusão de uma implantação. Por exemplo, uma estrutura de dados que fica mais lenta ao longo do tempo devido ao maior uso da CPU pode diminuir a velocidade da carga de trabalho vinculada à CPU.

Otimização de código

Para reduzir a latência no App Engine, otimize o código usando estes métodos:

  • Trabalho off-line: use o Cloud Tasks para evitar que as solicitações do usuário bloqueiem o aplicativo aguardando a conclusão do trabalho, como enviar e-mails.

  • Chamadas de API assíncronas: verifique se o código não está bloqueado aguardando a conclusão de uma chamada de API.

  • Chamadas de API em lote: a versão em lote de chamadas de API geralmente é mais rápida do que enviar chamadas individuais.

  • Desnormalizar modelos de dados: reduza a latência das chamadas feitas para a camada de persistência de dados desnormalizando os modelos de dados.

Dependências do aplicativo

Monitore as dependências do aplicativo para detectar se os picos de latência estão relacionados a uma falha de dependência.

Uma mudança na carga de trabalho e um aumento no tráfego podem aumentar a latência de uma dependência.

Dependência sem escalonamento

Se a dependência do seu aplicativo não for escalonada à medida que o número de instâncias do App Engine aumentar, ela poderá ficar sobrecarregada quando o tráfego aumentar. Um exemplo de dependência que pode não ser escalonada é um banco de dados SQL. Um número maior de instâncias de aplicativos resulta em um número maior de conexões de banco de dados, o que pode causar uma falha em cascata impedindo que o banco de dados seja inicializado. Para resolver esse problema, faça o seguinte:

  1. Implantar uma nova versão padrão que não se conecte ao banco de dados.
  2. Encerre a versão padrão anterior.
  3. Implantar uma nova versão não padrão que se conecte ao banco de dados.
  4. Migre lentamente o tráfego para a nova versão.

Como medida preventiva, projete seu aplicativo para soltar solicitações para a dependência usando a limitação adaptativa.

Falha na camada de cache

Para acelerar as solicitações, use várias camadas de armazenamento em cache, como o armazenamento em cache de borda, o Memcache e a memória na instância. Uma falha em uma dessas camadas de armazenamento em cache pode causar um aumento repentino na latência. Por exemplo, uma limpeza do Memcache pode fazer com que mais solicitações sejam enviadas para um Datastore mais lento.