我正在爲需要大量同步請求並異步處理它們的項目設計服務器守護程序。我意識到這樣一個項目的規模,但我認真對待這個項目,並試圖在繼續之前做出明確的設計和計劃。在服務中處理傳入請求的體系結構
這裏是我的目標列表:
- 可擴展性 - 必須能夠並行架構在多個處理器,甚至多臺服務器。
- 能夠應對大量的並行連接。
- 如果單個請求需要很長時間才能處理,則不得導致阻塞問題。
- 請求響應週轉時間必須最小。
- 建在具有.NET框架
我提出的架構和流程是相當複雜的(會在C#寫這篇),所以這裏是我最初的設計圖表:
(和here it is on tinypic,如果它調整不好)
這個想法是,請求通過網絡進入(雖然我還沒有決定是否TCP或UDP將是最好的),並通過immediat只適用於高速負載平衡器。負載均衡器然後使用加權隨機數生成器來選擇請求隊列(RQ)以發出請求。權重來自每個隊列的大小。使用加權RNG的原因,而不是僅僅將請求放入最不忙碌的隊列中,是因爲它阻止了一個空的但被阻塞的隊列(由於掛起的請求)鎖定了整個服務器。如果所有RQ超過一定的大小,則負載均衡器將丟棄該請求,並將「服務器太忙」響應放入輸出隊列(OPQ)中 - 此部分未顯示在圖中。
每個隊列對應於一個線程,其親和性設置爲服務器上的一個CPU核心。這些線程是並行請求處理器的一部分,它處理來自每個隊列的請求。該請求被分爲三種類型之一:
立即 - 立即請求是,顧名思義,立即處理。
可推遲 - 延遲請求被認爲是低優先級。它們在低負載時立即進行處理,或者如果負載很高,則將其放入延遲請求隊列(DRQ)。負載均衡器從DRQ獲取這些延遲請求,將它們標記爲即時,然後將它們放回適當的RQ中。
定時 - 將定時請求及其目標時間戳放入定時請求隊列(TRQ)中。這些請求通常是由另一個請求產生的,而不是由客戶端明確發送。當超過請求時間戳時,下一個可用的請求處理器線程將使用它並對其進行處理。
當請求被處理時,數據可被獲取從鍵/值對的緩存在存儲器中,一個密鑰/值對的緩存或磁盤上,或從一個專用的SQL數據庫服務器。緩存的值將是BSON,索引將是一個字符串。我正在考慮使用Dictionary<T1,T2>
在內存中執行此操作,並使用btree(或類似的)來實現磁盤緩存。
當處理完成時創建響應,並將其放置到輸出隊列(OPQ)。一個循環然後消耗來自OPQ的響應,並通過網絡將它們傳回客戶端。如果OPQ達到其最大大小的80%,則四分之一的請求處理器線程將暫停。如果OPQ達到其最大大小的90%,則一半的請求處理器線程將暫停。如果OPQ達到其最大大小,則所有請求處理器線程都會暫停。這將通過一個信號量來實現,該信號也應該阻止個別請求處理器線程被阻塞並且留下陳舊的請求。
我要找的是在幾個方面的建議:
- 是否有任何大的紕漏,以這個架構,我錯過了什麼?
- 有什麼我應該考慮改變的性能原因?
- TCP或UDP會更適合於請求嗎?獲得TCP提供的「交付證明」會非常有用,但UDP的輕量級特性也很吸引人。
- 在處理Windows服務器上的100k +同時連接時,我需要考慮哪些特殊事項?我知道Linux的TCP堆棧很好,但我不太確定Windows。
- 我還有其他問題要問嗎?我忘了考慮什麼?
我知道這是一個很多的閱讀,可能是相當多問了,所以感謝您的時間。
更新版本圖here的。
這是怎麼去項目/那怎樣?任何博客文章呢?我非常有興趣聽到你們沿途學到了什麼,以及你們得出了什麼結論。 – Tyson