Как предотвратить дублирование сообщений SQS?

как лучше всего предотвратить дублирование сообщений в Amazon SQS? У меня есть SQS доменов, ожидающих обхода. прежде чем я добавлю новый домен в SQS, я могу проверить сохраненные данные, чтобы увидеть, был ли он недавно обведен, чтобы предотвратить дубликаты.

проблема заключается в доменах, которые еще не были просмотрены. Например, если в очереди 1000 доменов,которые не были обведены. Любая из этих ссылок может быть добавлена снова, и снова, и снова. Который раздувает мои SQS к сотням тысяч сообщений, которые в основном дублируются.

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

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

4 ответов


Как упоминалось в других ответах, вы не можете предотвратить дублирование сообщений, поступающих из SQS.

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

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

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

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

факт хранения

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

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

теперь предположим, что приходят сделки, и есть 3 системы, заинтересованные в этом:

  1. мэйнфрейм старой школы, который должен оставаться в курсе
  2. система, которая сопоставляет все сделки и делится ими с партнерами на FTP-сервере
  3. сервис, который регистрирует торговлю и перераспределяет акции новому владельцу

Это немного запутанно, я знаю, но идея в том, что одно сообщение (факт) приходит, имеет различные распределенные вниз по течению эффекты.

теперь давайте представим, что мы поддерживаем магазин фактов, запись всех сделок, поступающих в наш брокер. И что все 3 вниз по течению владельцы сервиса звонит нам, чтобы сказать нам, что они потеряли все свои данные за последние 3 дня. Скачивание по FTP 3 дня позади, универ 3 дней позади, и все сделки за 3 дня.

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

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

как магазин фактов помогает нам с дубликатами сообщений

при условии, что вы реализуете свой факт хранения на уровень сохраняемости, который дает вам части CA теорема CAP, согласованность и доступность, вы можете сделать следующее:

Как только сообщение получено из очереди, вы проверяете в своем хранилище фактов, видели ли вы это сообщение раньше, и если да, то заблокировано ли оно в данный момент и в состоянии ожидания. В моем случае я буду использовать MongoDB для реализации моего хранилища фактов, так как мне это очень удобно, но различные другие технологии БД должны быть в состоянии справиться с этим.

Если факт еще не существует, он вставляется в хранилище фактов с ожидающим состоянием и временем истечения блокировки. Это должно быть сделано с помощью атомарных операций, ведь вы не хотите, чтобы это произошло дважды! Здесь вы гарантируете, что ваш сервис idempotence.

счастливый случай-случается большую часть времени

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

дублировать

вот что происходит, когда приходит сообщение и это не дубликат. Но давайте посмотрим, когда придет дубликат сообщения. Служба поднимает его и просит магазин фактов записать его с помощью блокировки. То магазин говорит, что он уже существует, и что это запертый. Служба игнорирует сообщение и пропускает его! Как только обработка сообщения будет выполнена другим работником, он удалит это сообщение из очереди, и мы его больше не увидим.

случай катастрофы-случается редко

Итак, что происходит, когда служба записывает факт в первый раз в магазине, затем получает блокировку на определенный период, но падает? Ну SQS представит вам сообщение снова, если оно было подобрано, но не удалено в пределах определенный период после того, как его подали из очереди. Вот почему мы кодируем наш магазин фактов таким образом, что служба поддерживает блокировку в течение ограниченного времени. Потому что, если он падает, мы хотим, чтобы SQS представил сообщение службе или другой экземпляр позже, позволяя этой службе предположить, что факт должен быть включен в состояние (выполнен) снова.


нет способа уровня API для предотвращения дублирования сообщений, которые будут отправлены в очередь SQS. Боюсь, вам нужно будет справиться с этим на уровне приложения.

вы можете использовать таблицу DynamoDB для хранения доменных имен, ожидающих обхода, и добавлять их в очередь, только если они не находятся в DynamoDB, например.


поскольку вы не можете запретить SQS отправлять дублированные сообщения, Вы должны реализовать это на своей стороне. Один простой способ сделать это-использовать идемпотентных потребителей Apache Camel, см. http://camel.apache.org/idempotent-consumer.html


согласно AWS Docs,Exactly-Once Processing обеспечивает способ избежать дублирования сообщений.

В отличие от стандартных очередей, очереди FIFO не вводят дубликаты сообщения. Очереди FIFO помогают избежать отправки дубликатов в очередь. Если повторите действие SendMessage в течение 5-минутной дедупликации интервал, Amazon SQS не вводит никаких дубликатов в очередь.

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

https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html#cfn-sqs-queue-contentbaseddeduplication