- Removemos o RabbitMQ e o substituímos por uma fila no PostgresDB usando SQL
- A troca levou cerca de meio dia, e o código-fonte ficou 580 linhas menor
- Mais importante ainda: a estabilidade e a resiliência melhoraram bastante
- Não se trata de criticar sistemas de fila como o RabbitMQ, mas simplesmente de um esforço para manter tudo mais simples
- A Prequel, autora deste texto, é um produto que ajuda empresas B2B SaaS a sincronizar com os bancos de dados de seus clientes por meio de pipelines de dados em larga escala
- A arquitetura era composta por RabbitMQ + AQMP + Helm + wrapper em GoLang, e funcionou bem por um tempo, mas os problemas começaram a aparecer
- O envio das mensagens passou a sofrer atrasos longos demais, fazendo com que mensagens fossem canceladas
- Como o consumer fazia prefetch das mensagens, surgiu a situação em que a próxima mensagem ficava retida até a conclusão da mensagem atual
- Se esse prefetch fosse definido como 0, ele se tornava infinito, então não era possível desativá-lo
- O problema acontecia porque os trabalhos que recebiam e processavam as mensagens geralmente eram tarefas de longa duração (transferência de dados)
- Eles entenderam exatamente o que estava acontecendo, mas não havia uma forma imediata de corrigir isso. Como o problema afetava clientes em produção, esperar não era uma opção
- Por isso, passaram a operar com um modelo simples de leitura e escrita no Postgres usando uma única tabela
- Locks em nível de linha para leitura/escrita garantem que apenas um consumer leia cada trabalho
- É absurdamente simples, mas está funcionando perfeitamente
- Há também a vantagem de o estado da aplicação não ficar dividido entre RabbitMQ e Postgres, mas consolidado em um único lugar
6 comentários
Eu também implementei diretamente uma fila no mysql com
row level lock, e isso tem funcionado bem em produção há anos.O que eu queria, simplesmente, era oferecer uma funcionalidade parecida com fila para vários workers, armazenando junto o payload com estados dentro da fila como em espera/em andamento/falha (se concluir, é removido).
Pelo fato de, no texto, terem feito a transição do rabbitmq para o banco de dados em pouco tempo, imagino que isso se deva a não precisarem necessariamente da generalidade de um serviço de filas dedicado nem dos seus diversos recursos e possibilidades de configuração.
Parece que o problema surgiu por um descompasso entre o envio do ACK manual e a transação do banco de dados,
e é interessante que eles tenham resolvido isso não com engenharia, mas removendo o RabbitMQ.
O RabbitMQ provavelmente não teve culpa...
https://news.ycombinator.com/item?id=35526846
Há muitas opiniões nos comentários.
Também existe algo como isto, que funciona de forma semelhante: https://github.com/pjongy/jasyncq
Parece que há possibilidade de ser feito
selectao mesmo tempo; fiquei curioso sobre como isso foi resolvido.Parece que está escrito
row level lock.