Como gerenciar riscos de escalonamento

A infraestrutura do Google é projetada para operar de maneira flexível em alta escala: a maioria das camadas pode se adaptar ao aumento das demandas de tráfego até chegar a uma escala de grandes proporções. Um padrão de design básico que torna isso possível consiste em camadas adaptativas: componentes de infraestrutura que realocam dinamicamente a carga com base nos padrões de tráfego. No entanto, essa adaptação leva tempo. Como o Cloud Tasks permite o envio de grandes volumes de tráfego, ele expõe os riscos de produção em situações em que a expansão do tráfego é mais rápida que a capacidade de adaptação da infraestrutura.

Visão geral

Este documento fornece diretrizes sobre as práticas recomendadas para manter o alto desempenho do Cloud Tasks em filas com muito tráfego. Uma fila de TPS elevado é uma fila em que são criadas ou despachadas 500 tarefas por segundo (TPS) ou mais. Um grupo de filas de alto TPS é um conjunto contíguo de filas, como [queue0001, queue0002,…, queue0099], que tem pelo menos 2000 tarefas criadas ou despachadas no total. O histórico de TPS de uma fila ou grupo de filas pode ser visto usando as métricas do Stackdriver, api/request_count para operações "CreateTask" e queue/task_attempt_count para tentativas de tarefas. As filas e os grupos de filas com tráfego elevado estão propensos a duas classes diferentes de falhas:

A sobrecarga da fila ocorre quando o tráfego de criação e despacho da tarefa para uma fila individual ou um grupo de filas aumenta mais rapidamente do que a infraestrutura pode se adaptar. Da mesma forma, a sobrecarga do destino ocorre quando a taxa em que as tarefas estão sendo despachadas causa picos de tráfego na infraestrutura de destino downstream. Em ambos os casos, recomendamos seguir um padrão de 500/50/5: ao fazer o escalonamento para mais de 500 TPS, aumentar o tráfego em não mais de 50% a cada 5 minutos. Neste documento, analisamos diferentes cenários que podem introduzir riscos de escalonamento e fornecemos exemplos de como aplicar esse padrão.

sobrecarga da fila

Filas ou grupos de filas podem ficar sobrecarregados sempre que o tráfego aumenta de repente. Como resultado, essas filas podem apresentar:

  • aumento da latência da criação de tarefas;
  • aumento da taxa de erros na criação de tarefas;
  • redução na taxa de despacho.

Para se proteger contra isso, recomendamos estabelecer controles em qualquer situação de aumento repentino na taxa de criação ou despacho de um grupo de filas ou de uma fila. Recomendamos no máximo 500 operações por segundo para uma fila ou um grupo de filas inativo, aumentando depois o tráfego em 50% a cada cinco minutos. Teoricamente, seguindo essa programação de intensificação do tráfego, é possível aumentar para até 740 mil operações por segundo após 90 minutos. Há várias circunstâncias em que isso pode ocorrer.

Por exemplo:

  • lançamento de novos recursos que fazem uso intenso do Cloud Tasks
  • movimentação do tráfego entre filas
  • reequilíbrio do tráfego em mais ou menos filas
  • execução de jobs em lote que injetam um grande número de tarefas

Nesses e em outros casos, siga o padrão 500/50/5.

Como usar a divisão de tráfego do App Engine

Se as tarefas forem criadas por um aplicativo do App Engine, será possível aproveitar a divisão de tráfego do App Engine (padrão/flexível) para reduzir o impacto do aumento de tráfego. Ao dividir o tráfego entre as versões (padrão/flexível), as solicitações que precisam ser gerenciadas por taxa podem ser ativadas ao longo do tempo para proteger a integridade da fila. Por exemplo, pense no caso de aumentar o tráfego para um grupo de filas recentemente expandido: deixe que [queue0000, queue0199] seja uma sequência de filas com TPS elevado que recebe um total de 100.000 criações de TPS no pico.

Deixe [queue0200, queue0399] ser uma sequência de novas filas. Após o deslocamento de todo o tráfego, o número de filas na sequência dobra e a nova faixa de filas recebe 50% do tráfego total da sequência.

