У нас аналогичные задачи возникают. В идеале хотелось бы что-то похожее на такие слои:
— есть PostgreSQL в кластере. Ее настройкой занимаются администраторы баз данных. Они поддерживают конфигурацию и docker-compose файл для ее запуска.
— на следующем слое у нас система управления процессами (Taskurotta). Ей нужна база данных для работы. У нее свои владельцы. У них свой docker-compose для разворачивания системы в кластере. При этом база данных для этих людей может быть черным ящиком. Достаточно compose файл БД подгрузить к проекту, например, с помощью git submodules указав требуемую версию и они вместе стартанут. Владельцы этой системы запускают автоматические тесты на данном окружении.
— на следующем уровне абстракции есть прикладные микросервисы которым нужна Taskurotta которой нужна база данных. Они так-же пишут автоматические тесты и хотят использовать нужной версии систему управления процессами. И как черный ящик, потому как владельцы не они и им достаточно чтобы система была доступна по нужному порту. И групп таких микросервисов много со своими владельцами.
— на следующем уровне фронтенд разработка с REST сервисами, которым нужны несколько групп микросервисов, которым… которым нужен дом, который построил Джек :) Им уже тем более тяжело знать все нюансы настройки бэкенд систем. Им нужно свои тесты прогнать подключив бэкенд как черный ящик с торчащими на ружу точками взаимодействия.
На большом проекте в микросервисной архитектуре уже тяжело знать про всё. Хочется разделять всё на подсистемы со своими владельцами. Но при этом иметь возможность легко собрать окружения для выполнения автоматических тестов.
Сравнивать нужно для конкретных задач. Сравнивать фичи — дело неблагодарное, бесполезное и холиваное. Тем более без собственного багажа знаний по сравниваемым объектам.
Великую ценность имеют аргументы по использованию нужного инструмента в определенных условиях. Сравнения инструментов в вакууме не несут пользы.
Понятно что вы рассматриваете только попытку отправки сообщения в mq и транзакцию БД, а о гарантированном выполнении вы не заботитесь.
Мысль же была о том, что если операция важная (это не ваш случай), то на mq систему полагаться не стоит до определенной степени (даже если она приняла ваше сообщение). И тогда имеет смысл регистрация процессов на стороне системы отправителе для последующей переотправки.
Контекст этой ветки обсуждения о том, что MQ может быть не достаточно надежным и соответственно вариант с промежуточной очередью не рассматривается. Надо городить журнал (очередь) на стороне системы.
Поняно. У нас проблема в общей терминологии. Это не транзакция в каноническом смысле.
Если речь шла о том как продолжить процесс в MQ только после успешной транзакции в системе-отправителе, убрав таким образом возможные дубли процессов — то ваш метод решает задачу.
то список этих задач в итоге превратится в очередь. Проблемы с использованием SQL в качестве очереди я описал в конце статьи.
Конечно это так. Есть минусы. Вопрос только в контексте задачи. Если мы помещая эту задачу в SQL DB будем еще и вызывать MQ для старта процесса, а после отправки удалять, то в этой БД может быть не так много задач в итоге, требующих переотправки.
Второй хинт — это при переотправки одним потоком вытаскивать Только идентификаторы задач и по ним стартовать процесс в mq где уже пойдет распараллеливание с вытаскиванием аргументов задачи и т.д.
При таком подходе кролик осилит на обычном сервере более 1000 стартов процессов в секунду (помещений сообщений в очередь). Для задач где почтовое уведомление актуально хотя бы час (не сообщение с подтверждением регистрации), мы можем себе позволить переотправить минимум 3,6 миллиона сообщений в час.
Дружище! Так это самое главное — что вы жертвуете гарантированной отправкой уведомлений! Этого в явном виде нет в статье. Я это понял из комментариев и то не с первого раза.
Поясню контекст.
Обычно в рамках mq систем и взаимодействия с ними необходимо добиться гарантированного выполнения задачи. Отправка сообщения поэтому понимается как задача, которую нужно обязательно выполнить.
Заголовок статьи о транзакциях между mq и sql — что тоже подразумевает неизбежность выполнения или откат запланированных действий.
Применение термина идемпотентность в контексте отправки почты означает, что многократное повторение действия отправки эквивалентно однократному. Т.е. если отправляем почту данным получателям — то не важно сколько вызвался воркер, но все равно отправляем в итоге один раз. А у нас — или отправится или нет. И мы не знаем при повторах что делать а просто игнорируем дублирующиеся сообщения.
Все это привело в меня в непонимание.
Но Если мы жертвуем гарантированной отправкой сообщения — ситуация конечно меняется. Тогда вопрос стоит в выработки решения, где эти жертвы минимальны и от этого надо отталкиваться и это должно быть предметом анализа как мне кажется.
Первый воркер запишет его в БД, а второй удалит после отправки.
Ерунду я написал какую-то. Ничего это не снизит.
Итого: если уверенность достаточна в MQ — отправляйте сразу воркеру, отправляющему письма.
Если нет — то нужно более надежное место, куда можно сохранить задачу. И в случае отсутствия MQ переотправить ее позже. Или пассивный механизм — когда кто-то по шедулеру забирает задачи на выполнение с помощью MQ.
Далее отмечать выполнение (или удаление записи) в журнале по факту выполнения задачи.
Можно еще переотправлять в MQ если достигнут таймаут ожидания завершения задачи. В самом MQ задача на отправку сообщения может иметь TTL чтобы снизить количество дублей при длительном простое MQ.
Если мой тезис не верный и вы не пытаетесь обезопасить себя от неработающего MQ, то пусть генерит ваша система отправитель сообщение с уникальным идентификатором и отправляет сразу в MQ.
Первый воркер запишет его в БД, а второй удалит после отправки. Это ваша схема но с упращенной системой-отправителем. Этот подход может снизить вероятность повторной отправки но не предотвратит ее как и ваш описанный в статье.
1) но гарантируем, что один email не будет отправлен два раза.
2) то запись об email останется в невалидном статусе «Отправляется» (хотя если запись в этом статусе — есть вероятность, что email все таки отправился
Ваш подход не решает задачу первого требования. Отсюда вопрос — будет ли более простой подход менее надежным — сразу отправлять в целевую очередь. При этом меняется только описание первого вашего пункта на такое:
Получаем запись об email из БД (если ее там нет, значит транзакция [системы — отправителя] не была закомичена, и сообщение можно выбросить).
Все понял, спасибо. Перепутал что где ask'ается :)
В вашем примере не будет обеспечиваться однократная отправка почтового сообщения. Второй воркер может не смочь подтвердить отправку на шаге 2 и обработает это задание позже еще раз. Как это реализуется в исходной статье я тоже пока не понимаю.
Мне кажется системе-отправителю имеет смысл писать в свою БД идентификаторы сообщений перед отправкой в MQ только с одной целью — быть более устойчивой если MQ не работает или не отправит сообщение за разумное время. В этом случае переотправлять сообщения в MQ.
Наверное я что-то упустил. Перечитал еще раз и не помогло. Помогите разобраться пожалуйста.
Имеем — система получатель, которая использует идентификатор сообщения как идемпотентный ключ.
Имеем — система отправитель, которая генерит этот идентификатор сообщения.
Вопрос такой — почему система отправитель не отсылает сообщение сразу в целивую очередь?
Это для того чтобы все работало в ситуации недоступности MQ, где БД является более надежной? При этом мы помещаем идентификатор сообщения в БД и переотправляем сообщение в MQ по таймауту?
Отличное получится решение со средой из старого анегдота :)
Руководитель собрал коллектив в понедельник на летучку.
«Ну что, сегодня понедельник, надо отдохнуть от выходных, а во вторник надо уже втягиваться в работу. В среду придется поработать, а в четверг надо готовиться к выходным, ну а в пятницу короткий день. Вопросы есть?»
«Есть, а когда эта фигня со средой закончится?»
Возможно кто-то в душе археолог и историк, а кто-то изобретатель. Кто-то обладает усидчивостью необходимой для анализа, разбора и улучшения не новой, но востребованной программы, а есть другая крайность — у кого-то хватает терпения только свой код терпеть :) Все мы разные.
Видимо я не точно описал проблему. Имел ввиду увеличение в объеме самого JMS сообщения. Обработка данных происходит в памяти и на это нужно обращать внимание. Проблема еще более обостряется когда интегрированных систем становится много и соответственно много обработчиков данных работает в рамках одной JVM.
Если данные большие, то безопасней переместить их из одной систему в другую (например в файловую систему), обработать, и только потом направить дальше. Впрочем, ниже coriollon уточнил, что в его случае объем не превышает нескольких мегабайт в день и поэтому данный подход приемлем.
У нас аналогичные задачи возникают. В идеале хотелось бы что-то похожее на такие слои:
— есть PostgreSQL в кластере. Ее настройкой занимаются администраторы баз данных. Они поддерживают конфигурацию и docker-compose файл для ее запуска.
— на следующем слое у нас система управления процессами (Taskurotta). Ей нужна база данных для работы. У нее свои владельцы. У них свой docker-compose для разворачивания системы в кластере. При этом база данных для этих людей может быть черным ящиком. Достаточно compose файл БД подгрузить к проекту, например, с помощью git submodules указав требуемую версию и они вместе стартанут. Владельцы этой системы запускают автоматические тесты на данном окружении.
— на следующем уровне абстракции есть прикладные микросервисы которым нужна Taskurotta которой нужна база данных. Они так-же пишут автоматические тесты и хотят использовать нужной версии систему управления процессами. И как черный ящик, потому как владельцы не они и им достаточно чтобы система была доступна по нужному порту. И групп таких микросервисов много со своими владельцами.
— на следующем уровне фронтенд разработка с REST сервисами, которым нужны несколько групп микросервисов, которым… которым нужен дом, который построил Джек :) Им уже тем более тяжело знать все нюансы настройки бэкенд систем. Им нужно свои тесты прогнать подключив бэкенд как черный ящик с торчащими на ружу точками взаимодействия.
На большом проекте в микросервисной архитектуре уже тяжело знать про всё. Хочется разделять всё на подсистемы со своими владельцами. Но при этом иметь возможность легко собрать окружения для выполнения автоматических тестов.
Для продуктивного спора нужен контекст а не набор фич.
Великую ценность имеют аргументы по использованию нужного инструмента в определенных условиях. Сравнения инструментов в вакууме не несут пользы.
Мысль же была о том, что если операция важная (это не ваш случай), то на mq систему полагаться не стоит до определенной степени (даже если она приняла ваше сообщение). И тогда имеет смысл регистрация процессов на стороне системы отправителе для последующей переотправки.
Если речь шла о том как продолжить процесс в MQ только после успешной транзакции в системе-отправителе, убрав таким образом возможные дубли процессов — то ваш метод решает задачу.
Конечно это так. Есть минусы. Вопрос только в контексте задачи. Если мы помещая эту задачу в SQL DB будем еще и вызывать MQ для старта процесса, а после отправки удалять, то в этой БД может быть не так много задач в итоге, требующих переотправки.
Второй хинт — это при переотправки одним потоком вытаскивать Только идентификаторы задач и по ним стартовать процесс в mq где уже пойдет распараллеливание с вытаскиванием аргументов задачи и т.д.
При таком подходе кролик осилит на обычном сервере более 1000 стартов процессов в секунду (помещений сообщений в очередь). Для задач где почтовое уведомление актуально хотя бы час (не сообщение с подтверждением регистрации), мы можем себе позволить переотправить минимум 3,6 миллиона сообщений в час.
Поясню контекст.
Обычно в рамках mq систем и взаимодействия с ними необходимо добиться гарантированного выполнения задачи. Отправка сообщения поэтому понимается как задача, которую нужно обязательно выполнить.
Заголовок статьи о транзакциях между mq и sql — что тоже подразумевает неизбежность выполнения или откат запланированных действий.
Применение термина идемпотентность в контексте отправки почты означает, что многократное повторение действия отправки эквивалентно однократному. Т.е. если отправляем почту данным получателям — то не важно сколько вызвался воркер, но все равно отправляем в итоге один раз. А у нас — или отправится или нет. И мы не знаем при повторах что делать а просто игнорируем дублирующиеся сообщения.
Все это привело в меня в непонимание.
Но Если мы жертвуем гарантированной отправкой сообщения — ситуация конечно меняется. Тогда вопрос стоит в выработки решения, где эти жертвы минимальны и от этого надо отталкиваться и это должно быть предметом анализа как мне кажется.
Ерунду я написал какую-то. Ничего это не снизит.
Итого: если уверенность достаточна в MQ — отправляйте сразу воркеру, отправляющему письма.
Если нет — то нужно более надежное место, куда можно сохранить задачу. И в случае отсутствия MQ переотправить ее позже. Или пассивный механизм — когда кто-то по шедулеру забирает задачи на выполнение с помощью MQ.
Далее отмечать выполнение (или удаление записи) в журнале по факту выполнения задачи.
Можно еще переотправлять в MQ если достигнут таймаут ожидания завершения задачи. В самом MQ задача на отправку сообщения может иметь TTL чтобы снизить количество дублей при длительном простое MQ.
Первый воркер запишет его в БД, а второй удалит после отправки. Это ваша схема но с упращенной системой-отправителем. Этот подход может снизить вероятность повторной отправки но не предотвратит ее как и ваш описанный в статье.
1) но гарантируем, что один email не будет отправлен два раза.
2) то запись об email останется в невалидном статусе «Отправляется» (хотя если запись в этом статусе — есть вероятность, что email все таки отправился
Ваш подход не решает задачу первого требования. Отсюда вопрос — будет ли более простой подход менее надежным — сразу отправлять в целевую очередь. При этом меняется только описание первого вашего пункта на такое:
Получаем запись об email из БД (если ее там нет, значит транзакция [системы — отправителя] не была закомичена, и сообщение можно выбросить).
В вашем примере не будет обеспечиваться однократная отправка почтового сообщения. Второй воркер может не смочь подтвердить отправку на шаге 2 и обработает это задание позже еще раз. Как это реализуется в исходной статье я тоже пока не понимаю.
Мне кажется системе-отправителю имеет смысл писать в свою БД идентификаторы сообщений перед отправкой в MQ только с одной целью — быть более устойчивой если MQ не работает или не отправит сообщение за разумное время. В этом случае переотправлять сообщения в MQ.
Имеем — система получатель, которая использует идентификатор сообщения как идемпотентный ключ.
Имеем — система отправитель, которая генерит этот идентификатор сообщения.
Вопрос такой — почему система отправитель не отсылает сообщение сразу в целивую очередь?
Это для того чтобы все работало в ситуации недоступности MQ, где БД является более надежной? При этом мы помещаем идентификатор сообщения в БД и переотправляем сообщение в MQ по таймауту?
Руководитель собрал коллектив в понедельник на летучку.
«Ну что, сегодня понедельник, надо отдохнуть от выходных, а во вторник надо уже втягиваться в работу. В среду придется поработать, а в четверг надо готовиться к выходным, ну а в пятницу короткий день. Вопросы есть?»
«Есть, а когда эта фигня со средой закончится?»
Если данные большие, то безопасней переместить их из одной систему в другую (например в файловую систему), обработать, и только потом направить дальше. Впрочем, ниже coriollon уточнил, что в его случае объем не превышает нескольких мегабайт в день и поэтому данный подход приемлем.