Controle o consumo de recursos usados por uma instância de um aplicativo, um locatário individual ou todo o serviço. Isso pode permitir que o sistema continue a funcionar e atender aos contratos de nível de serviço mesmo quando um aumento na demanda coloca uma carga extrema nos recursos.
Contexto e problema
A carga em um aplicativo de nuvem normalmente varia ao longo do tempo com base no número de usuários ativos ou nos tipos de atividades que eles executam. Por exemplo, provavelmente haverá mais usuários ativos durante o horário comercial ou o sistema poderá precisar executar uma análise computacionalmente dispendiosa no final de cada mês. Também pode haver picos repentinos e inesperados na atividade. Se os requisitos de processamento do sistema excederem a capacidade dos recursos disponíveis, ele sofrerá de desempenho ruim e poderá, inclusive, falhar. Se o sistema precisar atender a um nível combinado de serviço, essa falha poderá ser inaceitável.
Há muitas estratégias disponíveis para tratar a carga variável na nuvem, dependendo dos objetivos comerciais do aplicativo. Uma estratégia é usar o dimensionamento automático para combinar os recursos provisionados com as necessidades do usuário em qualquer dado momento. Isso tem o potencial de atender consistentemente à demanda do usuário, ao mesmo tempo otimizando os custos em execução. No entanto, embora o dimensionamento automático possa disparar o provisionamento de mais recursos, essa configuração não é imediata. Se a demanda crescer rapidamente, poderá haver um período com déficit de recurso.
Solução
Uma estratégia alternativa para dimensionamento automático é permitir que os aplicativos usem recursos até um limite e então limitá-los quando esse limite for atingido. O sistema deve monitorar como ele está usando recursos de modo que, quando o uso exceder o limite, ele possa acelerar as solicitações de um ou mais usuários. Isso permite que o sistema continue a funcionar e atenda a quaisquer SLAs (contratos de nível de serviço) em vigor. Para obter mais informações sobre como monitorar o uso de recursos, consulte Orientação sobre instrumentação e telemetria.
O sistema pode implementar várias estratégias de limitação, incluindo:
Rejeitar solicitações de um usuário individual que já tenha acessado APIs do sistema mais de n vezes por segundo durante um determinado período. Isso requer que o sistema meça o uso de recursos para cada locatário ou usuário que esteja executando um aplicativo. Para obter mais informações, consulte Orientação de medição de serviço.
Desabilitar ou comprometer a funcionalidade de serviços não essenciais selecionados de modo que os serviços essenciais possam ser executados sem impedimentos com recursos suficientes. Por exemplo, se o aplicativo estiver transmitindo por streaming saída de vídeo, ele poderá mudar para uma resolução mais baixa.
Usando nivelamento para suavizar o volume de atividade (essa abordagem é abordada em mais detalhes por Padrão de nivelamento de carga baseado em fila). Em um ambiente multilocatário, essa abordagem reduz o desempenho de cada locatário. Se o sistema precisar dar suporte a uma combinação de locatários com diferentes SLAs, o trabalho para locatários de alto valor poderá ser executado imediatamente. Solicitações para outros locatários poderão ser retidas e manipuladas quando a lista de pendências diminuir. O padrão Fila de Prioridade pode ser usado para ajudar a implementar essa abordagem, assim como a exposição de diferentes pontos de extremidade para os diferentes níveis/prioridades de serviço.
Adiar de operações sendo executadas em nome de locatários ou de aplicativos de menor prioridade. Essas operações podem ser suspensas ou limitadas, sendo gerada uma exceção para informar o locatário de que o sistema está ocupado e a operação deverá ser repetida mais tarde.
Você deve ter cuidado ao integrar com alguns serviços de terceiros que podem ficar indisponíveis ou retornar erros. Reduza o número de solicitações simultâneas sendo processadas para que os logs não sejam preenchidos desnecessariamente com erros. Você também evita os custos associados a tentar desnecessariamente o processamento de solicitações que falhariam por causa desse serviço de terceiros. Em seguida, quando as solicitações forem processadas com êxito, volte ao processamento normal de solicitações sem limitação. Uma biblioteca que implementa essa funcionalidade é a NServiceBus.
A figura mostra um gráfico de área para o uso de recursos (uma combinação de memória, CPU, largura de banda e outros fatores) em relação ao tempo para aplicativos que estão usando três recursos. Um recurso é uma área de funcionalidade, como um componente que executa um conjunto específico de tarefas, um trecho de código que executa um cálculo complexo ou um elemento que fornece um serviço como um cache na memória. Esses recursos são rotulados como A, B e C.
A área imediatamente abaixo da linha para um recurso indica os recursos usados por aplicativos quando eles invocam esse recurso. Por exemplo, a área abaixo da linha para o Recurso A mostra os recursos usados por aplicativos que estão usando o Recurso A e a área entre as linhas para o Recurso A e o Recurso B indica os recursos usados por aplicativos que estão invocando o Recurso B. Agregar as áreas para cada recurso mostra o uso total de recursos do sistema.
A figura anterior mostra os efeitos de adiar as operações. Logo antes do horário T1, o total de recursos alocados para todos os aplicativos que usam esses recursos atinge um limite (o limite de uso de recurso). Neste ponto, os aplicativos estão em risco de esgotar os recursos disponíveis. Nesse sistema, o Recurso B é menos crítico que o Recurso A ou o Recurso C, assim, ele é temporariamente desabilitado e os recursos que ele estava usando são liberados. Entre os tempos T1 e T2, os aplicativos que usam o Recurso A e o Recurso C continuam em execução como normal. Por fim, o uso de recursos desses dois recursos diminui até um ponto em que, no tempo T2, há capacidade suficiente para habilitar o Recurso B novamente.
As abordagens de dimensionamento automático e a limitação também podem ser combinadas para ajudar a manter os aplicativos responsivo e nos SLAs. Se há expectativa de que a demanda permaneça alta, a limitação fornecerá uma solução temporária enquanto o sistema escala horizontalmente. Neste ponto, a funcionalidade completa do sistema pode ser restaurada.
A figura a seguir mostra um gráfico de área do uso geral de recursos por todos os aplicativos que estão em execução em um sistema em relação ao tempo e ilustra como a limitação pode ser combinada com o dimensionamento automático.
No tempo T1, o limite especificando um limite flexível de utilização de recursos é atingido. Neste ponto, o sistema pode escalar horizontalmente. No entanto, se os recursos novos não ficarem disponíveis rápido o suficiente, os recursos existentes poderão ser esgotados e o sistema poderá falhar. Para evitar que isso ocorra, o sistema será temporariamente limitado, conforme descrito anteriormente. Quando o dimensionamento automático for concluído e os recursos extras estiverem disponíveis, a limitação poderá ser reduzida.
Problemas e considerações
Os seguintes pontos devem ser considerados ao decidir como implementar esse padrão:
A limitação de um aplicativo e a estratégia a ser usada, é uma decisão de arquitetura que afeta todo o projeto de um sistema. A limitação deve ser considerada no início do processo de design do aplicativo, porque não é fácil adicioná-la depois que um sistema tiver sido implementado.
A limitação deve ser executada rapidamente. O sistema deve ser capaz de detectar um aumento na atividade e reagir de acordo. O sistema também deve ser capaz de reverter para o estado original rapidamente depois que a carga diminuir. Isso requer que os dados de desempenho apropriados sejam capturados e monitorados continuamente.
Se um serviço precisar negar uma solicitação de usuário temporariamente, ele deverá retornar um código de erro específico, como 429 (“Excesso de solicitações”) e 503 (“Servidor muito ocupado”) para que o aplicativo cliente possa entender que o motivo da recusa em atender a uma solicitação é devido à limitação.
- HTTP 429 indica que o aplicativo de chamada enviou muitas solicitações em um intervalo de tempo e excedeu um limite predeterminado.
- HTTP 503 indica que o serviço não está pronto para lidar com a solicitação. A causa comum é que o serviço possa estar enfrentando mais picos de carga temporários do que o esperado.
O aplicativo cliente pode aguardar um período antes de tentar novamente a solicitação. Um cabeçalho HTTP Retry-After
deve ser incluído para apoiar o cliente na escolha da estratégia de repetição.
A limitação pode ser usada como uma medida temporária enquanto o sistema é dimensionado automaticamente. Em alguns casos, é melhor apenas limitar, em vez de dimensionar, se um aumento na atividade for repentino e possivelmente não dure muito, pois o dimensionamento pode aumentar consideravelmente os custos de execução.
Se a limitação estiver sendo usada como uma medida temporária enquanto um sistema é dimensionado automaticamente e, se as demandas de recursos aumentarem muito rapidamente, o sistema poderá não conseguir continuar funcionando, mesmo ao operar em um modo limitado. Se isso não for aceitável, considere a possibilidade de manter maiores reservas de capacidade e configurar um dimensionamento automático mais agressivo.
Normalize os custos de recursos para diferentes operações, pois eles geralmente não têm custos de execução iguais. Por exemplo, os limites de limitação podem ser menores para operações de leitura e maiores para operações de gravação. Não considerar o custo de uma operação pode resultar no esgotamento da capacidade e na exposição de um potencial vetor de ataque.
A alteração da configuração dinâmica do comportamento de limitação em tempo de execução é desejável. Se um sistema enfrentar uma carga anormal que a configuração aplicada não conseguir lidar, os limites de limitação precisarão aumentar ou diminuir para estabilizar o sistema e acompanhar o tráfego atual. Implantações caras, arriscadas e lentas não são desejáveis neste momento. Usando o padrão de Repositório de Configuração Externa, a configuração de limitação é externalizada e pode ser alterada e aplicada sem implantações.
Quando usar esse padrão
Use este padrão:
Para garantir que um sistema continue a cumprir os contratos de nível de serviço.
Para impedir que um único locatário monopolize os recursos fornecidos por um aplicativo.
Para lidar com estouros de atividade.
Para ajudar a otimizar os custos de um sistema, limitando os níveis máximos de recursos necessários para mantê-lo funcionando.
Design de carga de trabalho
Um arquiteto deve avaliar como o padrão Limitação pode ser usado no design das suas cargas de trabalho para abordar os objetivos e os princípios discutidos nos pilares do Azure Well-Architected Framework. Por exemplo:
Pilar | Como esse padrão apoia os objetivos do pilar |
---|---|
As decisões de design de confiabilidade ajudam sua carga de trabalho a se tornar resiliente ao mau funcionamento e a garantir que ela se recupere para um estado totalmente funcional após a ocorrência de uma falha. | Você projeta os limites para ajudar a evitar o esgotamento dos recursos que pode levar ao mau funcionamento. Você também pode usar esse padrão como um mecanismo de controle em um plano de degradação normal. - RE:07 Autopreservação |
As decisões de design de segurança ajudam a garantir a confidencialidade, integridade e disponibilidade dos dados e sistemas da sua carga de trabalho. | Você pode projetar os limites para ajudar a evitar o esgotamento dos recursos que pode resultar do abuso na automação do sistema. - SE:06 Controles de rede - SE:08 Proteção de recursos |
A otimização de custos se concentra em sustentar e melhorar o retorno sobre o investimento da sua carga de trabalho. | Os limites impostos podem informar a modelagem de custos e até mesmo estar diretamente vinculados ao modelo de negócios do seu aplicativo. Eles também colocam limites superiores claros na utilização, que podem ser levados em consideração no dimensionamento dos recursos. - CO:02 Modelo de custos - CO:12 Custos do dimensionamento |
A eficiência de desempenho ajuda sua carga de trabalho a atender com eficiência às demandas por meio de otimizações em dimensionamento, dados e código. | Quando o sistema está sob alta demanda, esse padrão ajuda a mitigar o congestionamento que pode causar gargalos de desempenho. Você também pode usá-lo para evitar proativamente cenários de vizinhos barulhentos. - PE:02 Planejamento de capacidade - PE:05 Dimensionamento e particionamento |
Tal como acontece com qualquer decisão de design, considere quaisquer compensações em relação aos objetivos dos outros pilares que possam ser introduzidos com este padrão.
Exemplo
A figura final ilustra como a limitação pode ser implementada em um sistema multilocatário. Os usuários de cada uma das organizações de locatário acessam um aplicativo hospedado na nuvem em que eles preenchem e enviam as pesquisas. O aplicativo contém instrumentação que monitora a taxa à qual esses usuários estão enviando solicitações ao aplicativo.
Para evitar que os usuários de um locatário afetam a capacidade de resposta e a disponibilidade do aplicativo para todos os outros usuários, é aplicado um limite ao número de solicitações por segundo que os usuários de um locatário podem enviar. O aplicativo bloqueia solicitações que excedem esse limite.
Próximas etapas
As seguintes diretrizes também podem ser relevantes ao implementar esse padrão:
- Diretrizes sobre Instrumentação e Telemetria. A limitação depende da coleta de informações sobre o quanto um serviço está sendo usado. Descreve como gerar e capturar informações de monitoramento personalizadas.
- Diretrizes de Medição de Serviço. Descreve como medir o uso dos serviços para obter um reconhecimento de como eles são usados. Essa informação pode ser útil para determinar como limitar um serviço.
- Diretrizes de dimensionamento automático. A limitação pode ser usada como uma medida temporária enquanto um sistema é dimensionado automaticamente ou para eliminar a necessidade de dimensionamento automático de um sistema. Contém informações sobre estratégias de dimensionamento automático.
Recursos relacionados
Os seguintes padrões também podem ser relevantes ao implementar este padrão:
- Padrão de nivelamento de carga baseado em fila. O nivelamento de carga baseado em fila é um mecanismo comumente usado para implementar a limitação. Uma fila pode agir como um buffer que ajuda a estabilizar a taxa em que as solicitações enviadas por um aplicativo são entregues a um serviço.
- Padrão de fila de prioridade. Um sistema pode usar o enfileiramento prioritário como parte da sua estratégia de limitação para manter o desempenho de aplicativos críticos ou de maior valor, ao mesmo tempo reduzindo o desempenho de aplicativos menos importantes.
- Padrão de repositório de configuração externo. Ao centralizar e externalizar as políticas de limitação, você pode alterar a configuração no tempo de execução sem a necessidade de uma reimplantação. Os serviços podem assinar alterações de configuração, aplicando assim a nova configuração imediatamente, para estabilizar um sistema.