2011-02-12 23 views
2

這兩個不同模型中的哪一個會更高效(考慮抖動,處理器緩存利用率,整體設計,所有內容等)?套接字服務器的高效重疊I/O

  1. 1 IOCP和旋轉X線程(其中X是計算機具有的處理器的數量)。這意味着我的「服務器」只有1個IOCP(隊列)用於所有請求和X個線程來處理/處理它們。我已閱讀了許多文章,討論這種設計的效率。有了這個模型,我將有1個監聽器也會與IOCP相關聯。讓我們假設我可以弄清楚如何保持數據包/請求同步。

  2. X IOCP(其中X是計算機具有的處理器數量),每個IOCP有1個線程。這意味着每個處理器都有自己的隊列和1個線程來處理/處理它們。有了這個模型,我將有一個單獨的監聽器(不使用IOCP)來處理連接並將SOCKET分配給正確的IOCP(創建的X之一)。讓我們假設我可以找出負載平衡。

使用對兩種設計過於簡化的類推(銀行):

與幾個收銀員到手的交易
  1. 一行。每個人都在同一行,每個出納員將下一個可用人員排隊。

  2. 每個收銀臺都有自己的線路和人「擺」到這些線路

這兩個設計之間,哪一個更高效的之一。在每個模型中,重疊I/O結構將使用帶有MEM_COMMIT的VirtualAlloc(與「新」相對),因此交換文件不應該成爲問題(無分頁)。根據我對它的描述,將VirtualAlloc與MEM_COMMIT一起使用,內存被保留,不會被分頁。這將允許SOCKETS將傳入的數據寫入我的緩衝區而不經過中間層。所以我不認爲顛簸應該是一個因素,但我可能是錯的。

有人告訴我#2會更有效率,但我沒有聽說過這種模式。預先感謝您的意見!

+0

我不確定,但是#2甚至工作?是否有可能通過幾個不同的線程監聽同一套接字? –

+0

是的,這是可能的。至少,在unix上,我確信windows沒有什麼不同 – rvs

+0

我會做的是有一個單獨的監聽器對象,它監聽輸入連接。該對象會將SOCKET分配給其中一個IOCP。每個IOCP都不會聽。 – BabelFish

回答

2

我假設對於#2,你計劃手動將套接字與IOCP進行關聯,而這個套接字在接受套接字時基於某種「好」度量來決定是「最好的」。不知何故,這種'善良'的措施將持續到插座的生命?

IOCP使用「標準」方式,即選項編號1,內核計算出如何最好地使用您擁有的線程,並允許在其中任何一個線程阻塞時運行更多線程。用你的方法,假設你以某種方式計算出如何分配工作,你將會得到比使用選項1更多的線程。

您的#2選項還會阻止您將AcceptEx()用於重疊接受,並且在您從場景中移除線程(以及由此產生的上下文切換和潛在爭用)時,這比使用正常接受循環更有效。

你的比喻失敗了;實際上更多的情況是,有一個隊列中有X隊的銀行櫃員,你加入隊列並知道你會看到一個有效的順序,而不是每個出納員都有自己的隊列,你必須猜測你加入的隊列不包含大量想要開設新帳戶的人,而旁邊的人包含大量只想付費的人。單一隊列可確保您得到有效處理。

我想你對MEM_COMMIT感到困惑。這並不意味着內存不在分頁文件中,也不會被分頁。將VirtualAlloc用於重疊緩衝區的常見原因是爲了確保頁邊界上的對齊,並因此減少爲I/O鎖定的頁數(頁面大小的緩衝區可以分配在頁邊界上,因此只需要一頁而不是由於內存管理器決定使用不在頁面邊界上啓動的塊,因此發生了兩次)。

總的來說,我認爲你正在嘗試提前優化某種方式。首先使用IOCP以正常方式獲取高效的服務器,然後對其進行配置。我嚴重懷疑你甚至需要擔心構建#2版本......同樣,使用new來分配緩衝區,然後在發現服務器由於ENOBUFS而失敗時切換到VirtualAlloc()增加的複雜性你確定這是由I/O鎖定頁面限制引起的,而不是缺乏非分頁池(你確實意識到你必須爲VirtualAlloc()分配「分配粒度」大小的塊)。

無論如何,我有一個免費的IOCP服務器框架,可在這裏找到:http://www.serverframework.com/products---the-free-framework.html這可能會幫助您開始。

編輯:複雜的版本,您認爲可能是在您使用網卡綁定有開關吐在多個網卡的流量,每個網卡綁定到不同的物理處理器,然後綁定你的IOCP一些NUMA架構有用線程到同一個處理器。然後,您可以從該NUMA節點分配內存,並有效地讓您的網絡交換機負載平衡您NUMA節點上的連接。恕我直言,我仍然建議,更好的,恕我直言,獲得一個工作服務器,你可以使用首先使用IOCP的「正常」方法進行配置文件,只有當你知道跨NUMA節點問題實際上影響你的性能走向更復雜建築...

+0

嘿Len,是的,我看過你的免費代碼(並且實際上仍然在審查它)。你有一個免費版本和許可版本的權利?感謝您對MEM_COMMIT的澄清。這是正在推動#2的人向我描述的。我也知道VirtualAlloc的頁面邊界分配。另外,是的,我會使用一個線程等待新的連接(#2),並將SOCKET關聯到將在連接期間保持不變的IOCP。我實際上會使用AcceptEx並設置OVERLAPPED結構的hEvent。 (如果我沒有弄錯) – BabelFish

+0

我相信你在某個地方提到過,當多個服務器在同一臺服務器上運行時(即一個用於端口443,另一個用於端口993等),你的免費版本不能正常工作。這可能會發生在我們身上。 – BabelFish

+0

您不需要在IOCP的「OVERLAPPED」中使用'hEvent'。 #2是錯誤的;這樣簡單,它不會像#1那麼好。免費代碼對於多個服務器來說資源效率較低,但它們仍然可以正常工作。 –

0

排隊論告訴我們,單個隊列比多個隊列有更好的特性。你有可能通過盜竊工作來解決這個問題。

多隊列方法應該有更好的緩存行爲。它是否明顯更好取決於有多少接收到的數據包與單個事務相關聯。如果請求適合單個傳入數據包,那麼即使使用單個IOCP方法,它也會與單個線程相關聯。