使用的是官方的demo
客户端代码
require __DIR__ . '/workerman/Autoloader.php';
use Workerman\Worker;
use Workerman\Lib\Timer;
use Workerman\Connection\AsyncTcpConnection;
$worker = new Worker();
$worker->onWorkerStart = 'connect';
function connect(){
static $count = 0;
// 2000个链接
if ($count++ >= 10000) return;
// 建立异步链接
$con = new AsyncTcpConnection('ws://127.0.0.1:3458');
$con->onConnect = function($con) {
// 递归调用connect
connect();
};
$con->onMessage = function($con, $msg) {
//echo "recv $msg\n";
};
$con->onClose = function($con) {
echo "con close\n";
};
// 当前链接每10秒发个心跳包
Timer::add(10, function()use($con){
$con->send("ping");
});
$con->connect();
echo $count, " connections complete\n";
}
Worker::runAll();
服务端代码
public static function onConnect($client_id)
{
// 向当前client_id发送数据
Gateway::sendToClient($client_id, "Hello $client_id\r\n");
// 向所有人发送
Gateway::sendToAll("$client_id login\r\n");
}
/**
* 当客户端发来消息时触发
* @param int $client_id 连接id
* @param mixed $message 具体消息
*/
public static function onMessage($client_id, $message)
{
// 向所有人发送
// Gateway::sendToAll("$client_id said $message\r\n");
}
服务器8核
客户端与服务器在同一台服务器上 本机访问
gateaway进程8个 business24个
cpu占用一半 内存几乎没用
event内核已安装 linux内核已优化
onMessage里的广播没屏蔽前跑到两千多就卡了,屏蔽后1w连接需要6,7分钟才能完成
想请教下是原本就是这样还是我linux优化不到位
/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
# see details in https://help.aliyun.com/knowledge_detail/39428.html
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.core.somaxconn= 65535
net.core.netdev_max_backlog = 30000
net.ipv4.tcp_tw_recycle = 0
fs.file-max = 6815744
# see details in https://help.aliyun.com/knowledge_detail/41334.html
net.ipv4.tcp_max_tw_buckets = 20000
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 262144
net.ipv4.tcp_synack_retries = 2
kernel.sysrq=1
kernel.pid_max=3999999
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) 63456
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 102400
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) 63456
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
广播Gateway::sendToAll是很耗时的操作,需要和所有gateway通讯,并且将数据发给所有在线连接,如果在线人数多会占用大量的cpu资源和带宽资源。所以不要轻易调用Gateway::sendToAll广播数据。
一般来说普通服务器包量极限大概在10W-20W/S左右,超过这个量服务器负载就很高了,会很慢。如果是多队列网卡可以成倍增加这个极限。
你的业务代码是在onConnect也就是在有客户端连接时调用Gateway::sendToAll广播。这样会导致随着连接越来越多最后连接速度越来越慢。原因主要是当连接很多时广播数据会造成大量的包量和流量,假设已经有1w个连接,每秒有10个新连接连上来,那就是每秒广播10次数据给1w个连接,每秒10W个数据包,假设每个数据包100字节,那么每秒产生的流量大约为 80Mb/s的数据。这么大的数量和包量一般的服务器已经是极限了。假设每个数据包是1000字节,那么流量直接干到800Mb,需要服务器有G口的带宽了。要知道一个普通机房出口带宽才10G-20G左右。
如果你在onMessage里也用Gateway::sendToAll广播,由于客户端是每10秒发送一个ping,当服务器有2000个连接时,也就是服务端每秒收到200个ping,然后每秒广播200次
$client_id said $message
。则每秒产生的包量为2000*200=20W
个包,产生的流量大概150M左右。同样普通服务器支撑不了这么大的包量。所以不是随便写几行代码就能支撑万人在线,当在线人数很多时要考虑的地方很多。最主要的是减少通讯请求量,尤其不要随便广播数据。
我第一感觉也是包太多,后台看流量达到150m了 本还希冀于我优化没搞好。请问正常业务下统计在线人数给用户 还有用户发来消息,展示给所有人有什么好的方法么 直播间大概1w人吧
统计在线人数有专门的接口,但是你千万别有个新连接就调用接口统计一次并广播,那样你会看到数字一直在跳,而且浪费cpu和带宽。你可以在0号进程开个定时器10秒统计一次。如果人数很多,上万人,实际上不需要100%精确统计,误差1000都可以接受。超过1万人你可以显示为1.x万人,如果本次统计1.x与上次统计1.x相等,则可以省略一次广播推送。同理几千人在线的话,100内的误差忽略不记,显示为x千人。记住广播很耗费资源,能省就省。
谢谢老大!