Согласованность данных между несколькими микросервисами, которые дублируют данные

#database #transactions #microservices #data-consistency

#База данных #транзакции #микросервисы #согласованность данных

Вопрос:

В настоящее время я пытаюсь разобраться в архитектуре микросервисов, и я столкнулся с проблемой согласованности данных. Я читал, что дублирование данных между несколькими микросервисами считается хорошей идеей, потому что это делает каждый сервис более независимым.

Однако я не могу понять, что делать в следующем случае, чтобы обеспечить согласованность:

  1. У меня есть служба поддержки клиентов, в которой есть метод RegisterCustomer.
  2. Когда я регистрирую клиента, я хочу отправить сообщение через RabbitMQ, чтобы другие службы могли получать эту информацию и сохранять в своей базе данных.

Мой код выглядит примерно так:

              ...
            _dbContext.Add(customer);
            CustomerRegistered e = Mapper.Map<CustomerRegistered>(customer);
            await _messagePublisher.PublishMessageAsync(e.MessageType, e, "");
            //!!app crashes
            _dbContext.SaveChanges();
            ...
  

Итак, я хотел бы знать, как я могу справиться с таким случаем, когда приложение отправляет сообщение, но не может сохранить сами данные? Конечно, я мог бы поменять местами методы DbContextSave и PublishMessage, но проблема все еще существует. Что-то не так с моим подходом к хранению данных?

Ответ №1:

ДА. Вы выполняете двойную сохраняемость — сохраняемость в БД и долговременную очередь. Если один завершится успешно, а другой завершится неудачей, у вас всегда будут проблемы. Есть несколько способов справиться с этим:

  1. Сохраняйте в БД, а затем измените сбор данных (CDC) таким образом, чтобы данные из журнала предварительной записи БД (WAL) использовались для создания материализованного представления во второй службе DB с использованием потоковой передачи в реальном времени

  2. Сохраняется в долговременной очереди и кэше. Используя потоковую передачу в реальном времени, сохраняйте данные в обеих службах. Считывать данные из кэша, если данные доступны в кэше, в противном случае считывать из базы данных. Это позволит выполнять чтение после записи. Даже если в худшем случае произойдет сбой записи в кэш, в течение нескольких секунд данные будут в БД посредством потоковой передачи

Ответ №2:

NServiceBus действительно поддерживает длительную распределенную транзакцию во многих сценариях по сравнению с RMQ. Возможно, вы можете рассмотреть возможность использования этой функции, чтобы гарантировать, что оба контекста сохраняются или откатываются вместе в случае сбоев, если вы можете использовать NServiceBus вместо RMQ.

Ответ №3:

Я думаю, что решение, которое вы ищете, — это шаблон исходящих, в той же базе данных, что и ваши бизнес-данные, есть таблица базы данных, связанная с событием, это позволяет зафиксировать их в той же транзакции базы данных, а затем фоновый рабочий цикл отправляет событие в mq