**:
對於乙個server,我們一般考慮他所能支撐的qps,但有那麼一種應用, 我們需要關注的是它能支撐的連線數個數,而並非qps,當然qps也是我們需要考慮的效能點之一。這種應用常見於訊息推送系統,也稱為comet應用,比如聊天室或即時訊息推送系統等。comet應用具體可見我之前的介紹,在此不多講。對於這類系統,因為很多訊息需要到產生時才推送給客戶端,所以當沒有訊息產生時,就需要hold住客戶端的連線,這樣,當有大量的客戶端時,就需要hold住大量的連線,這種連線我們稱為長連線。
首先,我們分析一下,對於這類服務,需消耗的系統資源有:cpu、網路、記憶體。所以,想讓系統效能達到最佳,我們先找到系統的瓶頸所在。這樣的長連線,往往我們是沒有資料傳送的,所以也可以看作為非活動連線。對於系統來說,這種非活動連線,並不占用cpu與網路資源,而僅僅占用系統的記憶體而已。所以,我們假想,只要系統記憶體足夠,系統就能夠支援我們想達到的連線數,那麼事實是否真的如此?如果真能這樣,核心來維護這相當大的資料結構,也是一種考驗。
要完成測試,我們需要有乙個服務端,還有大量的客戶端。所以需要服務端程式與客戶端程式。為達到目標,我的想法是這樣的:客戶端產生乙個連線,向服務端發起乙個請求,服務端hold住該連線,而不返回資料。
1. 服務端的準備
對於服務端,由於之前的假想,我們需要一台大記憶體的伺服器,用於部署nginx的comet應用。下面是我用的服務端的情況:
summary: dell r710, 2 x xeon e5520 2.27ghz, 23.5gb / 24gb 1333mhz服務端程式很簡單,基於nginx寫的乙個comet模組,該模組接受使用者的請求,然後保持使用者的連線,而不返回。nginx的status模組,可直接用於監控最大連線數。system: dell poweredge r710 (dell 0vwn1r)
processors: 2 x xeon e5520 2.27ghz 5860mhz fsb (16 cores)
memory: 23.5gb / 24gb 1333mhz == 6 x 4gb, 12 x empty
disk-control: megaraid_sas0: dell/lsilogic perc 6/i, package 6.2.0-0013, fw 1.22.02-0612,
network: eth0 (bnx2):broadcom netxtreme ii bcm5709 gigabit ethernet,1000mb/s
os: rhel server 5.4 (tikanga), linux 2.6.18-164.el5 x86_64, 64-bit
服務端還需要調整一下系統的引數,在/etc/sysctl.conf中:
net.core.somaxconn = 2048# /sbin/sysctl -p 生效net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 4096 16777216
net.ipv4.tcp_wmem = 4096 4096 16777216
net.ipv4.tcp_mem = 786432 2097152 3145728
net.ipv4.tcp_max_syn_backlog = 16384
net.core.netdev_max_backlog = 20000
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_max_syn_backlog = 16384
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_max_orphans = 131072
這裡,我們主要看這幾項:
net.ipv4.tcp_rmem 用來配置讀緩衝的大小,三個值,第乙個是這個讀緩衝的最小值,第三個是最大值,中間的是預設值。我們可以在程式中修改讀緩衝的大小,但是不能超過最小與最大。為了使每個socket所使用的記憶體數最小,我這裡設定預設值為4096。
net.ipv4.tcp_wmem 用來配置寫緩衝的大小。
讀緩衝與寫緩衝在大小,直接影響到socket在核心中記憶體的占用。
而net.ipv4.tcp_mem則是配置tcp的記憶體大小,其單位是頁,而不是位元組。當超過第二個值時,tcp進入pressure模式,此時tcp嘗試穩定其記憶體的使用,當小於第乙個值時,就退出pressure模式。當記憶體占用超過第三個值時,tcp就拒絕分配socket了,檢視dmesg,會打出很多的日誌「tcp: too many of orphaned sockets」。
另外net.ipv4.tcp_max_orphans這個值也要設定一下,這個值表示系統所能處理不屬於任何程序的socket數量,當我們需要快速建立大量連線時,就需要關注下這個值了。當不屬於任何程序的socket的數量大於這個值時,dmesg就會看到」too many of orphaned sockets」。
另外,服務端需要開啟大量的檔案描述符,比如200萬個,但我們設定最大檔案描述符限制時,會遇到一些問題,我們在後面詳細講解。
2. 客戶端的準備
由於我們需要構建大量的客戶端,而我們知道,在一台系統上,連線到乙個服務時的本地埠是有限的。由於埠是16位整數,也就只能是0到65535,而0到1023是預留埠,所以能分配的只是1024到65534,也就是64511個。也就是說,一台機器只能建立六萬多個長連線。要達到我們的兩百萬連線,需要大概34臺客戶端。
當然,我們可以採用虛擬ip的方式來實現這麼多客戶端,如果是虛擬ip,則每個ip可以繫結六萬多個埠,34個虛擬ip就可以搞定。而我這裡呢,正好申請到了公司的資源,所以就採用實體機來做了。
由於系統預設引數,自動分配的埠數有限,是從32768到61000,所以我們需要更改客戶端/etc/sysctl.conf的引數:
net.ipv4.ip_local_port_range = 1024 65535# /sbin/sysctl -p
客戶端程式是基於libevent寫的乙個測試程式,不斷的建立新的連線請求。
3. 由於客戶端與服務端需要建立大量的socket,所以我們需要調速一下最大檔案描述符。客戶端,需要建立六萬多個socket,我設定最大為十萬好了,的在/etc/security/limits.conf中新增:
admin soft nofile 100000服務端,需要建立200萬連線,那我想設定nofile為200萬,好,問題來了。admin hard nofile 100000
當我設定nofile為200萬時,系統直接無法登陸了。嘗試幾次,發現最大只能設定到100萬。在查過原始碼後,才知道,原來在2.6.25核心之前有個巨集定義,定義了這個值的最大值,為1024*1024,正好是100萬,而在2.6.25核心及其之後,這個值是可以通過/proc/sys/fs/nr_open來設定。於是我公升級核心到2.6.32。ulimit詳細介紹見ulimit問題及其影響
公升級核心後,繼續我們的調優,如下:
# sudo bash -c 'echo 2000000 > /proc/sys/fs/nr_open'
現在再設定nofile就可以了
admin soft nofile 20000004. 最後,在測試的過程中,根據dmesg的系統打出的資訊不斷調整服務端/sbin/sysctl中的配置,最後我們的測試完成了200萬的長連線。為了使記憶體占用儘量減少,我將nginx的request_pool_size從預設的4k改成1k了。另外,net.ipv4.tcp_wmem與net.ipv4.tcp_rmem中的預設值也設定成4k。admin hard nofile 2000000
兩百萬連線時,通過nginx的監控得到資料:
兩百萬連線時系統記憶體情況:
HTTP長連線和WebSocket長連線的區別
要理解http長連線和websocket長連線的區別,首先要理解一下什麼是http的長連線和短連線。首先需要消除乙個誤解 http協議是基於請求 響應模式的,因此客戶端請求後只要服務端給了響應,本次http請求就結束了,沒有長連線這一說。那麼自然也就沒有短連線這一說了。所謂的http分為長連線和短連...
http 長連線 短連線
http短連線 非持久連線 是指,客戶端和服務端進行一次http請求 響應之後,就關閉連線。所以,下一次的http請求 響應操作就需要重新建立連線。http長連線 持久連線 是指,客戶端和服務端建立一次連線之後,可以在這條連線上進行多次請求 響應操作。持久連線可以設定過期時間,也可以不設定。http...
Http長連線配置
客戶端與nginx的長連線 keepalive timeout 客戶端與nginx之間的長連線超時設定,當乙個連線的最後一次資料傳輸至今超過了這個時間,那麼當前連線就會被服務端主動關閉。預設值60s,因此客戶端與nginx預設是長連線的。keepalive requests 也是客戶端與nginx的...