fbpx
Streams no RabbitMQ
Publicado em: domingo, 11 de jul de 2021
Categorias: RabbitMQ de A a Z

Uma novidade que vai deixar aqueles que ficavam comparando RabbitMQ e Kafka mais perdidos ainda. No dia 9 de julho saiu um o RabbitMQ 3.9.0 RC que conta com suporte a Streams.

A comparação direta era descabida até então: Enquanto o Kafka trabalha com streams o RabbitMQ lida com filas. Alguns comportamentos fundamentais nunca foram possíveis no Kafka, da mesma forma que alguns dos comportamentos do Kafka nunca foram possíveis com RabbitMQ.

Até agora!

Na versão 3.9 que saiu no último dia 9 de Julho, um recurso me chamou a atenção porque não teve alarde algum. Trata-se do suporte à streams. Agora o RabbitMQ trabalha tanto com Queues (chamadas de Classic Queues) quanto com Streams e isso é incrível.

As classic queues tem um comportamento mandatório de controle de processamento. Por isso em uma fila, uma mesma mensagem nunca é entregue para 2 consumidores.

Ou seja, se você tem 100 mensagens na fila, em condições perfeitas, com 2 consumidores, cada um receberia 50 mensagens, nenhuma mensagem é entregue 2 vezes ou para os 2 consumidores. Assim, até então, para que fazer com que 2 consumidores consumissem a mesma mensagem, eram necessárias 2 classic queues.

A regra é que se você quer entregar a mesma mensagem para diversos consumidores, cada consumidor precisa de uma fila.

A única exceção à essa regra diz respeito ao reprocessamento em caso de falha ou timeout.

Streams

As streams possuem consumo não destrutivo. Ou seja, consumir não apaga as mensagens.

Ao iniciar o consumo de mensagens (chamando o método model.BasicConsume) é necessário enviar um parâmetro OFFSET para determinar a partir de onde devemos começar a consumir a stream. Trata-se de um número, mas existem convenções como FIRST, LAST e NEXT, além do suporte a datas no padrão POSIX.

Exceto pela adição desse parâmetro (x-stream-offset) a coreografia de consumo segue a mesma das classic queues. Já na declaração da stream, precisamos adicionar o parâmetro “x-queue-type” com valor “stream” para que ele crie uma stream.

Diferente das filas, todos os consumidores de uma stream receberão todas as mensagens a partir do offset informado.

Embora esse comportamento só tenha chegado agora, após 14 anos desde seu lançamento em 2007, ele está no inconsciente e na expectativa de dá os primeiros passos com RabbitMQ. Seja pela ausência de preocupação nos produtores de tutoriais, ou pela falta de intimidade do leitor com documentações, ou mesmo pelo hábito e preconceito a respeito das Documentações que acaba não indo muito fundo no entendimento dos fundamentos da plataforma.

Esse novo recurso parece motivador, já que no caso de .NET temos um provider nativo de primeira linha. O nível de preocupação com nosso provider é alto e isso é bem interessante. Outra coisa interessante é que não é necessário um provider especial, o AMQP continua funcionando perfeitamente bem, inclusive com a coreografia de ack manual. Onde o ack tem o papel de alterar um offset default na stream.

A versão 3.9

Essa versão traz break changes na configuração, principalmente para quem usa Docker e Docker Compose para subir instâncias RabbitMQ.

Esses são detalhes para um novo post.

O que muda na API?

Criando Streams

Na declaração de uma Stream, usamos a mesma API que usávamos para declarar filas.

ConnectionFactory factory = new ConnectionFactory();
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();

Map<String, Object> arguments = new HashMap<>();
arguments.put("x-queue-type", "stream");
arguments.put("x-max-length-bytes", 20_000_000_000); // maximum stream size: 20 GB
arguments.put("x-stream-max-segment-size-bytes", 100_000_000); // size of segment files: 100 MB
channel.queueDeclare(
  "my-stream",
  true,         // durable
  false, false, // not exclusive, not auto-delete
  arguments
);

O AMQP sempre disponibilizou esses dicionário de argumentos adicionais, que na maioria das vezes não usávamos em muitos casos. Especificamente na criação da Queue, era um cenário comum. No entanto não precisávamos expressar o x-queue-type quando tratávamos de filas clássicas. Para declarar uma stream, você precisa informar o x-queue-type com o valor stream.

