Eu sei que existem perguntas semelhantes aqui, mas elas estão me dizendo para voltar aos sistemas RDBMS regulares se eu precisar de transações ou usar operações atômicas ou confirmação de duas fases . A segunda solução parece a melhor escolha. O terceiro que não desejo seguir, porque parece que muitas coisas podem dar errado e não posso testá-lo em todos os aspectos. Estou tendo dificuldade em refatorar meu projeto para executar operações atômicas. Não sei se isso vem do meu ponto de vista limitado (só trabalhei com bancos de dados SQL até agora) ou se realmente não pode ser feito.
Gostaríamos de testar o MongoDB em nossa empresa. Escolhemos um projeto relativamente simples - um gateway SMS. Ele permite que nosso software envie mensagens SMS para a rede celular e o gateway faz o trabalho sujo: na verdade, comunicando-se com os provedores por meio de diferentes protocolos de comunicação. O gateway também gerencia o faturamento das mensagens. Todo cliente que solicita o serviço precisa comprar alguns créditos. O sistema diminui automaticamente o saldo do usuário quando uma mensagem é enviada e nega o acesso se o saldo for insuficiente. Também porque somos clientes de provedores de SMS de terceiros, também podemos ter nossos próprios saldos com eles. Temos que acompanhar isso também.
Comecei a pensar em como posso armazenar os dados necessários com o MongoDB se reduzir alguma complexidade (cobrança externa, envio de SMS em fila). Vindo do mundo SQL, eu criaria uma tabela separada para usuários, outra para mensagens SMS e outra para armazenar as transações relacionadas ao saldo dos usuários. Digamos que eu crie coleções separadas para todos aqueles no MongoDB.
Imagine uma tarefa de envio de SMS com as seguintes etapas neste sistema simplificado:
verifique se o usuário possui saldo suficiente; negar acesso se não houver crédito suficiente
envie e armazene a mensagem na coleção do SMS com os detalhes e o custo (no sistema
status
ativo , a mensagem teria um atributo e uma tarefa a buscaria para entrega e definiria o preço do SMS de acordo com seu estado atual)diminuir o saldo do usuário pelo custo da mensagem enviada
registrar a transação na coleção de transações
Agora, qual é o problema com isso? O MongoDB pode fazer atualizações atômicas apenas em um documento. No fluxo anterior, pode acontecer que algum tipo de erro entre e a mensagem seja armazenada no banco de dados, mas o saldo do usuário não é atualizado e / ou a transação não é registrada.
Eu vim com duas idéias:
Crie uma única coleção para os usuários e armazene o saldo como um campo, transações e mensagens relacionadas ao usuário como sub-documentos no documento do usuário. Como podemos atualizar documentos atomicamente, isso realmente resolve o problema da transação. Desvantagens: se o usuário enviar muitas mensagens SMS, o tamanho do documento poderá aumentar e o limite de 4 MB poderá ser atingido. Talvez eu possa criar documentos históricos em tais cenários, mas não acho que seja uma boa ideia. Também não sei quão rápido o sistema seria se eu enviasse cada vez mais dados para o mesmo grande documento.
Crie uma coleção para usuários e outra para transações. Pode haver dois tipos de transações: compra de crédito com alteração positiva do saldo e mensagens enviadas com alteração negativa do saldo. A transação pode ter um subdocumento; por exemplo, nas mensagens enviadas, os detalhes do SMS podem ser incorporados na transação. Desvantagens: eu não armazeno o saldo atual do usuário, por isso tenho que calculá-lo toda vez que um usuário tenta enviar uma mensagem para saber se a mensagem pode passar ou não. Receio que esse cálculo possa ficar lento à medida que o número de transações armazenadas aumenta.
Estou um pouco confuso sobre qual método escolher. Existem outras soluções? Não consegui encontrar práticas recomendadas on-line sobre como solucionar esses tipos de problemas. Eu acho que muitos programadores que estão tentando se familiarizar com o mundo NoSQL estão enfrentando problemas semelhantes no começo.