高效能網路程式設計(一):單臺伺服器併發TCP連線數到底可以有多少?
引言
曾幾何時我們還在尋求網路程式設計中C10K問題(有關C10K問題請見文章《The C10K problem(英文線上閱讀、英文PDF版下載、中文譯文)》)的解決方案,但是現在從硬體和作業系統支援來看單臺伺服器支援上萬併發連線已經沒有多少挑戰性了。
我們先假設單臺伺服器最多隻能支援萬級併發連線,其實對絕大多數應用來說已經遠遠足夠了,但是對於一些擁有很大使用者基數的網際網路公司,往往面臨的併發連線數是百萬、千萬、甚至騰訊的上億(注:QQ預設用的UDP協議,具體請見討論貼《為什麼QQ用的是UDP協議而不是TCP協議?》)。
雖然現在的叢集,分散式技術可以為我們將併發負載分擔在多臺伺服器上,那我們只需要擴展出數十臺電腦就可以解決問題,但是我們更希望能更大的挖掘單臺伺服器的資源,先努力垂直擴充套件,再進行水平擴充套件,這樣可以有效的節省伺服器相關的開支(硬體資源、機房、運維人力、電力其實也是一筆不小的開支)。
那麼到底一臺伺服器能夠支援多少TCP併發連線呢?這就是本文要討論的問題。
檔案控制代碼限制
在linux下編寫網路伺服器程式的朋友肯定都知道每一個tcp連線都要佔一個檔案描述符,一旦這個檔案描述符使用完了,新的連線到來返回給我們的錯誤是“Socket/File:Can't open so many files”。
這時你需要明白作業系統對可以開啟的最大檔案數的限制。
程序限制
執行 ulimit -n 輸出 1024,說明對於一個程序而言最多隻能開啟1024個檔案,所以你要採用此預設配置最多也就可以併發上千個TCP連線。臨時修改:ulimit -n 1000000,但是這種臨時修改只對當前登入使用者目前的使用環境有效,系統重啟或使用者退出後就會失效。
重啟後失效的修改(不過我在CentOS 6.5下測試,重啟後未發現失效),編輯 /etc/security/limits.conf 檔案, 修改後內容為:
- soft nofile 1000000
- hard nofile 1000000
永久修改:編輯/etc/rc.local,在其後新增如下內容:
- ulimit -SHn 1000000
全侷限制
執行 cat /proc/sys/fs/file-nr 輸出 9344 0 592026,分別為:
- 1. 已經分配的檔案控制代碼數,
- 2. 已經分配但沒有使用的檔案控制代碼數,
- 3. 最大檔案控制代碼數。
但在kernel 2.6版本中第二項的值總為0,這並不是一個錯誤,它實際上意味著已經分配的檔案描述符無一浪費的都已經被使用了 。
我們可以把這個數值改大些,用 root 許可權修改 /etc/sysctl.conf 檔案:
- fs.file-max = 1000000
- net.ipv4.ip_conntrack_max = 1000000
- net.ipv4.netfilter.ip_conntrack_max = 1000000
埠號範圍限制?
作業系統上埠號1024以下是系統保留的,從1024-65535是使用者使用的。由於每個TCP連線都要佔一個埠號,所以我們最多可以有60000多個併發連線。我想有這種錯誤思路朋友不在少數吧?(其中我過去就一直這麼認為)
我們來分析一下吧。
如何標識一個TCP連線:
系統用一個4四元組來唯一標識一個TCP連線:{local ip, local port,remote ip,remote port}。好吧,我們拿出《UNIX網路程式設計:卷一》第四章中對accept的講解來看看概念性的東西,第二個引數cliaddr代表了客戶端的ip地址和埠號。而我們作為服務端實際只使用了bind時這一個埠,說明埠號65535並不是併發量的限制。
server最大tcp連線數:
server通常固定在某個本地埠上監聽,等待client的連線請求。不考慮地址重用(unix的SO_REUSEADDR選項)的情況下,即使server端有多個ip,本地監聽埠也是獨佔的,因此server端tcp連線4元組中只有remote ip(也就是client ip)和remote port(客戶端port)是可變的,因此最大tcp連線為客戶端ip數×客戶端port數,對IPV4,不考慮ip地址分類等因素,最大tcp連線數約為2的32次方(ip數)×2的16次方(port數),也就是server端單機最大tcp連線數約為2的48次方。
小結
上面給出的結論都是理論上的單機TCP併發連線數,實際上單機併發連線數肯定要受硬體資源(記憶體)、網路資源(頻寬)的限制,至少對我們的需求現在可以做到數十萬級的併發了,你的呢?
C10K問題系列文章
本文是C10K問題系列文章中的第1篇,總目錄如下: