LINUX.ORG.RU

Коммуникация микросервисов. Не пойму как правильно делать

 , ,


1

1

Допустим, есть микросервис1(мк1) и микросервис2(мк2), есть сервер сообщений rabbitmq(mq). Мк1 предоставляет апи, которое пишет в бд мк1 данные. После записи мк1 один должен отправить сообщение мк2. И тут вопросы:

  1. как быть, если мк2 лежит?
  2. как быть, если mq лежит?

Предполагаю, что мк1 должен при не отвечающем mq записать сообщение куда-то в базу, а потом какой-то воркер должен чекнуть то, что mq поднялся и отправить сообщение и удалить его из списка локальных сообщений. Но просто вот по этой логике(если mq лежит, то записываем сообщение локально, если не лежит - тогда отправляем) делать нельзя. Потому как тут появится такое событие:

  1. запрос1 выполнен: пытаемся отправить сообщение1
  2. mq лежит? Да!
  3. записываем сообщение1 в базу мк1(самого себя), чтобы отправить позже
  4. запрос2 выполнен: пытаемся отправить сообщение2
  5. mq лежит? Нет!
  6. отправляем сообщение2
  7. периодик воркер срабатывает и отправляет сообщение1

В итоге мы получаем, что сообщение2 отправлено быстрей, чем сообщение1. Это не правильно

А как вообще правильно выстраивать систему отправки сообщений, чтобы это всё правильно работало?

Ответ на: комментарий от JoyceGraham

Всё было бы так хорошо, если бы апи параллельно не выполнялись. А они выполняются. Тогда надо перед тем, как отправлять - блокировать сообщения, чтобы параллельно выполняющийся апи2 не продублировал то, что делает апи1

serg002 ()

как быть, если мк2 лежит?

Никак, не проблема, очередь для того и нужна.

как быть, если mq лежит?

Никак, очередь не лежит, в этом вся суть. Сделай кластер.

Если случилось что-то ужасное, и очередь таки лежит, сделай ещё несколько попыток, потом отменяй транзакцию, пиши в лог, что усё пропало, отвечай соответствующим образом на health check.

И не забывай, что БД у тебя тоже может лежать.

WitcherGeralt ★★ ()
Последнее исправление: WitcherGeralt (всего исправлений: 1)

4.1 а у нас есть сообщения в локальной базе?
4.1.1 если да, записать в локальную базу.
4.1.2 чего бы не гребнуть сообщения по таймстемпу и не отправить в нужном порядке.

system-root ★★★★★ ()

В итоге мы получаем, что сообщение2 отправлено быстрей, чем сообщение1. Это не правильно

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

alysnix ()

Если mq лежит, то при попытке что-то туда отправить (или еще раньше) твоё приложение свалится, ты не сможешь принимать запросы и все дальнейшие трепыхания бессмысленны. Если же ты допускаешь работу приложения при полудохлой инфраструктуре, то да, накапливай, разгребай воркерами, но это - дичь, брокер должен работать и продублирован раза на 3
Если лежит mk2, то сообщения падают в очередь, когда mk2 оживёт, то начнёт её разгребать.

В итоге мы получаем, что сообщение2 отправлено быстрей, чем сообщение1. Это не правильно

Так сделай велоочередь в мк1 и отправляй последовательно, когда mq поднимется.

crutch_master ★★★★★ ()

В итоге мы получаем, что сообщение2 отправлено быстрей, чем сообщение1. Это не правильно

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

Miguel ★★★★★ ()

как быть, если мк2 лежит?

Поднимать лапки и говорить пользователю, что всё плохо.

как быть, если mq лежит?

Накапливать сообщения? Нет! Тоже поднимать лапки и сознаться пользователю, что рулят сервером дятлы.

Это просто, честно и гарантирует консистентность данных. Всё остальное это чрезмерное усложнение и гипотетическая потеря данных, что недопустимо.

vtVitus ★★★★★ ()

сообщение2 отправлено быстрей, чем сообщение1. Это не правильно

Это пофиг. Перестановка не должна никак влиять. Если влияет - вот это неправильно.

В твоём сценарии сообщение2 и при нормально работающем mq может вперёд пролезть.

no-such-file ★★★★★ ()

Кластер из кроликов делай, можешь с бронебойностью (запись на диск очереди) и все. Пишешь один сервисом и читаешь другим.

То есть один сервис у тебя паблишер, а второй - подписчик.Подписчик не обязан всегда онлайн біть. Как и паблишер. Только очередь должна со 100% аптаймом жить.

Делаешь мониторинг на количество сообщений в очереди и спокойной живешь.

Много сообщений - лежит подписчик.

Долго нет сообщений («долго» у каждого свое и зависит от конкретного приложенька) - плохо паблишеру.

PunkoIvan ★★★★ ()

Как тут правильно уже ответили, да, очередь должна быть в кластере, таким образом, что аптайм очереди не меньше аптайма базы. Мы в команде делали ещё чтобы и сами сервисы были в кластере (docker swarm + несколько инстансов сервиса).

fulmar_lor ()