Consumo

No consumo a diferença segue o mesmo estilo, apenas 1 parâmetro novo: x-stream-offset.

channel.basicQos(100); // QoS must be specified
channel.basicConsume(
  "my-stream",
  false,
  Collections.singletonMap("x-stream-offset", "first"), // offset value
  (consumerTag, message) -> {
    // message processing
    // ...
   channel.basicAck(message.getEnvelope().getDeliveryTag(), false); // ack is required
  },
  consumerTag -> { });

A parte curiosa são as possibilidades de valores para x-stream-offset.

Convenções

"x-stream-offset", "first"

Valor

"x-stream-offset", 5000

Datas/Tempo

Date timestamp = new Date(System.currentTimeMillis() - 60 * 60 * 1_000);

"x-stream-offset", timestamp

Os exemplos de código foram tirados da documentação.

Conclusão

Me chama a atenção essa novidade, visto que já havia sido dito no post Understanding the Differences Between RabbitMQ vs Kafka em Nov/2020 que stream estava para chegar. Mas somente agora em Jul/2021, quase 1 ano depois, de fato temos a RC com streams chega ao github.

Para o meu uso, nada muda, os recursos mais importantes para mim são:

  • Garantia de entrega
  • Garantia de entrega única entre consumidores

Eu uso esses recursos para distribuir processamento entre consumidores e garantir que executarão a tarefa apesar de qualquer adversidade de infra, rede, indisponibilidade e downtime próprio ou de dependências. Óbvio que vou explorar a nova funcionalidade, Stream precisa entrar no meu curso de RabbitMQ para Aplicações .NET, mas embora possa fazer muita diferença na vida de muita gente, na minha por hora, não fará.

Você pediu e agora virou curso. Mensageria .NET é minha formação de especialista em RabbitMQ com .NET, onde ensino RabbitMQ do básico, cada fundamento, cada detalhe, ao avançado.

Onde você vai sair do zero absoluto e vai conseguir criar, projetar e corrigir soluções .NET com RabbitMQ.

Além de contar mais 3 outros bonus incríveis para ajudar todos que precisam de um up na carreira.

RabbitMQ Newsletter

Novidades e ofertas de conteúdo exclusivo e único no Brasil.

Hoje com orgulho somos referência quando se fala em RabbitMQ com .NET.

São quase 10 anos usando RabbitMQ em projetos .NET com C#, implantando, convencendo times e mostrando o caminho para aslcançar sos 5 benefícios.

Após centenas de pedidos, criei um curso dedicado aos profissionais .NET. 

Aqui nessa newsletter eu te entrego promoções e links especiais! Cola aqui, tem muita coisa legal!

Luiz Carlos Faria

Meu primeiro contato com RabbitMQ foi em 2013.

Eu estava sozinho na definição de uma arquitetura para a reestruturação de uma integração enquanto meu time estava ocupado com o dia-a-dia.

Naquela época eu precisava de apenas 1 ou 2 recursos que o RabbitMQ entregava.

Nas primeiras semanas e meses em produção pude perceber coisas que não estavam escritas em lugar algum, benefícios e formas de uso das quais poderiam resolver anos de frustração.

Desde então RabbitMQ tem sido meu aliado na restruturação de projetos dos mais variados.

E por mais simples que seja, ainda é possível, 10 anos depois, gerar surpresas com novas abordagens que geram novos benefícios.

7 dias

É tudo que precisa para sair do zero, à produção!

Com conforto, com segurança, e com apoio.

Desde que você já seja um desenvolvedor profissional.

Se você quer entregar mais Disponibilidade, Eficiência, Resiliência, Confiabilidade e/ou Escalabilidade, em projetos .NET, aqui é o seu lugar.

0 comentários

Enviar um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.

Lives

Fique de olho nas lives

Fique de olho nas lives no meu canal do Youtube, no Canal .NET e nos Grupos do Facebook e Instagram.

Aceleradores

Existem diversas formas de viabilizar o suporte ao teu projeto. Seja com os treinamentos, consultoria, mentorias em grupo.