Por que banco de dados como fila tão ruim? [fechadas]

33

Acabei de ler este artigo e estou confuso.

Vamos imaginar 1 webapp e 1 aplicativo distinto atuando como "trabalhador", ambos compartilhando o mesmo banco de dados .

Ah, eu disse "compartilhar" .. mas sobre o que o artigo adverte? :

Em quarto lugar, compartilhar um banco de dados entre aplicativos (ou serviços) é uma coisa ruim. É muito tentador colocar um estado compartilhado amorfo lá e, antes que você perceba, você terá um monstro imenso.

=> discordo. Existem alguns casos em que aplicativos distintos ainda fazem parte da mesma unidade e, portanto, a noção de "problema de acoplamento" não faz sentido nesse caso.

Vamos continuar: o aplicativo da Web lida com solicitações HTTP do cliente e pode atualizar a qualquer momento alguns agregados (termo DDD), gerando os eventos de domínio correspondentes.
O objetivo do trabalhador seria manipular esses eventos de domínio processando os trabalhos necessários.

O ponto é:

Como os dados de eventos devem ser passados ​​para o trabalhador?

A primeira solução, como o artigo lido promove, seria usar o RabbitMQ, sendo um ótimo middleware orientado a mensagens.

O fluxo de trabalho seria simples:

Sempre que o dinamômetro da web gera um evento, ele é publicado através do RabbitMQ, que alimenta o trabalhador.
A desvantagem seria que nada garante a consistência imediata entre a confirmação da atualização agregada e a publicação do evento, sem lidar com as possíveis falhas de envio ... ou problemas de hardware; essa é outra questão principal.

Exemplo: seria possível que um evento fosse publicado sem êxito da atualização agregada ... resultando em um evento representando uma representação falsa do modelo de domínio.
Você pode argumentar que o XA global (confirmação em duas fases) existe, mas não é uma solução que se adapta a todos os bancos de dados ou middlewares.

Então, o que poderia ser uma boa solução para garantir essa consistência imediata? :
IMO, armazenando o evento no banco de dados, na mesma transação local que a atualização agregada.
Um simples agendador assíncrono seria criado e responsável por consultar os eventos não publicados atuais do banco de dados e enviá-los ao RabbitMQ, que por sua vez preenche o trabalhador.

Mas por que precisar de um agendador extra no lado do aplicativo da Web e, a propósito: por que precisar do RabbitMQ nesse caso?

Por essa solução, parece logicamente que o RabbitMQ pode ser desnecessário, principalmente porque o banco de dados é compartilhado.
De fato, seja qual for o caso, vimos que a consistência imediata envolve uma pesquisa no banco de dados.
Assim, por que o trabalhador não seria responsável diretamente por essa pesquisa?

Portanto, pergunto-me por que tantos artigos na Web criticam dificilmente o enfileiramento de bancos de dados, enquanto promovem o middleware orientado a mensagens.

Trecho do artigo:

Simples, use a ferramenta certa para o trabalho: este cenário está implorando por um sistema de mensagens. Resolve todos os problemas descritos acima; sem mais pesquisas, entrega eficiente de mensagens, sem necessidade de limpar as mensagens concluídas das filas e sem estado compartilhado.

E consistência imediata, ignorada?

Em resumo, parece realmente que, seja qual for o caso, significando compartilhamento de banco de dados ou não, precisamos de pesquisa de banco de dados .

Perdi algumas noções críticas?

obrigado

Mik378
fonte
2
A pesquisa é uma espécie de arenque vermelho, porque quase todos os principais bancos de dados têm algum mecanismo para notificar de forma assíncrona outro processo, que é hora de extrair algum trabalho de uma tabela.
Blrfl

Respostas:

28

Se você estiver criando um aplicativo simples com pouco tráfego, há algo a ser dito sobre como manter outro componente fora do seu sistema. É muito provável que não usar um barramento de mensagens seja a resposta certa para você. No entanto, sugiro que você construa seu sistema de uma maneira que você possa trocar o sistema de filas baseado em banco de dados por uma solução de middleware. Eu concordo com o artigo. Um banco de dados não é a ferramenta certa para o sistema baseado em fila, mas pode ser bom o suficiente para você.

