Редактировал(а) Alexandr Fokin 2024/06/12 16:21

Скрыть последних авторов
Alexandr Fokin 5.8 1 | |(% style="width:929px" %)Ситуация:
Alexandr Fokin 5.3 2 Имеется очередь, из которой приложение читает данные и обрабатывает их. Рассмотрим пример, что приложение имеет следующий цикл обработки сообщения:
Alexandr Fokin 2.1 3 1) Взять сообщение из очереди
4 2) Попытаться выполнить некоторый набор действий на основе данных из сообщения.
Alexandr Fokin 5.8 5 Отметим, что обработка сообщения может завершиться как успешно, так и с ошибкой.|(% style="width:539px" %)
6 | |(% style="width:929px" %)1]
Alexandr Fokin 2.1 7 1) Получаем сообщение
Alexandr Fokin 5.3 8 2) Выполняем коммит сообщения (при следующем чтении на вход пойдет следующее сообщение)
Alexandr Fokin 5.8 9 3) Выполняем обработку|(% style="width:539px" %)Мы теряем сообщение, в случае если его обработка не завершилась успешно.
10 | |(% style="width:929px" %)2]
Alexandr Fokin 2.1 11 1) Получаем сообщение
12 2) Выполняем обработку
Alexandr Fokin 5.8 13 3) Если п.2 выполнен успешно, то выполняем коммит сообщения (при следующем чтении на вход пойдет следующее сообщение)|(% style="width:539px" %)В случае, если после выполнения 2 пункта наше приложение упадет (не успев выполнить пункт 3), то при повторном запуске мы обработаем то-же самое сообщение второй раз.
14 | |(% style="width:929px" %)(((
Alexandr Fokin 2.1 15 Вопросы
16 1) Является ли повторная обработка одного и того же сообщения допустимой для нашей системы.
Alexandr Fokin 5.1 17 2) Является ли потеря данных из одного из сообщений критичной для нашей системы.
Alexandr Fokin 5.3 18 3) Возможно в нашей системе производитель сообщение, генерирует сообщени3) Возможно в нашей системе производитель сообщение, генерирует сообщен3) Возможно в нашей системе производитель сообщение, генерирует сообщение повторно через некоторой промежуток времени, если фиксирует, что предыдущее сообщение не было обработано.
Alexandr Fokin 5.8 19 )))|(% style="width:539px" %)
20 | |(% style="width:929px" %)Более надежное, но более тяжелое решение:
21 Использование подхода номер 2 совместно с каким-либо более продвинутым механизмом транзакций. Т.е в случае падения приложения транзакция не будет завершена успешно.
Alexandr Fokin 4.1 22 Но есть риск если у нас выполняются 2 действия:
Alexandr Fokin 3.1 23 1) коммит транзакции в базе, 2) коммит сообщения. (или в порядке 2, 1)
24 В случае падения приложения между указанными шагами, мы все равно можем получить
Alexandr Fokin 5.3 25 либо потерю сообщения (закоммитили сообщение, но не завершили транзакцию),
Alexandr Fokin 4.1 26 либо повторную обработку (завершили транзакцию, но не закоммитил сообщение).
Alexandr Fokin 5.8 27 Хоть и вероятность такого события в целом крайне мала. (зависит от системы)|(% style="width:539px" %)
28 | |(% style="width:929px" %)(((
Alexandr Fokin 5.3 29 Замечание: на текущий момент отношу проблему к [[Dual write problem>>doc:Архитектура и модели.Группа\. Распределенные системы.Распределенные системы\. Консистентность.Dual write problem.WebHome]].
Alexandr Fokin 5.5 30 По хорошему у каждого запроса или хотя бы сообщения должен быть уникальный ключ. Использую его, транзакцию, таблицу с уникальным индексом можно добиться гарантии, что сообщение будет обработано только единожды. Транзакция БД позволяет атомарно зафиксировать и изменения и факт обработки сообщения (по его ключу).
Alexandr Fokin 2.1 31
Alexandr Fokin 5.4 32 Отдельный вопрос: хотим ли мы использовать очередь для приостановки обработки в случае ошибок. Зачастую мы не хотим останавливать обработку из-за одной ошибки. В таком случае важно сохранить проблемное сообщение, но при этом сделать так чтобы обработчик продолжил обрабатывать последующие сообщения.
33
Alexandr Fokin 5.3 34 Возможен вариант, когда сообщение просто записывается в БД в статусе ожидает обработку. И фоновый обработчик разбирает таблицу и обрабатывает необходимые строки.
Alexandr Fokin 5.8 35 )))|(% style="width:539px" %)
Alexandr Fokin 2.1 36
Alexandr Fokin 5.3 37