2009-07-20 86 views
4

我有一個處理多個客戶端郵件的多線程Windows服務的設計問題。 規則是如何設計處理郵件到達隊列中的服務

  • 每個消息是處理的東西的實體(具有一個唯一的ID),並且可以是不同的即的DoA,DOB,DOC等實體id的消息的有效載荷。
  • 處理過程可能需要一些時間(長達幾秒鐘)。
  • 消息必須按照它們到達每個實體(具有相同ID)的順序進行處理。
  • 消息然而,可以爲另一實體(只要它們不相同的實體ID即)
  • 處理的同時沒有並行處理的是可配置的(一般爲8)
  • 消息可以不會丟失。如果在處理消息時出現錯誤,則該消息和同一實體的所有其他消息必須被存儲以供將來手動處理。
  • 消息到達事務性MSMQ隊列。

您將如何設計服務。我有一個工作解決方案,但想知道其他人如何解決這個問題。

+0

你有多少個不同的實體(和實體類型)? – 2010-02-11 09:13:55

+0

每天約5000個實體(超過100萬個實體)。音量&沒有。會很快加倍。該消息僅包含實體標識和操作類型以及每個操作的數據。約20種不同的操作類型。 – softveda 2010-02-20 23:59:51

+0

也許有一個MessageReceiver將消息分派給線程池中的不同可用線程?如前所述,擁有由DateTimeReceived排序的XML序列化流將幫助您按時間順序執行,然後將此流傳遞給可用的線程。 – 2010-02-27 11:18:32

回答

0

我的做法是以下幾點:

  1. 使用可配置的線程數創建一個線程池。
  2. 保持實體標識的映射並將每個標識與一個消息隊列相關聯。
  3. 當您收到一條消息時,將其放入相應實體ID的隊列中。
  4. 每個線程只會查看專用於它的實體id(例如,創建一個類,該類被初始化爲這樣的Service(EntityID id))。
  5. 讓線程只處理其專用實體ID隊列中的消息。
  6. 一旦爲給定實體ID處理了所有消息,就從地圖中刪除該ID並退出該線程的循環。
  7. 如果線程池中有空間,則添加一個新線程來處理下一個可用的實體ID。

您必須管理當時無法處理的郵件,包括郵件處理失敗的情況。創建消息積壓等

如果您有權訪問併發映射(無鎖定/無等待映射),那麼您可以擁有多個讀寫器,無需鎖定或等待。如果您無法獲得併發地圖,那麼所有意外事件都將出現在地圖上:無論何時將消息添加到地圖中的隊列或添加新的實體ID都必須將其鎖定。最好的辦法是將地圖包裝在一個結構中,該結構提供適當鎖定的讀寫方法。

我不認爲你會看到任何鎖定性能顯著影響,但如果你開始看到一個我會建議你創建你自己的自由鎖散列映射:http://www.azulsystems.com/events/javaone_2007/2007_LockFreeHash.pdf

實現這個系統不會發生是一項基本任務,因此請將我的意見作爲一般指導原則......工程師需要實施適用的思路。

0

儘管我的要求與您的要求不同,但我確實必須處理來自消息隊列的併發處理。我的解決方案是有一個服務,它將查看每個傳入消息並將其交給代理進程使用。該服務具有一個設置,用於控制可以運行的代理程序數量。

0

我會看看每個從單個線程安全隊列中讀取的n個線程。然後,我會散列EntityId來決定巫女隊列上的一個輸入消息。

有些時候,有些線程無能爲力,但如果你有幾個線程,然後CPUs,這是一個問題?

(你也可能希望集團的entites按類型分爲隊列,從而減少你的數據庫鎖定conflits數)

1

你要做的第一件事就是退一步,考慮一下這個應用程序的性能有多關鍵。你真的需要併發地處理消息嗎?這是關鍵任務嗎?或者你只是認爲你需要它嗎?你有沒有在你的服務上運行一個分析器來查找過程的真正瓶頸並優化它們?

我之所以這樣問,是因爲你提到你想8個併發procceses - 但是,如果你讓這個程序單線程的,這將大大降低複雜&研究與開發&測試時間......而且因爲只有你想要8,它似乎不值得...

其次,因爲你只能在同一個實體上進行併發消息 - 你多久會得到來自客戶端的併發請求來處理同一個實體?值得爲可能不經常出現的用例添加如此多的複雜層次嗎?

我會吻。我會通過WCF使用MSMQ,並將我的WCF服務保持爲單例。現在您擁有了強大的功能,訂購了MSMQ的可靠性,您現在可以滿足您的實際需求。然後,我會用高實際數據在高負載下測試它,然後運行分析器查找瓶頸如果我發現它太慢了。只有這樣,我纔會經歷構建更復雜的應用程序以管理僅針對特定用例的併發性的所有額外麻煩......

要考慮的一種設計是創建中央「門衛」或「服務總線」服務誰收到來自客戶端的所有消息,然後將這些消息傳遞給實際的工作服務。當他收到請求時,他會發現他的另一個客戶是否已經爲同一個實體發送了一條消息 - 如果是的話,他會將它發送給他發送另一條消息的同一個服務。通過這種方式,您可以同時爲給定的實體處理相同的消息,僅此而已......而且您可以輕鬆實現無縫擴展......但是,如果我絕對必須這樣做,並且通過分析和測試證明了這一點,而不是因爲'我們認爲我們需要它'(見YAGNI校長:))

相關問題