Ao implantar a versão que aumenta o número de filas, aumente gradualmente o tráfego para a nova versão e, assim, para as novas filas, usando a divisão de tráfego:

  • Comece movendo 1% do tráfego para a nova versão. Por exemplo, 50% de 1% de 100.000 TPS produz 500 TPS para o conjunto de filas novas.
  • A cada 5 minutos, aumente em 50% o tráfego enviado para a nova versão, conforme detalhado na tabela a seguir:
Minutos desde o início da implantação % do tráfego total deslocado para a nova versão % do tráfego total para as novas filas % do tráfego total para as filas antigas
0 1.0 0,5 99,5
5 1,5 0,75 99,25
10 2,3 1,15 98,85
15 3,4 1,7 98,3
20 5,1 2,55 97,45
25 7,6 3,8 96,2
30 11,4 5,7 94,3
35 17,1 8,55 91,45
40 25,6 12,8 87,2
45 38,4 19,2 80,8
50 57,7 28,85 71,15
55 86,5 43,25 56,75
60 100 50 50

Picos de tráfego impulsionados pela versão

Ao lançar uma versão que aumenta significativamente o tráfego para uma fila ou um grupo de filas, a implantação gradual é, novamente, um mecanismo importante para suavizar os aumentos. Gradualmente, implante suas instâncias para que o lançamento inicial não exceda o total de 500 operações para as novas filas, aumentando em não mais de 50% a cada cinco minutos.

Novas filas ou grupos de filas com TPS elevado

Filas recém-criadas são especialmente vulneráveis. Os grupos de filas, como [queue0000, queue0001, …, queue0199], são tão sensíveis quanto filas individuais durante os estágios iniciais de implantação. Para essas filas, a implantação gradual é uma estratégia importante. Inicie serviços novos ou atualizados que criam filas ou grupos de filas com TPS elevado, em etapas em que a carga inicial seja inferior a 500 TPS e os aumentos de 50% ou menos sejam realizados com intervalo de cinco minutos ou mais.

Grupos de filas recém-expandidos

Ao aumentar a capacidade total de um grupo de filas, como na expansão de [queue0000-queue0199 a queue0000-queue0399], siga o padrão 500/50/5. É importante observar que, para os procedimentos de implantação, os novos grupos de filas não se comportam de maneira diferente das filas individuais. Aplique o padrão 500/50/5 ao grupo novo como um todo, não apenas a filas individuais dentro do grupo. Para essas expansões de grupos de filas, a implantação gradual é novamente uma estratégia importante. Se a fonte do seu tráfego for o App Engine, use a divisão de tráfego. Consulte Picos de tráfego impulsionados pela versão. Ao migrar seu serviço para adicionar tarefas ao maior número de filas, expanda gradualmente suas instâncias, de modo que o lançamento inicial não exceda um total de 500 operações para as novas filas, aumentando em mais de 50% a cada cinco minutos.

Expansão emergencial do grupo de filas

Às vezes, pode ser útil expandir um grupo de filas existente, como nos casos em que tarefas precisam ser adicionadas ao grupo de filas mais rapidamente do que o grupo é capaz de despachar. Se os nomes das novas filas estiverem espalhados uniformemente entre os nomes de filas existentes quando classificados lexicograficamente, o tráfego poderá ser enviado imediatamente para essas filas, desde que não haja mais que 50% de novas filas intercaladas e o tráfego para cada fila seja menor que 500 TPS. Esse método é uma alternativa ao uso de divisão de tráfego e lançamento gradual, conforme descrito nas seções acima.

Para conseguir este tipo de nomeação intercalada, anexe um sufixo às filas que terminam em números pares. Por exemplo, se você tiver 200 filas existentes [queue0000-queue0199] e quiser criar 100 novas, escolha [queue0000a, queue0002a, queue0004a, …, queue0198a] como os nomes das novas filas, em vez de [queue0200-queue0299].

Se precisar de um aumento adicional, você ainda pode intercalar até 50% mais filas a cada cinco minutos.

Enfileiramentos de tarefas em larga escala/lote

