正如上面提到的其他答案,您不能防止來自SQS的重複消息。
大多數情況下,您的郵件將交給您的消費者一次,但您將在某個階段會出現重複。
我不認爲這個問題有一個簡單的答案,因爲它需要提出一個適當的架構來處理重複,這意味着它在自然界是冪等的。
如果分佈式架構中的所有工作者都是冪等的,那很容易,因爲您不需要擔心重複。但實際上,這種環境並不存在,在某種程度上無法應對。
我目前正在研究一個需要我解決這個問題的項目,並且提出了一個處理它的方法。我認爲這可能會使其他人分享我的想法。它可能是一個很好的地方,可以對我的想法獲得一些反饋。
事實存儲
這讓他們收集理論上可以重播重現所有受影響的下游系統相同狀態的事實,開發服務心中有數。
例如,假設您正在爲股票交易平臺構建消息代理。 (我之前實際上曾在這樣一個項目上工作過,這很可怕,但也是一個很好的學習經歷。)
現在,讓我們說,是交易進來,並有3個系統感興趣:
- 一個老派的主機,其需要保持更新
- 是整理所有的行業和系統與FTP服務器
- 記錄該交易,並重新分配股份的新主人
這是一個有點令人費解的服務於合作伙伴分享,I K現在,但這個想法是,一個消息(事實)進來,有各種分佈式下游影響。
現在我們假設我們維護一個事實存儲庫,記錄所有進入我們經紀人的交易。而且所有3家下游服務業主都打電話告訴我們,他們已經丟失了過去3天內的所有數據。 FTP下載3天后,大型機落後3天,所有交易都落後3天。
因爲我們有事實存儲,所以理論上我們可以重放所有這些消息,從某個時間到某個時間。在我們的例子中,這將從3天前到現在。下游服務可能會受到影響。
這個例子可能看起來有點過頭了,但我試圖傳達一些非常特別的東西:事實是重要的事情要跟蹤,因爲這是我們將在我們的架構中用來戰鬥重複的地方。
的事實存儲如何幫助我們提供您實現一個持久層,讓你的CAP theorem,一致性和可用性的CA部分的事實存儲重複的消息
,您可以執行以下操作:
一旦收到來自隊列的消息,就會檢查事實存儲庫中是否已經看到過此消息,並且如果有的話,此時是否鎖定以及處於未決狀態。在我的例子中,我將使用MongoDB來實現我的事實存儲庫,因爲我對它很滿意,但其他各種數據庫技術應該能夠處理這個問題。
如果該事實尚不存在,則將其插入事實存儲中,具有掛起狀態和鎖定過期時間。這應該使用原子操作來完成,因爲您不希望這種情況發生兩次!這是您確保您的服務idempotence的地方。
快樂的情況下 - 偏偏大部分的時間
當事實存儲又回到了你的服務告訴它其實並不存在,而且一鎖被創建,該服務將嘗試做的工作。完成後,將刪除SQS消息,並將事實標記爲已完成。
重複消息
所以這時候一個消息來通過,這不是一個重複發生的事情。但是讓我們看看重複的消息何時進來。服務會將其提取出來,並要求事實存儲庫用鎖來記錄它。事實存儲庫告訴它它已經存在,並且它已被鎖定。該服務忽略消息並跳過它!一旦消息處理完成,另一名工作人員將從隊列中刪除此消息,並且我們不會再看到它。
災害的情況下 - 很少發生
當一個服務記錄了在店裏第一次的事實會發生什麼,然後得到一段時間的鎖定,但倒了?那麼SQS將再次向您顯示一條消息,如果它被提取,但在從隊列中提供一定時間內沒有被刪除。這就是爲什麼我們編寫我們的事實存儲庫,以便服務在有限的時間內保持鎖定。因爲如果崩潰了,我們希望SQS在稍後時間向服務或其另一個實例提供消息,從而允許該服務假定事實應該再次併入狀態(執行)。
[中SQS隊列使用了衆多消費者]的可能的複製(http://stackoverflow.com/questions/37472129/using-many-consumers-in-sqs-queue) – Krease
AWS現在提供[FIFO隊列(HTTP: //docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/FIFO-queues.html),它提供「精確的一次處理,但每秒只限於300次事務」。 – bishop