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
Respostas:
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.
fonte