测试性能:
需要安装node环境
websocket-bench 安装:
npm install -g websocket-bench --registry=http://registry.npm.taobao.org
查看系统句柄数设置
[root@localhost tmp]# ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 514944
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 65535
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 514944
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
##最大连接数或者每个进程可以同时打开的最大文件数
[root@localhost tmp]# ulimit -n
65535
##可以运行的最大并发进程数
[root@localhost tmp]# ulimit -u
514944
查看当前系统句柄数使用情况
[root@localhost ~]# cat /proc/sys/fs/file-nr
14976 0 13071862
已分配文件句柄的数目 已分配未使用文件句柄的数目 文件句柄的最大数目
查看某一个进程句柄数使用情况
java8@linux-u734:~># ll /proc/16109/fd|wc -l
211
查看当前可以使用的ip段
[root@localhost ~]# cat /proc/sys/net/ipv4/ip_local_port_range
32768 60999
在一台测试机上,连接到一个远程服务时的本地端口是有限的。根据TCP/IP协议,由于端口是16位整数,也就只能是0到 65535,而0到1023是预留端口,所以能分配的端口只是1024到65534,也就是64511个。也就是说,一台机器一个IP只能创建六万多个websocket长连接。
websocket-bench 命令
参考官网的命令说明:
Usage: websocket-bench [options]
Options:
-h, --help Output usage information
-V, --version Output the version number
-a, --amount Total number of persistent connection, Default to 100
-c, --concurency Concurent connection per second, Default to 20
-w, --worker Number of worker(s)
-g, --generator Js file for generate message or special event
-m, --message Number of message for a client. Default to 0
-o, --output
故我这里这么写
- 参数简单描述:
-a:一共的连接数,这里的关键在于不能大于系统剩余的句柄数,同时还要考虑到不能超过端口限制
-c:每秒的请求数
-w:几个工作线程执行,这里我设置为测试服务器的物理核数
-k:是否保持长连接
-v:日志
-t:这里就是关键点了,选择primus
的话,发到服务端的请求的后缀就是/primus
,一定要注意,注意,注意,下面给出解释
websocket-bench -a 20000 -c 1000 -g generator.js -t primus -p websockets -k -v ws://10.0.3.66:9905/
执行结果如下:
Launch bench with 20000 total connection, 1000 concurent connection
0 message(s) send by client
1 worker(s)
WS server : primus
file server : /home/tmp/generator.js
Benchmark Options {"generatorFile":"/home/tmp/generator.js","type":"primus","transport":"websockets","keepAlive":true,"verbose":true}
trying : 1000 ...
trying : 2000 ...
trying : 3000 ...
trying : 4000 ...
trying : 5000 ...
trying : 6000 ...
trying : 7000 ...
trying : 8000 ...
trying : 9000 ...
trying : 10000 ...
trying : 11000 ...
trying : 12000 ...
trying : 13000 ...
trying : 14000 ...
trying : 15000 ...
trying : 16000 ...
trying : 17000 ...
trying : 18000 ...
trying : 19000 ...
trying : 20000 ...
#### steps report ####
┌────────┬─────────────┬────────┬──────────────┐
│ Number │ Connections │ Errors │ Duration(ms) │
├────────┼─────────────┼────────┼──────────────┤
│ 1000 │ 1000 │ 0 │ 4432 │
├────────┼─────────────┼────────┼──────────────┤
│ 2000 │ 1000 │ 0 │ 4176 │
├────────┼─────────────┼────────┼──────────────┤
│ 3000 │ 1000 │ 0 │ 3173 │
├────────┼─────────────┼────────┼──────────────┤
│ 4000 │ 1000 │ 0 │ 2859 │
├────────┼─────────────┼────────┼──────────────┤
│ 5000 │ 1000 │ 0 │ 1858 │
├────────┼─────────────┼────────┼──────────────┤
│ 6000 │ 1000 │ 0 │ 2405 │
├────────┼─────────────┼────────┼──────────────┤
│ 7000 │ 1000 │ 0 │ 1404 │
├────────┼─────────────┼────────┼──────────────┤
│ 8000 │ 1000 │ 0 │ 1471 │
├────────┼─────────────┼────────┼──────────────┤
│ 9000 │ 1000 │ 0 │ 1432 │
├────────┼─────────────┼────────┼──────────────┤
│ 10000 │ 1000 │ 0 │ 1448 │
├────────┼─────────────┼────────┼──────────────┤
│ 11000 │ 1000 │ 0 │ 1485 │
├────────┼─────────────┼────────┼──────────────┤
│ 12000 │ 1000 │ 0 │ 1466 │
├────────┼─────────────┼────────┼──────────────┤
│ 13000 │ 1000 │ 0 │ 1520 │
├────────┼─────────────┼────────┼──────────────┤
│ 14000 │ 1000 │ 0 │ 1435 │
├────────┼─────────────┼────────┼──────────────┤
│ 15000 │ 1000 │ 0 │ 1440 │
├────────┼─────────────┼────────┼──────────────┤
│ 16000 │ 1000 │ 0 │ 1435 │
├────────┼─────────────┼────────┼──────────────┤
│ 17000 │ 1000 │ 0 │ 1503 │
├────────┼─────────────┼────────┼──────────────┤
│ 18000 │ 1000 │ 0 │ 1528 │
├────────┼─────────────┼────────┼──────────────┤
│ 19000 │ 1000 │ 0 │ 1458 │
├────────┼─────────────┼────────┼──────────────┤
│ 20000 │ 1000 │ 0 │ 1099 │
└────────┴─────────────┴────────┴──────────────┘
#### total report ####
┌────────┬─────────────┬────────┬──────────────┬──────────────┬──────────────┐
│ Number │ Connections │ Errors │ Message Send │ Message Fail │ Duration(ms) │
├────────┼─────────────┼────────┼──────────────┼──────────────┼──────────────┤
│ 20000 │ 20000 │ 0 │ 0 │ 0 │ 20133 │
└────────┴─────────────┴────────┴──────────────┴──────────────┴──────────────┘
generator.js 文件内容
module.exports = {
/**
* Before connection (optional, just for faye)
* @param {client} client connection
*/
beforeConnect : function(client) {
// Example:
// client.setHeader('Authorization', 'OAuth abcd-1234');
// client.disable('websocket');
},
/**
* On client connection (required)
* @param {client} client connection
* @param {done} callback function(err) {}
*/
onConnect : function(client, done) {
// Faye client
// client.subscribe('/channel', function(message) { });
// Socket.io client
// client.emit('test', { hello: 'world' });
// Primus client
var json = {"id":"1597740003592","type":"1","from":"A","to":"sys","body":"你好~1597740003592","timestamps":"1597740003592"};
client.write(json);
// WAMP session
// client.subscribe('com.myapp.hello').then(function(args) { });
done();
},
/**
* Send a message (required)
* @param {client} client connection
* @param {done} callback function(err) {}
*/
sendMessage : function(client, done) {
// Example:
// client.emit('test', { hello: 'world' });
// client.publish('/test', { hello: 'world' });
// client.call('com.myapp.add2', [2, 3]).then(function (res) { });
// Primus client
var jsonSend = '{"body":"1111","convid":"A-B","from":"A","id":"1597740584552","timestamps":"1597740584552","to":"B","type":"4"}';
client.write(jsonSend);
done();
},
/**
* WAMP connection options
*/
options : {
// realm: 'chat'
}
};
server端问题定位
针对 primus
问题
pipeline
.addLast("http-server-codec", new HttpServerCodec())//包括HttpRequestDecoder和HttpResponseEncoder
.addLast("http-object-aggregator", new HttpObjectAggregator(512 * 1024))//最大512kb
.addLast("http-decompressor", new HttpContentCompressor())//压缩
.addLast("chunked-write", new ChunkedWriteHandler())
.addLast("ws-server-protocol", new WebSocketServerProtocolHandler("/primus")) //没错,这里要改成这个
.addLast("ws-compression", new WebSocketServerCompressionHandler())
针对 -k
保持连接问题
后台会收到primus::ping::1597835497940
这种数据串,在handler处理下就行。不清楚 websocket-bench 需要在primus
下,需要什么样的PONG
类型,我这里的处理方式只是直接抛给TailContext
尾节点处理
机器性能这里描述下:
核数为:
Socket(s) * Core(s) per socket = 16
内存为:64G
java8@linux-u734:~> lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 16
On-line CPU(s) list: 0-15
Thread(s) per core: 1
Core(s) per socket: 1
Socket(s): 16
NUMA node(s): 2
Vendor ID: GenuineIntel
CPU family: 6
Model: 85
Stepping: 4
CPU MHz: 2300.000
BogoMIPS: 4600.00
Hypervisor vendor: VMware
Virtualization type: full
L1d cache: 32K
L1i cache: 32K
L2 cache: 1024K
L3 cache: 16896K
NUMA node0 CPU(s): 0-7
NUMA node1 CPU(s): 8-15
java8@linux-u734:~> free -g
total used free shared buffers cached
Mem: 62 19 43 0 0 16
-/+ buffers/cache: 2 60
Swap: 2 0 2
后端单机 java 程序的性能如下:
连接数一共3w,没有报错,客户端有两台,一台2w,一台1w
#### total report ####
┌────────┬─────────────┬────────┬──────────────┬──────────────┬──────────────┐
│ Number │ Connections │ Errors │ Message Send │ Message Fail │ Duration(ms) │
├────────┼─────────────┼────────┼──────────────┼──────────────┼──────────────┤
│ 10000 │ 10000 │ 0 │ 0 │ 0 │ 17809 │
└────────┴─────────────┴────────┴──────────────┴──────────────┴──────────────┘
┌────────┬─────────────┬────────┬──────────────┬──────────────┬──────────────┐
│ Number │ Connections │ Errors │ Message Send │ Message Fail │ Duration(ms) │
├────────┼─────────────┼────────┼──────────────┼──────────────┼──────────────┤
│ 20000 │ 20000 │ 0 │ 0 │ 0 │ 20086 │
└────────┴─────────────┴────────┴──────────────┴──────────────┴──────────────┘
java8@linux-u734:~> top -p 16109
建立连接的时候,cpu瞬时高峰在100%左右
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
16109 java8 20 0 18.8g 1.1g 12m S 120% 1.7 10:37.35 java
gc的回收情况,ygc会频繁点,fgc很少
java8@linux-u734:~> jstat -gcutil 16109 1000
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 80.57 8.45 40.28 95.23 89.58 165 3.316 1 0.179 3.495
0.00 80.57 33.28 40.28 95.23 89.58 165 3.316 1 0.179 3.495
0.00 80.57 62.27 40.28 95.23 89.58 165 3.316 1 0.179 3.495
0.00 80.57 94.40 40.28 95.23 89.58 165 3.316 1 0.179 3.495
61.81 0.00 10.11 47.75 95.23 89.58 166 3.354 1 0.179 3.534
61.81 0.00 21.85 47.75 95.23 89.58 166 3.354 1 0.179 3.534
61.81 0.00 34.79 47.75 95.23 89.58 166 3.354 1 0.179 3.534
61.81 0.00 44.78 47.75 95.23 89.58 166 3.354 1 0.179 3.534
61.81 0.00 50.11 47.75 95.23 89.58 166 3.354 1 0.179 3.534
61.81 0.00 74.89 47.75 95.23 89.58 166 3.354 1 0.179 3.534
61.81 0.00 82.40 47.75 95.23 89.58 166 3.354 1 0.179 3.534
61.81 0.00 95.23 47.75 95.23 89.58 166 3.354 1 0.179 3.534
0.00 78.79 11.74 54.10 95.23 89.58 167 3.393 1 0.179 3.572
0.00 78.79 20.07 54.10 95.23 89.58 167 3.393 1 0.179 3.572
0.00 78.79 32.35 54.10 95.23 89.58 167 3.393 1 0.179 3.572
0.00 78.79 44.46 54.10 95.23 89.58 167 3.393 1 0.179 3.572
0.00 78.79 56.51 54.10 95.23 89.58 167 3.393 1 0.179 3.572
0.00 78.79 67.21 54.10 95.23 89.58 167 3.393 1 0.179 3.572
0.00 78.79 67.37 54.10 95.23 89.58 167 3.393 1 0.179 3.572
0.00 78.79 67.37 54.10 95.23 89.58 167 3.393 1 0.179 3.572
0.00 78.79 73.58 54.10 95.23 89.58 167 3.393 1 0.179 3.572
0.00 78.79 76.25 54.10 95.23 89.58 167 3.393 1 0.179 3.572
0.00 78.79 79.68 54.10 95.23 89.58 167 3.393 1 0.179 3.572
0.00 78.79 82.03 54.10 95.23 89.58 167 3.393 1 0.179 3.572
0.00 78.79 85.38 54.10 95.23 89.58 167 3.393 1 0.179 3.572
0.00 78.79 94.62 54.10 95.23 89.58 167 3.393 1 0.179 3.572
46.73 0.00 1.32 62.40 95.23 89.58 168 3.429 1 0.179 3.608
参考文章
实现单台测试机6万websocket长连接
websocket-bench官方