DEV Community

Cover image for O Modelo de Concorrência do Brighter: Como Threads Dedicadas Impulsionam Pumps de Mensagens Assíncronas
Rafael Andrade
Rafael Andrade

Posted on

O Modelo de Concorrência do Brighter: Como Threads Dedicadas Impulsionam Pumps de Mensagens Assíncronas

Introdução

No artigo anterior, exploramos a arquitetura do pump de mensagens do Brighter, incluindo os padrões Reactor e Proactor. Este artigo foca em como configurar o número de instâncias da bomba de mensagens e explica a decisão de design do Brighter de usar threads dedicadas para processamento de mensagens, mesmo em cenários assíncronos.

Recapitulação do Pump de Mensagens

O Pump de mensagens do Brighter abstrai o consumo de mensagens do transporte subjacente (ex: RabbitMQ, Kafka). Existem duas implementações principais:

  • Padrão Reactor: Processamento síncrono de mensagens usando uma única thread por bomba.
  • Padrão Proactor: Processamento assíncrono de mensagens via async/await, aproveitando o SynchronizationContext para preservar a afinidade de thread.

Configurando o Número de Bombas de Mensagens

Por padrão, o Brighter configura uma instância do pump de mensagens por assinatura. Para escalar horizontalmente, ajuste o parâmetro noOfPerformers:

new <Provider>Subscription<SomeRequest>(
   new SubscriptionName("some-name"),
   new ChannelName("some-queue"),
   new RoutingKey("some-topic"),
   noOfPerformers: 16 // Defina para corresponder às suas necessidades de concorrência
)
Enter fullscreen mode Exit fullscreen mode

Modelo de Execução da Bomba de Mensagens

O Brighter usa uma abordagem de multitarefa preemptiva:

  • Cada pump de mensagens é executada em sua própria thread dedicada.
  • As threads são gerenciadas explicitamente para evitar contenção e garantir desempenho previsível.

Por que não usar Task.Run ou Task.Factory.StartNew?

O Brighter evita Task.Run para operações de longa duração porque:

  • Sobrecarga do ThreadPool: Tarefas de longa duração podem esgotar o ThreadPool, causando starvation do pool de threads.
  • Controle Determinístico: Threads fornecem controle mais refinado sobre afinidade de CPU e prioridade em comparação com Tasks.
  • Consistência: Alinha-se ao modelo de thread por bomba do Reactor, garantindo compatibilidade com fluxos síncronos e assíncronos.

Como observado no ADR para suporte a pipelines assíncronos, o design do Brighter prioriza o gerenciamento explícito de threads para evitar problemas com async/await em ambientes com pool.

Contexto Assíncrono e Afinidade de Thread

Para o padrão Proactor, o Brighter usa um SynchronizationContext personalizado para garantir:

  • Afinidade de Thread: Mantém a mesma thread antes e depois do await para evitar trocas de contexto.
  • Execução Previsível: Prevê condições de corrida isolando pipelines assíncronas em suas próprias threads.

Essa abordagem resolve a tensão entre a E/S não bloqueante do Proactor e a necessidade de gerenciar estado local de thread em sistemas distribuídos.

Principais Razões de Design

  • Segurança de Thread: Threads dedicadas eliminam conflitos de estado compartilhado durante o processamento.
  • Escalabilidade: noOfPerformers permite escalonamento horizontal sem alterar o modelo de threads da aplicação.
  • Confiabilidade Assíncrona: O SynchronizationContext personalizado garante comportamento determinístico, evitando problemas como starvation do pool de threads.

Conclusão

Configurar o número de bombas de mensagens no Brighter equilibra escalabilidade e gerenciamento de recursos. Ao dedicar threads a cada bomba:

  • O Reactor garante processamento ordenado e previsível.
  • O Proactor permite fluxos assíncronos de alta taxa de transferência, preservando afinidade de thread.

Esse design, baseado em multitarefa preemptiva e gerenciamento explícito de threads, garante confiabilidade em pipelines síncronos e assíncronos. Para cenários assíncronos avançados, consulte o ADR sobre suporte a pipelines assíncronos.

Referência

Top comments (0)