一、 简介
ws相关业务测试时,ws连接数是一个麻烦点,之前同事是用python写的,只能启2000个ws连接左右。
后来我用node.js写了一下发现效果很好,至少5w个没问题,以下是我的测试过程。
需求:
- 需要验证ws服务端,启5w个连接是否正常。
- 需要验证ws服务端,启5w个连接时,通过业务接口发消息是否会丢数据。
测试方案:
- node.js脚本作为客户端,用来启ws连接、保持连接、统计收数据情况
- JMeter脚本作为负载机,请求发消息接口,达到负载效果
- 查看JMeter和客户端的日志,对比数据
注:共启5w个连接数,共计发送20w条消息,客户端收到异常消息时打印出来并统计数量,另外每10秒打印一次最新数据,包括:总消息数、单人消息数
二、客户端
三、JMeter脚本
四、对比结果
JMeter结果
客户端结果
可以看到实际差了64条数据,因此可以推断发消息接口报错74次,其中10条进入了消息队列,其余64条没有进入消息队列。
也可以看到实际每个ws连接收到消息的数量。
附:我的node.js脚本
业务不同所以肯定不能复用,但是可以作为参考。
//接收参数
log('-------------------- 开始测试 --------------------');
var params = process.argv.splice(1);
var SUM = params[1];
//WS地址
var WS_LINK = "ws://192.168.2.115:8083/websocket/";
if (!SUM || SUM == '' || SUM==0){
console.log("请传入WebSocket连接数!");
process.exit();
}
var user_dict = {
};
var error_dict = {
};
var close_dict = {
};
var total_count = 0;
var total_error = 0;
var total_close = 0;
function ws (i){
i = i + 1
var ws = require("ws");
var user = '[token_' + i + '] ';
user_dict['token_' + i] = 0;
var sock = new ws(WS_LINK);
sock.on("open", function () {
console.log(user + 'Connection open ...');
console.log(user + 'verify token_' + i + ' ...');
sock.send('{"command":"userVerify","token":"token_' + i + '"}');
setInterval(function(){
sock.send('{"command":"ping"}')
},55000)
});
sock.on("error", function(err) {
console.log(user + "error: ", err);
error_dict['token_' + i] = user_dict['token_' + i];
total_error ++;
});
sock.on("close", function() {
console.log(user + 'Connection closed.');
close_dict['close_' + i] = user_dict['token_' + i];
total_close ++;
});
sock.on("message", function(data) {
console.log(user + 'Received Message: ' + data);
//正常消息
if(data.startsWith('"{\\\"data\\\":\\\"msg:')){
user_dict['token_' + i] ++;
total_count ++;
}else if (data == '{"code":0,"info":"","command":"ping","data":""}'){
//登录成功
}else if (data == '{"code":0,"info":"","command":"userVerify","data":""}' || data == '{"code":2001,"info":"no access","command":"ping","data":"no access"}' ){
//登录后的ping 和 未登录的ping
}else if (data == '{"code":2001,"info":"token is not exist.","command":"userVerify","data":""}' ){
//未注册
log (user + data);
}else{
log (user + data);
}
});
}
function log(data){
myDate = new Date();
var now = myDate.toLocaleDateString() + ' ' + myDate.toLocaleTimeString();
myData = now + ' ' + data + '\r\n';
var fs = require("fs");
fs.writeFile('./ws.log', myData, {
'flag': 'a' }, function(err) {
if (err) {
return console.error(err);
}
fs.readFile('./ws.log', function (err, data) {
if (err) {
return console.error(err);
}
});
});
}
for(var i=0;i< SUM ;i++){
ws(i);
}
setInterval(function(){
//pass
var msg = "";
for (var item in user_dict){
msg += '[' + item + '] ' + user_dict[item] + ", ";
}
console.log('SUCCESS: ' + msg);
log('SUCCESS: ' + msg);
console.log('SUCCESS: ' + '[total] ' + total_count);
log('SUCCESS: ' + '[total] ' + total_count);
//close
var closeMsg = "";
for (var item in close_dict){
closeMsg += '[' + item + '] ' + close_dict[item] + ", ";
}
if (closeMsg != ""){
console.log('CLOSE: ' + closeMsg);
log('CLOSE: ' + closeMsg);
}
if (total_close > 0){
console.log('CLOSE: ' + '[total] ' + total_close);
log('CLOSE: ' + '[total] ' + total_close);
}
//error
var errorMsg = "";
for (var item in error_dict){
errorMsg += '[' + item + '] ' + errorMsg[item] + ", ";
}
if (errorMsg != ""){
console.log('ERROR: ' + errorMsg);
log('ERROR: ' + errorMsg);
}
if (total_error > 0){
console.log('ERROR: ' + '[total] ' + total_error);
log('ERROR: ' + '[total] ' + total_error);
}
},10000)