實戰(zhàn)單機50萬Tcp連接

實戰(zhàn)單機50萬Tcp連接

本來準備嘗試挑戰(zhàn)百萬鏈接, 但是申請不到機器資源, 只好在自己的筆記本上來跑測試. 機器配置如下:

Memory: 11.4 GiB
Intel? Core? i5-5200U CPU @ 2.20GHz × 4

技術(shù)框架選擇的是Vert.x, 這是比Netty更好的服務(wù)端框架. 連續(xù)測試幾天, 最終壓到了48萬, 過程中也遇到了很多問題(小馬過河, 水深水淺得走下去試試才知道啊), 文末的鏈接給了很多幫助.

準備工作

Server端服務(wù)器配置

1.修改系統(tǒng)最大文件打開數(shù)。

臨時性方案:echo 1200000 > /proc/sys/fs/file-max

永久性方案:在/etc/sysctl.conf中添加fs.file-max = 1200000,設(shè)置完成后執(zhí)行命令:sudo sysctl -p,重新裝載配置使其生效。

查看當前系統(tǒng)使用的打開文件描述符數(shù):cat /proc/sys/fs/file-nr。

 ~/WorkSpace/Java/vert.x   sc  cat /proc/sys/fs/file-nr 
11069   0   2000000

執(zhí)行命令會輸出三個數(shù)值,第一個表示當前系統(tǒng)已分配使用的文件數(shù),第二個數(shù)為分配后已釋放的(目前已不再使用),第三個數(shù)是系統(tǒng)最大文件數(shù),等于file-max值。

2.修改進程最大文件打開數(shù)。

這個參數(shù)默認值比較小,我的ubuntu14.04上默認是1024個。如果我們創(chuàng)建大量的鏈接,當超過這個值時將會拋出:Too many open files錯誤。

首先,查看本機的默認最大文件打開數(shù):ulimit -n。如果我們想創(chuàng)建一百萬鏈接的話,這個值應(yīng)該設(shè)置大于1000000的值。

臨時修改方案,這種方案及時生效,但是重啟系統(tǒng)后配置丟失。

ulimit -Sn 1200000
ulimit -Hn 1200000

永久修改方案,需要修改/etc/security/limits.conf,*代表非root用戶。如果只想為某一個用戶設(shè)置的話*換成用戶名即可。

*         hard    nofile      1200000
*         soft    nofile      1200000
root      hard    nofile      1200000
root      soft    nofile      1200000

保存修改需重啟系統(tǒng)或者重新登錄使配置生效。

我們可以啟動一個進程來看一下它的最大文件打開數(shù):cat /proc/${pic}/limits。以下數(shù)據(jù)是我啟動的一個vertx Server進程:

 ~/WorkSpace/Java/vert.x   sc  cat /proc/27136/limits 
Limit                     Soft Limit           Hard Limit           Units     
Max cpu time              unlimited            unlimited            seconds   
Max file size             unlimited            unlimited            bytes     
Max data size             unlimited            unlimited            bytes     
Max stack size            8388608              unlimited            bytes     
Max core file size        0                    unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             46651                46651                processes 
Max open files            1200000              1200000              files     
Max locked memory         65536                65536                bytes     
Max address space         unlimited            unlimited            bytes     
Max file locks            unlimited            unlimited            locks     
Max pending signals       46651                46651                signals   
Max msgqueue size         819200               819200               bytes     
Max nice priority         0                    0                    
Max realtime priority     0                    0                    
Max realtime timeout      unlimited            unlimited            us     

可以看到open files一行已經(jīng)變成我們的預(yù)設(shè)值。在修改的時候需要注意一點ulimit的之不能超過系統(tǒng)的max file size。

我的ubuntu 17.04在做這個修改的時候遇到一點問題,設(shè)置完成后重啟系統(tǒng),啟動程序發(fā)現(xiàn)最大打開文件總是4096。折騰了半天發(fā)現(xiàn)是ubuntu系統(tǒng)的bug。解決方案來自這里

