Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Agrupar mensagens relacionadas por uma chave de categoria e processar cada grupo sequencialmente, uma mensagem de cada vez, ao mesmo tempo que se processam diferentes grupos em paralelo.
Este padrão resolve a tensão entre manter a correção primeiro a entrar, primeiro a sair (FIFO) dentro de cada grupo lógico e escalar o processamento concorrente entre grupos. O design garante que as restrições de encomenda não se tornam um gargalo em todo o sistema.
Contexto e problema
As aplicações muitas vezes precisam de processar mensagens relacionadas pela ordem em que chegam, continuando a escalar para lidar com o aumento da carga. Numa arquitetura distribuída, este requisito é difícil de alcançar porque os trabalhadores puxam mensagens de forma independente de uma fila partilhada. Quando vários trabalhadores competem por mensagens, como no padrão Consumidores Concorrentes, a encomenda falha.
Considere um sistema de acompanhamento de ordens que recebe uma série de operações, como criar uma ordem, adicionar uma transação, modificar uma transação anterior e eliminar uma ordem. As operações de cada ordem devem ser processadas por ordem FIFO, pois aplicá-las fora da sequência corromperia o estado da ordem. No entanto, a fila de chegada intercala operações entre muitas encomendas. Um único consumidor que impõe encomendas globais torna-se um gargalo, e vários consumidores podem processar as operações da mesma encomenda fora de sequência.
As abordagens diretas a este problema dividem-se cada uma de forma diferente:
Consumidor único. Um único consumidor preserva a ordem das mensagens porque processa uma mensagem de cada vez, mas não consegue escalar para suportar um aumento da taxa de transferência.
Múltiplos consumidores concorrentes. Vários consumidores aumentam a taxa de processamento ao obter mensagens em paralelo, mas perdem as garantias de ordenação por grupo. Dois trabalhadores podem puxar mensagens consecutivas para a mesma ordem e processá-las simultaneamente ou fora de sequência, o que corrompe o estado da ordem.
Solution
O padrão Convoy Sequencial divide mensagens relacionadas em categorias e processa cada categoria sequencialmente, uma mensagem de cada vez, enquanto as categorias são processadas em paralelo.
O padrão funciona atribuindo a cada mensagem uma chave de categoria que identifica o grupo a que pertence. Um corretor de mensagens usa esta chave para particionar mensagens em grupos lógicos. Dentro de cada grupo, o corretor impõe ordens FIFO para que um consumidor que bloqueie um grupo receba mensagens estritamente na sequência em que foram enfileiradas. Diferentes grupos podem ser processados por diferentes consumidores simultaneamente, pelo que o sistema escala horizontalmente entre grupos sem sacrificar a encomenda dentro de nenhum grupo individual.
No Azure, as sessões de mensagens do Azure Service Bus fornecem uma implementação incorporada deste padrão.
O diagrama seguinte mostra o padrão geral de Comboios Sequenciais.
Na fila, as mensagens para diferentes categorias podem estar intercaladas, como mostrado no diagrama seguinte.
Este padrão oferece vários benefícios chave:
Processamento ordenado por grupo. As mensagens dentro de cada categoria são processadas estritamente em sequência, o que previne condições de raça, mutações de estado fora de ordem e a necessidade de reordenar soluções alternativas.
Escala horizontal entre grupos. Cada categoria é uma unidade independente de concorrência. A adição de consumidores aumenta o débito proporcionalmente ao número de categorias ativas, sem comprometer as garantias de ordenação.
Desacoplamento produtor-consumidor. Os produtores colocam mensagens em fila sem saber qual consumidor as irá processar ou quando. Os consumidores são escaláveis e substituíveis de forma independente.
Problemas e considerações
Considere os seguintes pontos ao decidir como implementar esse padrão:
Categoria e unidade de escala. Determine com base em que propriedade das mensagens recebidas pode escalar horizontalmente. A chave de categoria define a unidade de paralelismo: cada valor de chave distinta torna-se um grupo processável de forma independente. No cenário de acompanhamento de ordem, esta propriedade é o ID da ordem. Escolher uma chave demasiado grosseira (por exemplo, um único ID de cliente para todas as encomendas) limita o paralelismo, enquanto escolher uma chave demasiado fina não oferece benefício significativo na encomenda.
Limites de rendimento. Avalie a taxa de transferência da sua mensagem de destino. Como este padrão impõe processamento sequencial dentro de cada categoria, a taxa de processamento por categoria fica limitada ao tempo necessário para processar uma única mensagem. Otimize o tempo de processamento por mensagem, por exemplo, usando E/S assíncrona ou agrupando escritas a jusante, porque esse tempo determina diretamente o throughput máximo para cada categoria. Se os seus requisitos globais de throughput forem muito elevados, reconsidere se a ordenação FIFO estrita é realmente necessária ao longo de todo o ciclo de vida da mensagem. Alternativas incluem impor uma mensagem inicial e uma mensagem final para colocar uma sequência entre parênteses, ou ordenar mensagens por carimbo temporal dentro de uma janela batch e depois enviar o batch para processamento paralelo.
Capacidades de serviço. Verifique se o intermediário de mensagens escolhido suporta o processamento das mensagens uma de cada vez numa fila ou categoria de uma fila. Nem todos os serviços de mensagens oferecem garantias de bloqueio ao nível de sessão ou FIFO dentro de uma partição. Se o corretor não suportar nativamente esta capacidade, o consumidor deve implementar a sua própria lógica de coordenação, o que acrescenta complexidade e arrisca processamento duplicado, mensagens perdidas ou execução fora de ordem. O suporte às sessões também pode limitar a escolha do nível de mensagens ou SKU, o que afeta o custo.
Capacidade de evolução Planeie como irá adicionar novas categorias de mensagens ao sistema. O padrão deve acomodar o crescimento da cardinalidade da categoria sem exigir alterações estruturais aos consumidores. Por exemplo, suponha que o sistema de registo descrito anteriormente é específico de um cliente. Se precisares de integrar um novo cliente, deverias conseguir adicionar um conjunto de processadores de registo que distribuam o trabalho por ID de cliente sem redesenhar a topologia da fila.
Entrega de mensagens fora de ordem. As mensagens podem chegar fora de ordem devido à latência variável da rede entre o produtor e o corretor, antes de a ordem de sessão do corretor entrar em vigor. Considere usar números de sequência para verificar a ordem dentro de cada categoria. Também pode incluir uma bandeira de fim de sequência na última mensagem de uma transação para que os consumidores possam detetar quando uma sequência está completa.
Tratamento de mensagens de envenenamento. Uma mensagem que falha repetidamente no processamento dentro de uma sessão bloqueia todas as mensagens subsequentes nessa sessão porque o padrão impõe uma ordem sequencial rigorosa. Defina uma estratégia para detetar mensagens problemáticas, por exemplo, acompanhando o número de tentativas de entrega, e movê-las para uma fila de mensagens não entregues após um número máximo de tentativas definido, para que as restantes mensagens da sessão possam continuar a ser processadas.
Disponibilidade de corretores. O intermediário de mensagens é uma dependência comum a todas as categorias. A sua disponibilidade e durabilidade afetam diretamente as garantias de fiabilidade do padrão. Avalie funcionalidades de resiliência ao nível do broker, como zonas de disponibilidade e recuperação após desastre geográfico, com base nos requisitos de disponibilidade da carga de trabalho e no orçamento, pois as configurações com maior durabilidade normalmente aumentam o custo.
Correção da chave do produtor. O padrão assume que os produtores definem corretamente a chave de categoria (ID da sessão) em todas as mensagens. Se um produtor definir uma chave incorreta, seja acidentalmente ou devido a um erro, a mensagem é encaminhada para a sessão errada e corrompe o estado do grupo. Valide que os produtores atribuem chaves de categoria de forma consistente e considere adicionar lógica de validação de chaves do lado do consumidor se a consequência de uma mensagem encaminhada incorretamente for grave.
Complexidade operacional. A monitorização do processamento baseado em sessões implica uma sobrecarga operacional superior à do consumo de filas padrão. Os operadores precisam de visibilidade sobre a acumulação de sessões (o número de sessões ativas e a quantidade de mensagens em espera em cada sessão) para identificar as categorias que estão a atrasar-se. Sessões com letra morta requerem um fluxo de trabalho separado de monitorização e remediação para investigar mensagens falhadas, resolver a causa raiz e reproduzir mensagens corrigidas de volta à sessão.
Contenção e latência do bloqueio da sessão. O bloqueio de sessão introduz sobrecarga de latência porque cada consumidor deve adquirir um bloqueio exclusivo numa sessão antes de processar as mensagens. Quando um consumidor tem um bloqueio de sessão, nenhum outro consumidor pode processar mensagens dessa sessão, mesmo que o consumidor esteja lento ou temporariamente bloqueado. Se a duração do bloqueio for demasiado curta, a expiração do bloqueio pode causar o reprocessamento de mensagens. Se a duração do bloqueio for demasiado longa, um consumidor parado atrasa a recuperação. Ajuste a duração do bloqueio da sessão com base no tempo esperado de processamento das mensagens e implemente a renovação do bloqueio para operações de maior duração.
Escalabilidade e custo para o consumidor. O paralelismo entre sessões traduz-se em instâncias concorrentes de consumidores. Num modelo serverless, como o Funções do Azure, cada sessão ativa corresponde a uma execução em simultâneo e, num modelo dedicado, corresponde a uma instância ou thread de execução. O número de sessões ativas, portanto, influencia diretamente o custo de computação. Planeie limites de escala para consumidores e controlos de concorrência para equilibrar o rendimento com o custo.
Quando utilizar este padrão
Utilize este padrão quando:
- As mensagens chegam por ordem e devem ser processadas na mesma ordem.
- As mensagens podem ser categorizadas de modo a que cada categoria se torne uma unidade de escala independente para o sistema.
Este padrão pode não ser adequado quando:
Prevê cenários com uma taxa de transferência muito elevada (milhões de mensagens por minuto), porque o requisito FIFO limita a escalabilidade que o sistema pode alcançar.
A ordem das mensagens não é obrigatória. Quando as mensagens podem ser processadas independentemente em qualquer ordem, o padrão Consumadores Concorrentes proporciona uma escalabilidade horizontal mais simples sem a sobrecarga de coordenação do bloqueio de sessão.
Design da carga de trabalho
Avalie como utilizar o Convoy Sequencial no design de uma carga de trabalho para abordar os objetivos e princípios abordados nos pilares do Azure Well-Architected Framework. A tabela a seguir fornece orientação sobre como esse padrão suporta as metas de cada pilar.
| 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 garantem que ela se recupere para um estado totalmente funcional após a ocorrência de uma falha. | Este padrão utiliza ordenação FIFO baseada em sessões para eliminar condições de corrida, lógica de processamento de mensagens sujeita a contenção e outras soluções alternativas para mensagens incorretamente ordenadas que podem levar ao mau funcionamento. - RE:02 Fluxos críticos - RE:07 Trabalhos em segundo plano |
Se este padrão introduzir compensações dentro de um pilar, considere-as em relação aos objetivos dos outros pilares.
Example
No Azure, pode implementar este padrão usando sessões de mensagens do Service Bus. Para os consumidores, pode utilizar o Azure Logic Apps com o conector Service Bus peek-lock ou o Funções do Azure com o accionador do Service Bus.
Quando um produtor define a SessionId propriedade numa mensagem, o Service Bus agrupa todas as mensagens que partilham o mesmo ID de sessão numa única sessão lógica. Um consumidor aceita uma sessão e recebe um bloqueio exclusivo sobre ela. Este bloqueio garante que apenas um consumidor processa as mensagens dessa sessão em cada momento e que as mensagens chegam por ordem FIFO. Outros consumidores podem aceitar e processar simultaneamente sessões diferentes, proporcionando processamento paralelo nos vários grupos.
No exemplo do acompanhamento de encomendas, o sistema processa cada mensagem do registo na ordem em que foi recebida e envia cada transação para outra fila onde a categoria é definida para o ID da ordem. Uma transação nunca envolve múltiplas encomendas neste cenário, pelo que os consumidores processam cada categoria em paralelo, mas seguindo FIFO dentro de cada categoria.
O processador do registo distribui as mensagens, desagregando em lotes individuais o conteúdo de cada mensagem da primeira fila:
O processador do registo executa três etapas:
- Percorre o registo uma transação de cada vez.
- Define o ID da sessão da mensagem para corresponder ao ID da ordem.
- Envia cada transação do livro-razão para uma fila secundária, com o ID da sessão definido como o ID da encomenda.
Os consumidores escutam a fila secundária e processam todas as mensagens com IDs de encomenda correspondentes segundo a ordem FIFO. Os consumidores utilizam o modo peek-lock.
A fila do livro-razão é um ponto de transição de processamento em série para processamento em paralelo: todas as transações passam por ela sequencialmente antes de serem distribuídas para processamento paralelo baseado em sessões. Esta fase de serialização é o principal gargalo de escalabilidade porque bloqueia o throughput de todo o pipeline a jusante. No entanto, depois de o processador do registo distribuir as mensagens pela fila secundária, os consumidores podem escalar independentemente por sessão, uma por cada ID de encomenda.
Tecnologias de apoio
Sessões de mensagens Service Bus: Agrupa as mensagens por ID de sessão e aplica o processamento FIFO dentro de cada sessão. As sessões de mensagens são o principal mecanismo do Azure para implementar o padrão Sequential Convoy.
Funções do Azure Service Bus trigger: Suporta triggers baseados em sessões que permitem que as instâncias de funções processem mensagens de uma única sessão de cada vez.
Conector do Service Bus para o Logic Apps: Fornece um conector do Service Bus com suporte para peek-lock para consumir filas com sessões ativadas no processamento baseado em fluxos de trabalho.
Contributors
A Microsoft mantém este artigo. Os seguintes colaboradores escreveram este artigo.
Autor principal:
- Naga Venkata Cheruvu | Arquiteto Sénior de Soluções Cloud + Infraestrutura de IA
Para ver perfis não públicos do LinkedIn, faça login no LinkedIn.
Recursos relacionados
Padrão de Consumidores Concorrentes: Vários consumidores consomem mensagens de uma fila partilhada em paralelo, o que aumenta a taxa de transferência, mas remove a garantia de ordenação das mensagens. O padrão Sequential Convoy resolve a lacuna na ordenação que o padrão Competing Consumers introduz. Aborda esta lacuna particionando as mensagens em sessões com chaves de categoria e processando cada sessão sequencialmente.
Padrão de nivelamento de carga baseado em filas: Uma fila serve de memória intermédia entre produtores e consumidores para absorver picos e atenuar uma carga desigual. O padrão Sequential Convoy baseia-se neste buffering adicionando partição baseada em sessões, de modo que a fila de ambos os níveis carregue entre categorias e preserve a ordenação FIFO dentro de cada categoria.
Padrão de fila de prioridade: As mensagens são encaminhadas para filas separadas ou recebem prioridade dentro de uma fila para que o trabalho de prioridade superior seja processado antes do trabalho de menor prioridade. Quando a ordenação dentro de um nível de prioridade também tiver de ser preservada, o padrão de Comboio Sequencial pode ser combinado com o enfileiramento por prioridade para garantir o processamento FIFO em cada sessão identificada por prioridade.
Mensagem Peek-Lock (leitura não destrutiva): Esta operação recupera e bloqueia atomicamente uma mensagem de uma fila ou subscrição para processamento.
Entrega por ordem de mensagens correlacionadas no Logic Apps através de sessões do Service Bus: Este artigo de blogue descreve o suporte do Logic Apps para o padrão Sequential Convoy.