Use uma fila que atua como um buffer entre uma tarefa e um serviço que ela invoca para suavizar cargas pesadas intermitentes que podem fazer com que o serviço falhe ou a tarefa atinja o tempo limite. Isso pode ajudar a minimizar o impacto dos picos de demanda na disponibilidade e capacidade de resposta para a tarefa e o serviço.
Contexto e problema
Muitas soluções na cloud envolvem a execução de tarefas que invocam serviços. Neste ambiente, se um serviço estiver sujeito a cargas pesadas intermitentes, este poderá causar problemas de fiabilidade ou desempenho.
Um serviço pode fazer parte da mesma solução que as tarefas que a utilizam ou pode ser um serviço de terceiros a fornecer acesso a recursos frequentemente utilizados, tal como um serviço de armazenamento ou em cache. Se o mesmo serviço for utilizado por várias tarefas em execução em simultâneo, poderá ser difícil prever o volume de pedidos do serviço a qualquer momento.
Um serviço pode obter picos de procura que provocam uma sobrecarga do mesmo, o que impede o envio de respostas aos pedidos de uma forma atempada. O congestionamento de um serviço com um grande número de pedidos simultâneos também poderá resultar numa falha do serviço se este não conseguir processar a disputa provocada por estes pedidos.
Solução
Refatore a solução e introduza uma fila entre a tarefa e o serviço. A tarefa e o serviço são executados de forma assíncrona. A tarefa publica uma mensagem que contém os dados que o serviço necessita para uma fila. A fila funciona como uma memória intermédia ao armazenar a mensagem até que seja obtida pelo serviço. O serviço obtém as mensagens da fila e processa-as. Os pedidos de várias tarefas, que podem ser gerados a uma velocidade altamente variável, podem ser transmitidos ao serviço através da mesma fila de mensagens. Esta figura mostra a utilização de uma fila para redistribuir a carga de um serviço.
A fila desacopla as tarefas do serviço e, assim, o serviço pode processar as mensagens ao seu próprio ritmo, independentemente do volume de pedidos de tarefas simultâneas. Além disso, não ser verificará nenhum atraso numa tarefa se o serviço estiver indisponível no momento em que publica uma mensagem para a fila.
Este padrão fornece os benefícios seguintes:
Pode ajudar a maximizar a disponibilidade, porque os atrasos resultantes nos serviços não têm um impacto imediato e direto na aplicação, a qual pode continuar a publicar mensagens na fila, mesmo quando o serviço está indisponível ou não está no momento a processar mensagens.
Pode ajudar a maximizar a escalabilidade, uma vez que tanto o número de filas como o número de serviços podem ser diversificados para satisfazer a procura.
Pode ajudar a controlar os custos, porque o número de instâncias do serviço implementadas apenas tem de ser suficiente para satisfazer a carga média ao invés do pico de carga.
Alguns serviços implementam a limitação quando a procura atinge um limiar que pode levar à falha do sistema. A limitação pode reduzir as funcionalidades disponíveis. Pode implementar a redistribuição de carga com estes serviços para assegurar que este limiar não é alcançado.
Problemas e considerações
Na altura de decidir como implementar este padrão, considere os seguintes pontos:
- É necessário implementar a lógica da aplicação que controla a velocidade a que os serviços processam as mensagens para evitar sobrecarregar o recurso de destino. Evite transmitir picos de procura para a próxima fase do sistema. Teste o sistema sob carga, para garantir que fornece a redistribuição necessária, e ajuste o número de filas e o número de instâncias de serviço que processam as mensagens para obter esta configuração.
- As filas de mensagens são um mecanismo de comunicação unidirecional. Se uma tarefa esperar uma resposta de um serviço, poderá ser necessário implementar um mecanismo que o serviço pode utilizar para enviar uma resposta. Para obter mais informações, veja o Asynchronous Messaging Primer (Manual Básico de Mensagens Assíncronas).
- Tenha cuidado se aplicar o dimensionamento automático a serviços que estão escutando solicitações na fila. Tal pode resultar numa maior contenção de todos os recursos que estes serviços partilham e reduz a eficácia da utilização da fila para redistribuir a carga.
- Dependendo da carga do serviço, você pode se deparar com uma situação em que você está efetivamente sempre ficando para trás, onde o sistema está sempre enfileirando mais solicitações do que você está processando. A variabilidade do tráfego de entrada para seu aplicativo precisa ser levada em consideração
- O padrão pode perder informações dependendo da persistência da fila. Se a sua fila falhar ou deixar cair informações (devido aos limites do sistema), existe a possibilidade de não ter uma entrega garantida. O comportamento da fila e os limites do sistema precisam ser levados em consideração com base nas necessidades da sua solução.
Quando utilizar este padrão
Este padrão é prático para qualquer aplicação que utiliza os serviços sujeitos a sobrecargas.
Este padrão não será prático se a aplicação esperar uma resposta do serviço com uma latência mínima.
Design da carga de trabalho
Um arquiteto deve avaliar como o padrão de Nivelamento de Carga Baseado em Fila pode ser usado no design de sua carga de trabalho para abordar as metas e os princípios abordados nos pilares do Azure Well-Architected Framework. Por exemplo:
Pilar | Como esse padrão suporta os objetivos do pilar |
---|---|
As decisões de projeto 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. | A abordagem descrita neste padrão pode fornecer resiliência contra picos repentinos de demanda, dissociando a chegada de tarefas de seu processamento. Ele também pode isolar falhas no processamento de filas para que elas não afetem a entrada. - RE:06 Dimensionamento - RE:07 Trabalhos em segundo plano |
A Otimização de Custos está focada em sustentar e melhorar o retorno do investimento da sua carga de trabalho. | Como o processamento de carga é dissociado da solicitação ou da entrada de tarefas, você pode usar essa abordagem para reduzir a necessidade de provisionar recursos em excesso para lidar com a carga de pico. - CO:12 Custos de escala |
A Eficiência de Desempenho ajuda sua carga de trabalho a atender às demandas de forma eficiente por meio de otimizações em escala, dados e código. | Essa abordagem permite o design intencional no desempenho da taxa de transferência porque a entrada de solicitações não precisa estar correlacionada à taxa em que elas são processadas. - PE:05 Dimensionamento e particionamento |
Como em qualquer decisão de design, considere quaisquer compensações em relação aos objetivos dos outros pilares que possam ser introduzidos com esse padrão.
Exemplo
Um aplicativo Web grava dados em um armazenamento de dados externo. Se um grande número de instâncias do aplicativo Web for executado simultaneamente, o armazenamento de dados poderá não conseguir responder às solicitações com rapidez suficiente, fazendo com que as solicitações atinjam o tempo limite, sejam limitadas ou falhem. O diagrama a seguir mostra um armazenamento de dados sendo sobrecarregado por um grande número de solicitações simultâneas de instâncias de um aplicativo.
Para resolver isso, você pode usar uma fila para nivelar a carga entre as instâncias do aplicativo e o armazenamento de dados. Um aplicativo do Azure Functions lê as mensagens da fila e executa as solicitações de leitura/gravação no repositório de dados. A lógica do aplicativo no aplicativo de função pode controlar a taxa na qual ele passa solicitações para o armazenamento de dados, para evitar que o armazenamento seja sobrecarregado. (Caso contrário, o aplicativo de função apenas reintroduzirá o mesmo problema no back-end.)
Próximos passos
As seguintes orientações também podem ser relevantes ao implementar este padrão:
Asynchronous Messaging Primer (Manual Básico de Mensagens Assíncronas). As filas de mensagens são inerentemente assíncronas. Poderá ser necessário redesenhar a lógica da aplicação numa tarefa se esta for adaptada a partir da comunicação direta com um serviço para utilizar uma fila de mensagens. Da mesma forma, poderá ser necessário refatorar um serviço para aceitar pedidos de uma fila de mensagens. Em alternativa, pode ser possível implementar um serviço de proxy, conforme descrito no exemplo.
Escolha entre os serviços de mensagens do Azure. Informações sobre como escolher um mecanismo de mensagens e colocação em fila do Azure.
Comunicação assíncrona baseada em mensagens.
Recursos relacionados
- Estilo de arquitetura Web-Queue-Worker. A função Web e a função de trabalho não têm estado. O estado da sessão pode ser armazenado numa cache distribuída. Qualquer trabalho de execução longa é realizado de modo assíncrono pela função de trabalho. A função de trabalho pode ser acionada por mensagens na fila ou executada com base numa agenda para o processamento em lotes.
Os seguintes padrões também podem ser relevantes ao implementar esse padrão:
Padrão de Consumidores Concorrentes. Pode ser possível executar várias instâncias de um serviço, com cada uma a agir como um consumidor de mensagens da fila de redistribuição de carga. Pode utilizar esta abordagem para ajustar a velocidade a que as mensagens são recebidas e transmitidas para um serviço.
Padrão de Limitação. Uma forma simples de implementar a limitação com um serviço passa por utilizar a redistribuição de carga baseada na fila e encaminhar todos os pedidos para um serviço através de uma fila de mensagens. O serviço pode processar pedidos a uma velocidade que garante que os recursos necessários pelo serviço não são esgotados e para reduzir a quantidade de contenção que pode ocorrer.