3

我正在爲需要大量同步請求並異步處理它們的項目設計服務器守護程序。我意識到這樣一個項目的規模,但我認真對待這個項目,並試圖在繼續之前做出明確的設計和計劃。在服務中處理傳入請求的體系結構

這裏是我的目標列表:

  • 可擴展性 - 必須能夠並行架構在多個處理器,甚至多臺服務器。
  • 能夠應對大量的並行連接。
  • 如果單個請求需要很長時間才能處理,則不得導致阻塞問題。
  • 請求響應週轉時間必須最小。
  • 建在具有.NET框架

我提出的架構和流程是相當複雜的(會在C#寫這篇),所以這裏是我最初的設計圖表:

Architecture Flow Chart

(和here it is on tinypic,如果它調整不好)

這個想法是,請求通過網絡進入(雖然我還沒有決定是否TCP或UDP將是最好的),並通過immediat只適用於高速負載平衡器。負載均衡器然後使用加權隨機數生成器來選擇請求隊列(RQ)以發出請求。權重來自每個隊列的大小。使用加權RNG的原因,而不是僅僅將請求放入最不忙碌的隊列中,是因爲它阻止了一個空的但被阻塞的隊列(由於掛起的請求)鎖定了整個服務器。如果所有RQ超過一定的大小,則負載均衡器將丟棄該請求,並將「服務器太忙」響應放入輸出隊列(OPQ)中 - 此部分未顯示在圖中。

每個隊列對應於一個線程,其親和性設置爲服務器上的一個CPU核心。這些線程是並行請求處理器的一部分,它處理來自每個隊列的請求。該請求被分爲三種類型之一:

  1. 立即 - 立即請求是,顧名思義,立即處理。

  2. 可推遲 - 延遲請求被認爲是低優先級。它們在低負載時立即進行處理,或者如果負載很高,則將其放入延遲請求隊列(DRQ)。負載均衡器從DRQ獲取這些延遲請求,將它們標記爲即時,然後將它們放回適當的RQ中。

  3. 定時 - 將定時請求及其目標時間戳放入定時請求隊列(TRQ)中。這些請求通常是由另一個請求產生的,而不是由客戶端明確發送。當超過請求時間戳時,下一個可用的請求處理器線程將使用它並對其進行處理。

當請求被處理時,數據可被獲取從鍵/值對的緩存在存儲器中,一個密鑰/值對的緩存或磁盤上,或從一個專用的SQL數據庫服務器。緩存的值將是BSON,索引將是一個字符串。我正在考慮使用Dictionary<T1,T2>在內存中執行此操作,並使用btree(或類似的)來實現磁盤緩存。

當處理完成時創建響應,並將其放置到輸出隊列(OPQ)。一個循環然後消耗來自OPQ的響應,並通過網絡將它們傳回客戶端。如果OPQ達到其最大大小的80%,則四分之一的請求處理器線程將暫停。如果OPQ達到其最大大小的90%,則一半的請求處理器線程將暫停。如果OPQ達到其最大大小,則所有請求處理器線程都會暫停。這將通過一個信號量來實現,該信號也應該阻止個別請求處理器線程被阻塞並且留下陳舊的請求。

我要找的是在幾個方面的建議:

  • 是否有任何大的紕漏,以這個架構,我錯過了什麼?
  • 有什麼我應該考慮改變的性能原因?
  • TCP或UDP會更適合於請求嗎?獲得TCP提供的「交付證明」會非常有用,但UDP的輕量級特性也很吸引人。
  • 在處理Windows服務器上的100k +同時連接時,我需要考慮哪些特殊事項?我知道Linux的TCP堆棧很好,但我不太確定Windows。
  • 我還有其他問題要問嗎?我忘了考慮什麼?

我知道這是一個很多的閱讀,可能是相當多問了,所以感謝您的時間。

更新版本圖here的。

+0

這是怎麼去項目/那怎樣?任何博客文章呢?我非常有興趣聽到你們沿途學到了什麼,以及你們得出了什麼結論。 – Tyson

回答

2

也可以考慮以下幾點:

  • 故障轉移。您可以設計一種方法來保留請求,同時可能的服務崩潰,以便即使在服務重新啓動後仍會處理所有待處理的請求。
  • 錯誤隊列。 (也稱爲Dead Letter Channel圖案)
  • Pipes and Filters。通過提供此類功能,您將獲得服務的高度靈活性和可擴展性。
  • 請求確認。在某個預定義的時間間隔內,向服務發送請求並等待Ack消息的客戶端(其CorrelationId設置爲初始RequestId),以這種方式服務可以通知客戶端特定請求已收到並放入入站隊列,如果客戶端沒有接收剛剛發送的請求確認 - 它可以重新發送或標記爲失敗。

PS:另外我建議大書「Enterprise Integration Patterns

+0

這是故障轉移的一個優點。由於每個實例都將在單獨的服務器上運行,因此我將在它們之間進行負載平衡(無論哪個請求被髮送到哪個服務器),並且只要服務器關閉就重新平衡它。但是,我並沒有考慮對待處理的請求做些什麼。也許我應該保留它們在磁盤上的副本,以防守護程序崩潰,但是如果整個機器出現故障,請考慮丟失的請求?任何更好的想法? – Polynomial

+0

只是爲了澄清:所需的響應時間將意味着如果實際服務器出現故障,重新啓動時間太長,請求仍然相關,因此我必須拋棄磁盤隊列。 – Polynomial

0

如果你想要這個擴展得很好,你需要確保所有的組件都是可擴展的 - 處理元素,輸入/輸出件和隊列。如果您打算在Microsoft堆棧上執行此操作,我會認真推薦查看Windows Azure,它提供了大部分(如果不是全部)您需要的關鍵功能。有一件事你沒有提到 - 是否會有一個持久存儲層(例如數據庫)?如果是這樣,準備好擴展,否則它將成爲你的單點失敗。

+0

數據庫顯示在圖中,並在我的問題中提到。我也不想使用Azure,因爲我寧願讓我的應用程序執行邏輯。這是因爲我希望它可以安裝在一系列不同的主機(包括客戶主機)上,並將它們作爲自己的實例或作爲共享實例的一部分。 – Polynomial

+0

對不起 - 圖片被我當前的位置阻止,並且我在文章中遺漏了數據庫引用。至於「我的應用程序正在執行邏輯」,我沒有看到如何使用Azure的可伸縮性功能消除了調整邏輯的能力。安裝在客戶主機上的應用程序可以使用「通用」實例,或使用單獨的帳戶來「安裝」其私有化。 –

+0

我的意思是我希望某些客戶能夠在不需要購買或安裝Azure的情況下運行我的服務器的「農場」。我也想遠離昂貴的軟件依賴。 – Polynomial

1

我不明白你爲什麼需要多個請求隊列。在我看來,只需要一個請求隊列,許多處理器都從中讀取數據。它不應該是任何隊列系統的問題。只有一個隊列將來自處理器的輸入解耦,從而實現更好的可擴展性 - 在需要時啓動更多處理器,而沒有人需要關心它。

至於TCP與UDP - 你在尋找什麼樣的性能?使用ZeroMQ等現有通信基礎設施爲您處理這些技術問題不是更好嗎?

Itay。你

+0

有多個請求隊列的想法源於我關於專門化某些隊列以優先考慮請求類型的一個子集的想法。這應該讓我調整我的代碼,使處理某些消息類型更快一點。在TCP/UDP /其他方面,我不太確定我需要什麼。我想直接與網絡協議接口,但這意味着我僅限於任何.NET支持(這幾乎只是TCP和UDP)。 – Polynomial

+0

我不會去那裏。如果您的隊列支持優先級(某些隊列系統可以,我不記得MSMQ是否支持),那麼您就是免費的。 總的來說,我認爲你正在嘗試重塑很多已經發明的東西 - 並且是開源的。在我開始通過網絡實施之前,我會真正考慮幾個現有的排隊系統。也看看WCF,但我不確定它是如何面向性能的。 – zmbq

+0

也許我應該保留多個隊列,但只是用它們來存儲不同的消息優先級。這樣我就可以將我的負載均衡器移動到隊列的另一端,並簡化流程中的大量內部工作。 – Polynomial

相關問題