2009-10-22 40 views
7

我有一個用C寫的守護進程,它需要同時處理20-150K的TCP連接。他們是長期運行的連接,並且很少拆卸下來。它們在任何給定的時間都有非常少量的數據(很少超過MTU,這是一種刺激/響應協議),但對它們的響應時間至關重要。我想知道當前的UNIX社區正在使用什麼來獲取大量套接字,並儘量減少響應時間。我已經看到設計圍繞多路複用連接到fork工作池,線程(每個連接),靜態大小的線程池。有什麼建議麼?如何在現代多核/多插口機器上擴展TCP偵聽器

+2

請重新格式化你的問題的代碼。單個水平滾動線不是很有幫助。 – ndim 2009-10-22 18:01:37

+0

爲什麼選擇C?你不能用別的東西......說Erlang? – jldupont 2009-10-22 18:02:14

+2

@jldupont,語言對此是否重要?這似乎是一個系統問題,而不是某種語言限制。 – mrduclaw 2009-10-22 18:11:14

回答

7

最簡單的建議是使用libevent,它可以很容易地編寫一個簡單的非阻塞單線程服務器,以符合您的要求。如果每個響應的處理需要一些時間,或者如果它使用某些阻塞API(如幾乎任何來自數據庫的任何內容),那麼您將需要一些線程。

  • 一個答案是工作者線程,你在哪裏產生一組線程,每個線程都監聽一些隊列工作。如果你喜歡,它可以是單獨的進程,而不是線程。主要區別在於溝通機制告訴工作人員該做什麼。

  • 一個不同的方法是使用多個線程,併爲它們中的每一個提供這些150K連接的一部分。每個人都將擁有自己的進程循環,並且主要像單線程服務器一樣工作,除了偵聽端口,它將由單個線程處理。這有助於在覈心之間傳播負載,但是如果使用阻塞資源,它將阻塞由該特定線程處理的所有連接。

libevent讓你使用第二種方式,如果你小心;但也有一個替代方案:libev。它不像libevent那樣廣爲人知,但它特別支持多環路方案。

+1

您應該考慮工作線程模型和工作進程模型。事實上,如果你想要這樣做,你應該真的爲線程和進程編寫代碼,然後計時。在現代Linux內核進程中,切換開銷類似於線程切換,但應用程序不必執行任何鎖定信號量。 – 2009-10-22 20:25:45

0

已開發若干系統以改善select(2)性能:kqueue,epoll/dev/poll。在所有這些系統中,可以有一個工作線程池等待任務;當完成其中一個文件句柄時,您不會被強制重複設置所有文件句柄。

0

你必須從頭開始?你可以使用類似gearman的東西。

+0

對我來說,看起來像齒輪工會引入很多延遲(因爲單獨的工作服務器)。 – cmeerw 2009-10-22 20:26:11

+0

我在想同樣的事情......對於非關鍵性的響應時間和工作批次來說,這可能很好。 – Obi 2009-10-23 05:47:56

1

如果系統配置訪問不要過度做並設置一些iptables的/ PF的/ etc 爲這個負載均衡連接到N個守護實例(進程)將工作開箱。取決於阻止守護進程n的性質應該來自系統上的核心數量還是幾倍更高。這種方法看起來很粗糙,但它可以處理破損的守護進程,並在必要時重啓它們。同樣遷移將會平滑,因爲您可以開始將新連接轉移到另一組進程(例如,新版本或遷移到新框)而不是服務中斷。最重要的是,你會得到幾個功能,如源親和力,這可以顯着幫助緩存和爭用有問題的會話。

如果您沒有訪問系統(OPS或不能打擾),你可以使用負載平衡器守護(有大量的開源者的),而不是iptables的/ PF /等,並利用N服務守護進程,如上所述。

而且,這種方法有助於分離特權端口。如果外部服務需要服務於低端口(< 1024),則只需要運行特權/或管理員/根或內核的負載平衡器。)

我已經寫過幾個IP負載均衡器在生產中可能非常容易出錯。你不想支持和調試。此外,操作和管理會比外部代碼更容易猜測您的代碼。

+1

相反,它聽起來..它不是一個Web服務器。 :)它是很多客戶端的服務器..客戶端保持TCP連接,並有他們期望的輸入設置響應。 – Obi 2009-10-22 19:45:08

+0

你**閱讀**很多瘋狂雜誌是一個**孩子**,是不是? – caf 2009-10-22 20:35:00

+0

@Obi iptables/pf是IP/TCP/UDP,而不是HTTP。您可以使用庫(libevent?),線程或直OpenMP。最後可以在源代碼的特定關鍵點進行相當多的內核間平衡。此外,英特爾最近的nehalem/i7還有超線程技術,但不知道ICC或GCC是否已經支持OpenMP(他們幾年前在2000年初期爲前一個超線程時代所做的) IMHE線程給出了O(n^2)由於同步和caché混音而導致的性能下降。另外它通常伴隨着很多分支預測錯誤。因人而異。 @caf **什麼**? – alecco 2009-10-22 21:25:40

2

如果性能至關重要,那麼您真的想要尋求一個多線程事件循環解決方案 - 即工作線程池來處理您的連接。不幸的是,沒有抽象庫要做到這一點,在大多數Unix平臺上工作(注意,libevent的僅僅是單線程的最這些事件循環庫),所以你必須自己做骯髒的工作。在Linux上,這意味着使用邊緣觸發epoll與工作線程池(Windows將有I/O完成端口,這也可以在多線程環境中正常工作 - 我不確定其他Unix)。我已經做了一些嘗試在Linux和Windows I/O完成端口上抽象邊緣觸發epoll的工作(它正在進行中,但可能提供一些想法)。

1

我認爲哈維爾的回答是很有道理的。如果你想測試理論,那麼請查看node JavaScript項目。

節點基於Google的v8引擎,它將javascript編譯爲機器代碼,並且對於某些任務而言與c一樣快。也正是基於對libev和設計是完全無阻塞的,這意味着你不必擔心線程的上下文切換(一切在一個單一的事件循環運行)。在這方面它與erlang非常相似。

在JavaScript編寫高性能服務器現在是真的,真的與節點容易。你也可以通過一點點努力在c中編寫自定義代碼,併爲節點創建綁定以便進行實際處理(查看節點源代碼以瞭解如何執行此操作 - 文檔有點粗略此時此刻)。作爲一個更醜陋的選擇,您可以將您的自定義c代碼構建爲應用程序,並使用stdin/stdout與它進行通信。

我已經用自己的測試節點向上150k連接,絕對沒有問題(當然,如果所有這些連接都要一次通信,你將需要一些嚴重的硬件)。 node.js中的TCP連接平均只使用2-3k的內存,因此您理論上可以處理每1GB內存350-500k的連接。

注 - Node.js的目前不支持Windows版本,但它只是處於發展的初期階段,我會想象它會在某個階段被移植。

注2 - 你必須確保你調用到從節點不會阻止

+0

只需要注意...節點現在可以通過它的底層庫libuv完全支持(類似於libevent)。因爲它成功地封裝了Windows的非阻塞IOCP API,所以libuv在Windows上實際上會比libevent更快。如果您想編寫跨平臺的非阻塞應用程序,libuv和libevent現在都是非常可以接受的選項,但是正如我所提到的,libuv在windows上可能比libevent更好(直到libevent包裝IOCP)。 – andrew 2012-09-26 20:11:13