Sistemas baseados em filas como o RabbitMq são construídos em escala maciça em hardware moderado. Sua arquitetura é capaz de conseguir isso, evitando processos que tornam o sistema de banco de dados compatível com ACID lento por natureza. Como um barramento de mensagens precisa apenas garantir que uma mensagem seja armazenada e processada com êxito, ele não precisa se preocupar em bloquear e gravar logs de transações. Ambos os conceitos são absolutamente necessários para um sistema ACID, mas geralmente são uma causa de contenção.

Em termos de desempenho, tudo se resume a: você tem uma tabela SQL. Muitas leituras e muitas gravações. Ambos requerem algum tipo de bloqueio para atualizar linhas, páginas e índices. Seu mecanismo de pesquisa está constantemente bloqueando um índice para fazer pesquisas nele. Isso impede que gravações aconteçam; na melhor das hipóteses, eles estão na fila. O código que está processando também está bloqueado para atualizar o status da fila à medida que eles são concluídos ou falham. Sim, você pode fazer a otimização de consultas após a otimização para que isso funcione, ou pode usar um sistema projetado especificamente para a carga de trabalho que está solicitando. Um RabbitMq consome esse tipo de carga de trabalho sem sequer suar; Além disso, você pode salvar seu banco de dados da carga de trabalho, dando-lhe mais espaço para dimensionar outras atividades.

Outra coisa a considerar é que a maioria dos sistemas de filas normalmente não usa uma técnica de pesquisa (alguns permitem HTTP, mas recomendam evitar o uso pelo lado de recebimento). O RabbitMq usa protocolos de rede projetados especificamente para barramentos de mensagens como o AMPQ .

Editar: Adicionando caso de uso.

A maneira como usei o Rabbit é que tive um ponto de extremidade da API que aceita uma alteração que requer uma tabela de banco de dados muito usada. Esta tabela está em constante contenção e às vezes não poderá salvar uma alteração em tempo hábil da API. Em vez disso, o que faço é gravar a solicitação de alteração em uma fila e, em seguida, ter um serviço que lida com essas mensagens conforme possível. Se ocorrer uma contenção no banco de dados, a fila simplesmente aumenta e o processamento da mensagem é atrasado. Normalmente, o tempo de processamento é reduzido na faixa de 14ms, mas em tempos de alta contenção, chegamos a 2-3 segundos.

brianfeucht
fonte
Como você pode lidar com consistência imediata neste caso? Se a publicação for feita, mas logo após, a transação responsável por atualizar as reversões do modelo de domínio ... O middleware não teria conhecimento e processaria o evento.
Mik378
Você escreveu: "não precisa se preocupar com o bloqueio". Mas certamente existe um tipo de bloqueio para garantir a ordem crescente (no tempo) dos eventos roteados (em direção ao trabalhador), não?
Mik378
@ Mik378 Dê uma olhada neste artigo sobre idempotência de mensagens . Sim, tecnicamente, você perde alguma promessa de consistência, mas aposto que você encontrará o que ganha em termos de confiabilidade do tempo de atividade e desempenho dos aplicativos. Também é bastante fácil alterar a maneira como você processa as mensagens para tornar as perdas bastante simples.
Brianfeucht 6/03/2014
2
Sim, você precisaria de bloqueio para garantir a ordem. Alguns sistemas de filas podem fornecer isso ao preço do desempenho. Se você aceitar o fato de que algumas vezes as operações ocorrerão fora de ordem e descobrir uma maneira de lidar com isso no lado do processador, você ganhará exponencialmente do ponto de vista de desempenho.
Brianfeucht 6/03/2014
1
@ Mik378 - Adicionei um caso de uso à minha resposta. Espero que ajude!
Brianfeucht