2011-11-29 57 views
6

我讀過C10K doc以及關於擴展套接字服務器的許多相關論文。所有道路指向以下:帶epoll的TCP服務器的線程和縮放模型

  1. 避免「每個連接線程」的經典錯誤。

  2. 優先選擇epoll。

  3. 同樣,unix中遺留的async io機制可能很難使用。

我的簡單TCP服務器只是偵聽專用端口上的偵聽套接字上的客戶端連接。在收到新的連接後,解析請求併發迴響應。然後優雅地關閉套接字。

我想我對如何在單線程上使用epoll進行擴展有很好的把握。只需一個循環,即爲listen套接字以及現有客戶端連接調用epoll_wait。返回時,代碼將處理新的創建新客戶端連接以及根據剛獲得信號的套接字管理現有連接的狀態。可能還有一些邏輯來管理連接超時,優雅地關閉套接字,併爲每個連接高效地分配資源。看起來很簡單。

但是如果我想擴展這個來利用多線程和多個cpu核心呢?想到的核心思想是:

一個專用線程用於偵聽TCP偵聽套接字上的傳入連接。然後是一組N個線程(或線程池)來處理所有活動的併發客戶端連接。然後創建一些線程安全的方式,讓listen線程將新的連接(套接字)「分派」給一個可用的工作線程。 (Windows中的ala IOCP)。工作線程將在它正在處理的所有連接上使用epoll循環來執行單線程方法。

我在正確的軌道上嗎?或者是否有一個標準的設計模式,用於在多個線程上使用epoll 來執行TCP服務器

有關如何偵聽線程將派發新的連接到線程池的建議?

+0

如果你選擇的語言是靈活的,你可能想嘗試http://vibed.org/,它抽象了異步編程的異步特性,所以你仍然可以同步編程。 例如 ubyte [] buf = new ubyte [](1024); auto data = conn.read(buf); conn.write(data); – rmc

回答

-1

我想你是在正確的軌道上。但我也認爲細節取決於特定的情況(bandwidh,請求模式,個別請求處理等)。我認爲你應該嘗試一下,並仔細衡量。

2
  1. 首先,注意它是C * 10K *。如果你小於100(在典型系統上),不要擔心自己。即使那麼它取決於什麼你的插座正在做。
  2. 是的,但請記住,epoll操作需要系統調用,其成本可能會或可能不會比自己管理幾個fd_set貴。 poll也是如此。在低計數時,每次迭代都會在用戶空間中進行處理,這樣會更便宜。
  3. 當你不限制只有幾個你可以根據需要調整的套接字時,異步IO非常痛苦。大多數人通過使用事件循環來應對,但是這會碎片並顛倒你的程序流程。它通常還需要使用大型,笨拙的框架來達到這個目的,因爲可靠和快速的事件循環並不容易。

第一個問題是,你需要這個嗎?如果您通過產生線程處理每個傳入的請求,輕鬆應對現有的流量,請繼續這樣做。代碼會更簡單,所有的庫都會很好地播放。

正如我上面提到的,雜耍同時請求可能很複雜。如果您想在單個循環中執行此操作,則在生成響應時還需要確保CPU不足。

如果您的響應生成成本很高,則您建議的分派模型是典型的第一步解決方案。您可以分叉或使用線程。在選擇池化機制時,分叉或生成線程的成本不應該被考慮:相反,您應該使用這種機制來限制或限制系統上的負載。

在多個epoll環上分配套接字過多。如果你絕望,請使用多個進程。請注意,在多線程和進程的套接字上可以使用accept

+0

Matt,我其實還沒有編寫TCP網絡核心。因此,如果有更好的設計模式要考慮,我顯然沒有任何理由以「每個連接線程」模式開始。是否說「select」比低層套接字的epoll更便宜?你能詳細說明「cpu飢餓」問題嗎?我同意負載平衡設計點。我已經考慮過多個線程全部阻止接受。 – selbie