本文由作者鄭銀燕授權網易雲社區發布。
本文是我在測試過程中的記錄,實現了單台測試機發起最大的websocket長連接數。在一台測試機上,連接到一個遠程服務時的本地端口是有限的。根據TCP/IP協議,由於端口是16位整數,也就只能是0到 65535,而0到1023是預留端口,所以能分配的端口只是1024到65534,也就是64511個。也就是說,一台機器一個IP只能創建六萬多個websocket長連接。
一、客戶端參數調優
本文采用的測試機分別為黑mac系統和linux系統(由於黑mac機器本身性能問題,最大只能達到2萬連接,於是換用linux)。下面先以mac系統為例,闡述下客戶端參數調優,linux系統類似,這里不做闡述。
1、修改全局限制,系統默認的最大連接數限制
命令:sysctl kern.maxfiles

說明:全局限制,也就是系統默認的最大連接數限制是12288
修改大小: sudo sysctl -w kern.maxfiles=1048600

說明:設置系統最大連接數從12288到1048600
2、測試腳本是一個進程,開啟上萬個長連接,還需要修改單個進程的最大連接數。
命令:sysctl kern.maxfilesperproc

說明:單個進程默認最大連接數限制是10240
修改大小:sudo sysctl -w kern.maxfilesperproc=1048576

說明:設置進程連接數限制,進程的最大連接數要小於等於全局連接數
3、由於客戶端與服務端需要建立大量的socket,所以我們需要調速一下最大文件描述符。
命令:ulimit -n

說明:“ulimit -n”命令顯示當前shell能打開的最大文件數,默認值:256,該值總是小於kern.maxfilesperproc的值,因為一個shell就是一個進程。
修改大小:ulimit -n 1048576
說明:設置當前shell能打開的最大文件數為1048576,該值不能大於kern.maxfilesperproc,否則會提示設置失敗。
4、由於系統默認參數,自動分配的端口數有限,所以我們需要更改客戶端ip端口號的參數
命令:sysctl net.inet.ip.portrange,查詢得到的系統默認的端口號分配如下:

將可分配的首個端口號設置為1024
修改大小:sudo sysctl net.inet.ip.portrange.first=1024

5、按以上的方式設置參數有個問題,當系統重啟后,這些參數又恢復成了默認值,解決辦法就是把參數寫到/etc/sysctl.conf文件中,但是,默認這個文件是不存在的,所以首先就要創建它:
sudo touch /etc/sysctl.conf
然后把參數寫到文件里
kern.maxfiles=1048600
kern.maxfilesperproc=1048576
net.inet.ip.portrange.first=1024
net.inet.ip.portrange.last=65535
重啟系統,查看結果,顯示成功。
至於ulimit -n的值,可以把ulimit -n 1048576 寫到.bashrc中實現自動修改。
二、測試腳本
客戶端腳本采用nodejs編寫,之所以不采用jmeter的方式,是因為jmeter每個連接都是線程的方式,而單台測試機最好保持開啟1000個以內的線程,否則機器容易崩潰。
測試腳本如下:
var cwd = process.cwd();var WebSocketClient = require('websocket').client;var size = 10000;var host = 'example.com:80';var port = 443;var authInterval = 10;var index = 0;
setInterval(function(){ if(index < size){
uid = index;
cid = index;
init(uid, cid);
index++;
}
},authInterval);console.log('begin...');
init = function(uid, cid){ var client = new WebSocketClient();
client.connect('ws://XX.XX.XX.XX:XXXX/ws?token='+index,"","http://example.com:80");
client.on('connectFailed', function(error) { console.log('Connect Error: ' + error.toString());
});
client.on('connect', function(connection) { console.log(index+' Connected');
connection.on('error', function(error) { console.log("Connection Error: " + error.toString());
});
connection.on('close', function(error) { console.log(error + '; Connection Closed'); //client.close();
reconnect();
});
connection.on('message', function(message) {
});
});
};function timeLogout(){ return setTimeout(function (){
logout(uid);
}, StartTime);
}
三、測試結果
在相應的目錄下輸入命令node websocket.js,即可建立websocket連接。由於機器性能問題,連接數達到2w左右,就無法建立新的連接了。后面將機器改成雲主機,可以達到6萬的連接數。

四、后續展望
我的測試目標不是實現單台6萬的連接數。我的目標是可以達到百萬級穩定的長連接,並且可以向websocket服務器收發信息,計算每個消息從服務器發送到客戶端接收的平均耗時時間,以及查看建立百萬級連接,服務器的內存和cpu的使用情況。最終限制於機器的性能,暫時還沒做到。並且業務需求繁忙,這個測試就暫時告一段落了。后續想要通過使用虛擬IP的方式來實現百萬級連接,比如增加了18個IP地址,這樣就可以產生18 * 60000 = 1080000個連接。或者借用更多的機器數,每台機器維持6萬連接。
免費領取驗證碼、內容安全、短信發送、直播點播體驗包及雲服務器等套餐
更多網易技術、產品、運營經驗分享請訪問網易雲社區。
相關文章:
【推薦】 考拉消息中心消息盒子處理重構(策略模式)
【推薦】 windows系統下npm升級的正確姿勢以及原理
【推薦】 網易雲易盾與A10 Networks達成戰略合作 攜手打造抗DDoS攻擊的解決方案
