本文介紹如何使消息處理時長自適應。
背景信息
輕量消息隊列(原 MNS)的規范中,每條消息都有個默認的VisibilityTimeout,Worker在接收到消息后,Timeout就開始計時了。 如果Worker在Timeout時間內沒能處理完消息,那么消息就有可能被其他Worker接收到并處理。
Timeout計時的好處在于消息處理完之后需要顯式地DeleteMessage,那么如果Worker進程停止等情況發生,這條消息還有機會被其他Worker處理。
一些用戶會將隊列的默認VisibilityTimeout設置得比較長,以確保消息在被Worker處理完之前不會超時釋放。
問題描述
隊列的VisibilityTimeout是6個小時。
一個Worker接收到了消息M1,但是Worker在處理完消息之后,進程發生了Crash或者機器發生了重啟。
那么M1這條消息至少在6個小時之后才會被另一個Worker接收到并處理。而自己寫代碼處理Failover的情況的話,程序又會變得比較復雜。
目標
在一些即時性要求比較高,并且又希望盡快響應每一條消息的場景下,用戶會希望:
- 隊列的VisibilityTimeout比較短,例如5分鐘。在發生了進程Crash后,最多5分鐘,未處理完的消息就會被某個Worker接收到并處理。
- Worker處理消息的過程中,耗時很有可能超過5分鐘,那么消息在被處理的過程中不能超時。
解決方案
BestPractice的C# Demo可以實現這樣的場景。Demo下載地址為Sample。具體的做法是,在Worker處理消息的過程中,為消息定期檢查是否需要做ChangeVisibility,Worker處理完之后依然是主動deleteMessage。
遇到Demo使用問題,可提交工單處理。
下面是對于程序的幾點說明:
- 運行前需要填寫accessId、accessKey、EndPoint。
- 變量說明:
- MessageMinimalLife是消息注冊時必須有的最少的Life長度。需要這個的原因是,例如消息register的時候已經只剩下0.1秒的超時時間了,注冊進來也來不及ChangeVisibility延長生命。所以,MessageMinimalLife是為了確保消息能活到被ChangeVisibility,用戶可以自己根據業務壓力來設置。
- TimerInterval是Manager內部的Timer的Interval。只需要確保在Message到達MessageMinimalLife之前,Timer會被啟動就足夠了。時間可以設置得比較短(檢查得就比較頻繁)。
- QueueMessageVisibilityTimeout是Sample里Message的默認超時時間,是Queue的屬性。Sample里每次ChangeVisibility的時候,會把消息的VisibilityTimeout設置為QueueMessageVisibilityTimeout,所以它的值需要大于TimerInterval+ MessageMinimalLife,以確保消息不會超時。
- MessageTimeout是Message在Manager里面的超時時間,例如某個Worker卡住了,消息在5個小時之后依然沒有處理完畢(假設5個小時遠遠超出消息的正常處理時間),那么Manager就不會再為消息做ChangeVisibility了,會放任消息的Visibility超時。
- 流程說明:
- Worker在ReceiveMessage之后,會先做RegisterMessage,然后處理Message,最后再調用Manager的deleteMessage。
- Manager在消息第一次注冊進來之后,調用ThreadPool調度一個ChangeVisibilityTask檢查是否需要ChangeVisibility,并且把Message加到內部的messages列表中。
- Manager內部的Timer,會定時調用Parallel啟動 ChangeVisibilityTask檢查messages列表里的所有message。
- Manager.ChangeMessageVisibility (ChangeVisibilityTask)相關的具體事情,在流程圖里有顯示。流程圖如下:
文檔內容是否對您有幫助?