swoole optimized configuration and stress test
1, Server hardware:
2 vCPU 4 GB (I/O optimization) 100Mbps (peak)
2, Server side:
$server = new \swoole_websocket_server("0.0.0.0", 9556); $options = [ 'max_connection' => 150000, // Maximum number of links 'worker_num' => 6, // Number of worker s // swFactoryProcess_finish: send failed, session#1 output buffer has been overflowed. // When the server has a large number of TCP connections, in the worst case, it will occupy serv - > Max connection * buffer Ou output Ou size bytes of memory 'socket_buffer_size' => 512 * 1024 * 1024, // M must be a number to set the maximum amount of memory allowed for client connections // Heartbeat detection 'heartbeat_idle_time' => 30, 'heartbeat_check_interval' => 10, // 'buffer_output_size' = > 2 / / used to set the maximum single send length M ]; $server->set($options); $server->on('open', function ($server, $req) { error_log(date('Y-m-d H:i:s') . 'open connection count : ' . count($server->connections) . "\n", 3, './result.log'); }); $server->on('message', function ($server, $frame) { $count = count($server->connections); error_log(date('Y-m-d H:i:s') . "Shared by current server " . $count . " A connection\n", 3, './result.log'); $message = json_decode($frame->data, true); if (isset($message['messageType'])) { switch ($message['messageType']) { case 'ping': error_log(date('Y-m-d H:i:s') . "Shared by current server " . $count . " A connection\n", 3, './result.log'); $testFd = file_get_contents('./fd.log'); for ($index = 1; $index <= $count; $index++) { $server->push( $testFd, json_encode( [ 'messageType' => 'pong', 'connection_num' => $count, 'index' => $index, 'time' => microtime(true), 'data' => '{"messageType": "join_req", "data": {"roomId": "124","userId": numMax,"nickName": "nickName","avatar": "avatar","message": "message","role":0,"level":5,"masterUserId":111,"masterNickNam e":"masterNickName","masterAvatar":"masterAvatar","masterLevel":9}}' ] ) ); } break; case 'opon': file_put_contents('./fd.log', $frame->fd); break; default: break; } } if (file_exists('./fd.log')) { $fd = file_get_contents('./fd.log'); $server->push( intval($fd), json_encode( [ 'messageType' => 'Concurrent:' . $count . ' Client to specify a single client ' . $fd . ' Send message', 'connection_num' => $count, 'fd' => $frame->fd, 'time' => microtime(true), 'data' => '{"messageType": "join_req", "data": {"roomId": "124","userId": numMax,"nickName": "nickName","avatar": "avatar","message": "message","role":0,"level":5,"masterUserId":111,"masterNickNam e":"masterNickName","masterAvatar":"masterAvatar","masterLevel":9}}' ] ) ); } }); $server->on('close', function ($server, $fd) { if (file_exists('./fd.log')) { $testFd = file_get_contents('./fd.log'); $server->push( intval($testFd), json_encode( [ 'messageType' => 'pong', 'connection_num' => count($server->connections), 'fdClose' => $fd, 'time' => microtime(true), 'data' => '{"messageType": "join_req", "data": {"roomId": "124","userId": numMax,"nickName": "nickName","avatar": "avatar","message": "message","role":0,"level":5,"masterUserId":111,"masterNickNam e":"masterNickName","masterAvatar":"masterAvatar","masterLevel":9}}' ] ) ); if ($fd == $testFd) { unlink('./fd.log'); } } error_log( date('Y-m-d H:i:s') . "Current server close Client, now shared " . count($server->connections) . " A connection\n", 3, './result.log' ); }); $server->start();
3, Client:
Client kernel optimization:
http://rango.swoole.com/archives/185
https://wiki.swoole.com/wiki/page/p-c100k.html
Modify the following file: vim /etc/sysctl.conf
net.ipv6.conf.all.disable_ipv6 = 1 net.ipv6.conf.default.disable_ipv6 = 1 net.ipv6.conf.lo.disable_ipv6 = 1 vm.swappiness = 0 net.ipv4.neigh.default.gc_stale_time=120 net.ipv4.conf.all.rp_filter=0 net.ipv4.conf.default.rp_filter=0 net.ipv4.conf.default.arp_announce = 2 net.ipv4.conf.lo.arp_announce=2 net.ipv4.conf.all.arp_announce=2 #net.ipv4.tcp_max_tw_buckets = 5000 net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_max_syn_backlog = 1024 net.ipv4.tcp_synack_retries = 2 kernel.sysrq = 1 #optimization net.ipv4.tcp_tw_recycle = 1 net.ipv4.ip_local_port_range = 10000 65535 net.ipv4.tcp_syn_retries = 2 net.ipv4.tcp_synack_retries = 2 net.ipv4.tcp_fin_timeout = 10 net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_keepalive_intvl = 10 net.ipv4.tcp_keepalive_probes = 5 net.ipv4.tcp_keepalive_time = 300 net.ipv4.tcp_retries2=3 net.ipv4.tcp_orphan_retries=2 //The terminal takes effect immediately: sysctl -p
Configuration and installation of pressure measuring tools:
vim generator.js module.exports = { beforeConnect : function(client) { }, onConnect : function(client, done) { client.write({"messageType": "join_req"}); done(); // It is used to close the client process after the link is suspended; if the client needs to suspend the process and keep the long link, the method in the closure function can be annotated }, sendMessage : function(client, done) { client.write({"messageType": "join_req"}); done(); }, options : { } };
4, Server kernel optimization:
Set ulimit value (number of Linux file handles)
Optimize the number of open files [permanently effective]
vim /etc/security/limits.conf * soft nofile 102400 * hard nofile 102400
Note: to modify this file, you need to restart the system to take effect
5, Testing
Test statement:
websocket-bench -a 40000 -c 40000 -w 8 -t primus -p websockets ws://192.168.1.2:9556 -g generator.js -o result.log