Implementando um serviço distribuído de n-produtores / 1 consumidor para sistema de missão crítica

Aug 17 2020

Estou tentando implementar uma versão distribuída de multiprodutor / 1 consumidor para um sistema de missão crítica. Estou procurando boas alternativas para a abordagem atual baseada em RDBMS.

O problema

O sistema consiste em produtores de servidores (50+) que produzem continuamente milhares de instâncias por segundo. Cada instância é uma estrutura bem definida, com carimbo de data / hora e plana. Cada instância é armazenada em uma única fila pelos produtores.

Por outro lado, tenho um consumidor que consome as instâncias de forma FIFO.

Os produtores e o consumidor funcionam em máquinas diferentes conectadas por uma rede privada TCP / IP.

Para fins de integridade, existem dois requisitos fortes

  1. O consumidor não pode consumir o mesmo recurso duas vezes. É um erro.
  2. Todo recurso deve ser consumido pelo consumidor. Se um recurso for perdido, é uma perda

Além disso, a solução deve ser executada em servidores Linux e Windows.

Abordagem atual

Na versão atual, o sistema implementa esta solução utilizando um banco de dados relacional como barramento de dados.

Existe um servidor de banco de dados que oferece suporte a todos os produtores e consumidores. Os produtores inserem recursos em uma determinada tabela e o consumidor consome os recursos dessa tabela conforme representado na imagem acima.

O modelo de transação do servidor de banco de dados / JDBC permite controlar as inserções / exclusões para evitar a corrupção da fila.

Essa abordagem atual funciona bem, mas:

  1. Apresenta a sobrecarga de manter um servidor de banco de dados relacional completo para uma tarefa onde nenhum relacionamento de dados é necessário;
  2. O servidor de banco de dados relacional deve se ajustar aos requisitos de missão crítica, o que é difícil de conseguir em algumas configurações reais quando a instância do servidor de banco de dados não é dedicada

Alternativas

Aqui estou listando algumas alternativas para a abordagem atual do barramento de dados do servidor de banco de dados relacional:

Servidor dedicado de banco de dados relacional leve

Esta parece ser a abordagem mais fácil: usar um servidor de banco de dados relacional leve e dedicado como HSQLDB, Apache Derby ou H2.

Prós

Eles têm consideravelmente menos sobrecarga para manter se comparados com um RDBMS como o MS SQL Server, Oracle DB Server ou mesmo MySQL. Além disso, menos alterações de código e testes são necessários, uma vez que são basicamente mecanismos SQL como os usados ​​na solução atual.

Contras

Eles são servidores de banco de dados relacionais, portanto, ainda existe algum nível de sobrecarga para executar uma tarefa sem relacionamento. Outro ponto é o aspecto da missão crítica. Usamos o Derby DB internamente por anos para surpervision do sistema em tempo real nos modos incorporado e de rede. Funciona muito bem, sem travamento nem corrupção de dados. No entanto, o volume de transações / s para esse novo uso é maior.

Servidor Redis

À primeira vista, o Redis parece perfeito para esse caso de uso. Na memória, rápido, sem overhad para relacionamento de dados, direto. Amplamente utilizado como barramento de dados e relatado como confiável. Mas não para o Windows. Como dito nos documentos, Redis no Windows não é recomendado . A versão do Microsoft Windows não é mais mantida , o último lançamento data de 2016, então anexar o Redis ao sistema não parece promissor.

Implementando uma solução do zero

Enfim, é um problema produtor-consumidor. Implementar um serviço de rede usando TCP ou algo mais elegante como Camel e usar fila simultânea internamente mais algum mecanismo de persistência local custará muito tempo, reinventar a roda, mas ainda é uma opção.

Essas são as alternativas que estamos considerando até agora. Agradeço se alguém puder fornecer algumas dicas ou recomendações.

Respostas

2 LieRyan Aug 18 2020 at 02:08

Parece que você está procurando uma fila de mensagens. Dependendo de sua pilha de tecnologia, existem várias implementações de fila distribuída que podem interessar a você, por exemplo ZeroMQ ou RabbitMQ.

Algumas abordagens como ZeroMQ podem ser executadas sem ter um intermediário de mensagem, o que significa que os produtores e consumidores conversam diretamente sem a necessidade de outro serviço ou banco de dados para orquestrar / intermediar a fila. Ser sem corretor tem a vantagem de ser muito mais simples de gerenciar operacionalmente do que filas de mensagens corretadas e ser mais simples de entender, escalar e personalizar, mas a principal desvantagem é que falta os serviços normalmente fornecidos por corretores, portanto, se um participante é off-line, as mensagens podem ser perdidas. Se você precisa que a mensagem seja processada de forma confiável, você precisará projetar seus produtores para serem capazes de lidar com a repetição do envio se o consumidor não estiver disponível, você precisará adicionar um mecanismo para confirmação da entrega bem-sucedida e as necessidades do consumidor ser projetado para ser idempotente (ser capaz de detectar mensagens duplicadas e descartá-las). A principal vantagem de não ter um corretor é que você é livre para implementar tanto ou tão pouco comportamento de corretor quanto seu aplicativo precisar, portanto, você não está vinculado a um comportamento de corretor específico.

Uma fila de mensagens intermediárias como RabbitMQ é um pouco mais simples durante o uso, pois o corretor adiciona uma camada de persistência e confiabilidade de mensagens à estrutura do sistema de fila em vez de exigir que o produtor e os consumidores as implementem, mas adiciona a complexidade e a sobrecarga de gerenciamento do corretor , e o corretor adiciona latência, portanto, pode ser inadequado para cenários em que os milissegundos importam ou onde o nível de escalabilidade de destino excede o que pode ser alcançado em um sistema intermediado.

ainda existe algum nível de sobrecarga para realizar uma tarefa sem relacionamento

Sugiro que você crie o perfil de seu aplicativo para descobrir se isso realmente importa ou não. Provavelmente, se um banco de dados SQL em processo não for suficiente para um aplicativo não simultâneo, é mais provável que você o esteja usando de maneira ineficiente, e não devido a problemas de desempenho no próprio gerenciamento de relacionamento.