3.TCP協(xié)議棧優(yōu)化

Client端服務(wù)器配置

1.修改端口范圍。

linux服務(wù)器上端口范圍是0~65535,其中0~1024是給系統(tǒng)保留的端口范圍。當客戶端建立鏈接的時候會自動的選擇一個本地可用的端口號,為了能夠最大限度的利用機器上的端口,我們需要修改端口范圍。

通過命令cat /proc/sys/net/ipv4/ip_local_port_range我們可以查看當前的端口范圍配置。

修改的話我們在/etc/sysctl.conf中添加這行:net.ipv4.ip_local_port_range= 1024 65535,然后重載配置。這樣的話一個client服務(wù)器可以創(chuàng)建六萬多個鏈接(我本機測試64500個鏈接)。

即便是這樣我們也需要大概17臺客戶端測試機,這我上哪搞去啊。只能通過虛擬IP來弄了(系統(tǒng)知識嚴重匱乏,網(wǎng)上找了很長時間才搞定)。接下來我們來配置虛擬IP。配置虛擬IP我們可以通過ifconfig來搞。比如我們直接執(zhí)行命令:sudo ifconfig eth0:0 192.168.199.100 netmask 255.255.255.0。eth0是真實網(wǎng)卡的名字,eth0:0是虛擬網(wǎng)卡的名字,后邊是網(wǎng)卡綁定的IP。如果要想局域網(wǎng)訪問,這個IP要和你真實網(wǎng)卡上的IP在同一網(wǎng)段。本地訪問的話就隨意了。

還有另外一種方式是修改/etc/network/interfaces配置文件。我們添加一下條目:

auto eth0:0
iface eth0 inet static
address 192.168.1.201
netmask 255.255.255.0
broadcast 192.168.1.255
gateway 192.168.1.0

添加完成后,重啟network service:sudo /etc/init.d/networking restart。通過執(zhí)行ifconfig便可看到這個虛擬IP。

為啥一個server不能創(chuàng)建超過65536個鏈接呢?這得需要先了解一下系統(tǒng)是如何標識一個網(wǎng)絡(luò)套接字(socket)的。當系統(tǒng)創(chuàng)建一個網(wǎng)絡(luò)套接字,會以{源IP地址,源端口,目的IP地址,目的端口}這樣一個四元組來唯一表示這個鏈接。假設(shè)一個server擁有一個IP地址,而端口號最多就是65536個(極限)因此最大鏈接數(shù)也就固定了。如果我們在一個server上維持創(chuàng)建100M個鏈接,粗略估算一個IP 60000個鏈接,我們將需要17個IP地址。

開始測試

測試程序的都是用Vert.x實現(xiàn)的,源碼在此。代碼是非常簡單的,沒必要說了??纯丛跍y試過程中遇到的一些問題。

1.當連接增加到23萬多的時候,服務(wù)器hang住了,不在接受任何鏈接。

...
231000 connections connects in...
232000 connections connects in...

通過dmesg查看系統(tǒng)日志發(fā)了一些線索:

[13662.489289] TCP: too many orphaned sockets
[13662.489299] TCP: too many orphaned sockets
[13662.489304] TCP: too many orphaned sockets
[13662.489311] TCP: too many orphaned sockets
[13662.489317] TCP: too many orphaned sockets
[13662.489323] TCP: too many orphaned sockets
[13662.489330] TCP: too many orphaned sockets
[13662.489335] TCP: too many orphaned sockets
[13662.489341] TCP: too many orphaned sockets
[13662.489348] TCP: too many orphaned sockets

網(wǎng)上搜了一下,這是系統(tǒng)耗光了socket內(nèi)存,導(dǎo)致新連接進來時無法分配內(nèi)存。需要調(diào)整一下tcp socket參數(shù)。在tcp_mem三個值分別代表low,pressure,high三個伐值。