Quando um grande número de tarefas (milhões ou bilhões) precisa ser adicionado, um padrão de injeção dupla pode ser útil. Em vez de criar tarefas a partir de um único job, use uma fila injetora. Cada tarefa adicionada à fila injetora realiza um fan-out e adiciona 100 tarefas à fila ou ao grupo de filas desejado. A fila injetora pode ser acelerada ao longo do tempo, por exemplo: começar em 5 TPS, depois aumentar em 50% a cada 5 minutos.

Tarefas nomeadas

Quando você cria uma nova tarefa, o Cloud Tasks atribui a ela um nome exclusivo por padrão. Você pode atribuir seu próprio nome a uma tarefa usando o parâmetro name. No entanto, isso apresenta uma sobrecarga de desempenho significativa, resultando em maiores latências e taxas de erro potencialmente maiores associadas a tarefas nomeadas. Esses custos podem ser ampliados de maneira significativa se as tarefas forem nomeadas sequencialmente, como, por exemplo, carimbos de data/hora. Então, se você atribuir seus próprios nomes, recomendamos usar um prefixo bem distribuído para nomes de tarefas, como um hash do conteúdo. Consulte a documentação para mais detalhes sobre como nomear uma tarefa.

sobrecarga do destino

O Cloud Tasks pode sobrecarregar outros serviços que você está usando, como App Engine, Datastore e o uso da rede, se os despachos de uma fila aumentarem drasticamente em um curto período. Se um backlog de tarefas se acumulou, tirar essas filas da pausa tem o potencial de sobrecarregar esses serviços. A proteção recomendada é o mesmo padrão de 500/50/5 sugerido para sobrecarga de fila: se uma fila envia mais de 500 TPS, aumente o tráfego desencadeado por ela em não mais de 50% a cada cinco minutos. Use as métricas do Stackdriver para monitorar de maneira proativa o aumento de tráfego. Os alertas do Stackdriver podem ser usados para detectar situações potencialmente perigosas.

Como tirar filas com TPS elevado da pausa ou retomá-las

Quando uma fila ou uma série de filas é tirada da pausa ou retomada, as filas retomam os despachos. Se a fila tiver muitas tarefas, a taxa de despacho da fila recém-ativada poderá aumentar drasticamente de 0 TPS para a capacidade total da fila. Para acelerar, a fila de stagger recomeça ou controla as taxas de despacho da fila usando o maxDispatchesPerSecond do Cloud Tasks.

Tarefas agendadas em massa

Um grande número de tarefas, que estão programadas para despachar ao mesmo tempo, também pode introduzir um risco de sobrecarga do destino. Se você precisa iniciar um grande número de tarefas ao mesmo tempo, considere usar controles de taxa de fila para aumentar a taxa de despacho de maneira gradual ou ampliar explicitamente a capacidade do destino com antecedência.

Maior fan-out

Ao atualizar os serviços que são executados por meio do Cloud Tasks, aumentar o número de chamadas remotas pode criar riscos de produção. Por exemplo, digamos que as tarefas em uma fila de TPS alto chamem o manipulador /task-foo. Uma nova versão pode aumentar significativamente o custo de chamar /task-foo se, por exemplo, essa nova versão adicionar várias chamadas dispendiosas do Datastore ao manipulador. O resultado líquido dessa versão seria um aumento maciço no tráfego do Datastore, que está imediatamente relacionado às mudanças no tráfego do usuário. Use a implantação gradual ou a divisão de tráfego para gerenciar a aceleração.

Novas tentativas

É possível fazer uma nova tentativa de execução do seu código em caso de falha ao fazer chamadas da Cloud Tasks API. No entanto, quando uma proporção significativa de solicitações falha com erros do lado do servidor, uma alta taxa de novas tentativas pode sobrecarregar ainda mais suas filas e fazer com que elas se recuperem mais devagar. Por isso, recomendamos limitar o volume de tráfego de saída se o cliente detectar que uma quantidade significativa de solicitações está falhando no lado do servidor. Isso pode ser feito, por exemplo, com o algoritmo de limitação adaptável descrito no capítulo Lidando com sobrecarga do livro "Engenharia de Confiabilidade do Google" (em inglês). As bibliotecas de cliente gRPC do Google implementam uma variação desse algoritmo.