low:當TCP使用了低于該值的內(nèi)存頁面數(shù)時,TCP不會考慮釋放內(nèi)存。
pressure:當TCP使用了超過該值的內(nèi)存頁面數(shù)量時,TCP試圖穩(wěn)定其內(nèi)存使用,進入pressure模式,當內(nèi)存消耗低于low值時則退出pressure狀態(tài)。
high:允許所有tcp sockets用于排隊緩沖數(shù)據(jù)報的頁面量,當內(nèi)存占用超過此值,系統(tǒng)拒絕分配socket,后臺日志輸出"TCP: too many of orphaned sockets"。

打開/etc/sysctl.conf,加入以下配置:

net.ipv4.tcp_mem = 786432 2097152 3145728 
net.ipv4.tcp_rmem = 4096 4096 6291456
net.ipv4.tcp_wmem = 4096 4096 6291456

tcp_mem 中的單位是頁,1頁=4096字節(jié)。所以我們設(shè)置的最大tcp 內(nèi)存是12G。tcp_rmem,tcp_wmem單位是byte,所以最小socket讀寫緩存是4k。

2.server 又卡住不創(chuàng)建鏈接了。

236000 connections connects in...
237000 connections connects in...
238000 connections connects in...

再次查看系統(tǒng)異常信息。

[ 1465.133062] nf_conntrack: nf_conntrack: table full, dropping packet
[ 1465.133066] nf_conntrack: nf_conntrack: table full, dropping packet
[ 1470.134845] net_ratelimit: 23807 callbacks suppressed
[ 1470.134846] nf_conntrack: nf_conntrack: table full, dropping packet
[ 1470.154131] nf_conntrack: nf_conntrack: table full, dropping packet
[ 1470.154138] nf_conntrack: nf_conntrack: table full, dropping packet
[ 1470.161674] nf_conntrack: nf_conntrack: table full, dropping packet

nf_conntrack就是linux NAT的一個跟蹤連接條目的模塊,nf_conntrack模塊會使用一個哈希表記錄TCP通訊協(xié)議的創(chuàng)建的鏈接記錄,當這個哈希表滿了的時候,便會導(dǎo)致:nf_conntrack: table full, dropping packet錯誤。那我們接下來修改一下這個值,還是打開/etc/sysctl.conf文件。
加入以下記錄:

net.netfilter.nf_conntrack_max = 1200000
net.netfilter.nf_conntrack_buckets = 150000

這兩個值表示conntrack的最大值,以及哈希的桶數(shù)。

還有一個關(guān)于JVM的調(diào)優(yōu),這個也要注意,剛開始創(chuàng)建幾萬個的時候沒什么影響,但是上20萬之后GC影響逐漸顯著, 停頓次數(shù)和時間都比較顯著。我這邊server給了兩個G, client給了5個G. 調(diào)整之后好很多. 垃圾收集器CMS和Parallel都行.

參考

使用四種框架分別實現(xiàn)百萬websocket常連接的服務(wù)器
高性能網(wǎng)絡(luò)編程7--tcp連接的內(nèi)存使用
Conntrack Tuning

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 關(guān)于C10K的問題就不多說了,應(yīng)該是一個說爛的話題。網(wǎng)上也有很多C1000k,甚至C10M(也就是1kw并發(fā)...
    游泳的石頭閱讀 11,368評論 3 46
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,554評論 19 139
  • 簡介 用簡單的話來定義tcpdump,就是:dump the traffic on a network,根據(jù)使用者...
    保川閱讀 6,079評論 1 13
  • Ubuntu的發(fā)音 Ubuntu,源于非洲祖魯人和科薩人的語言,發(fā)作 oo-boon-too 的音。了解發(fā)音是有意...
    螢火蟲de夢閱讀 100,675評論 9 468
  • 我覺得天底下最愛惜糧食的人就是我的父親。 昨天午餐,我說我為了身材苗條一些,我每餐只吃八成飽。 部隊出身的曾擔任軍...
    火山wj閱讀 116評論 0 0

友情鏈接更多精彩內(nèi)容