六、Swoole 基础学习笔记 - 深入学习 Tcp Server 运行时参数配置
hi,我是温新,一名PHPer
文章基于 Swoole 5.0 版本编写。
学习目标:记住 Swoole Tcp 常用配置,了解其他相关配置
说明:本篇文章结合官方文档编写及参考网络资料编写,虽非全部原创,但也是结合了自己的理解,若转载请附带本文 URL,编写不易,持续编写更不易,谢谢!
上篇文章正式对是 Tcp Server 进行了一个记录,本篇文章将学习相关参数的配置。本篇文章将学习常用参数的配置,没有记录的参数请参考官方文档。
set 配置
max_conn
作用:服务器程序,最大允许的连接数(默认值为: ulimit -n)。
如:max_conn => 1000 ,设置 Server 最大允许维持 1000 个 TCP 连接。超过此数量后,新进入的连接将被拒绝。
max_conn 不允许设置太小,最设置的最小值为: (worker_num + task_worker_num) * 2 + 32
max_request
作用:设置 worker 进程的最大任务数。【默认值:0 即不会退出进程】。一个 worker 进程在处理完超过此数值的任务后将自动退出,进程退出后会释放所有内存和资源。
注意:此选项可以用于防止 worker 进程内存溢出。
演示:
<?php
$server->set([
	'worker_num' 	=> 2,
	'reactor_num' 	=> 3,
    // 设置进程最大处理数
	'max_request'	=> 2,
]);
配置好之后,使用另外一个客服端连接服务器,连接成功后向服务端发送数据,然后看看进程的变化:
# 客户端连接之前
$pstree -p 18001
php(18001)─┬─php(18002)─┬─php(18005)
           │            └─php(18006)
           ├─{php}(18003)
           └─{php}(18004)
# 客户端连接之后
$pstree -p 18001
php(18001)─┬─php(18002)─┬─php(18005)
           │            └─php(18087)# 进程发生变化
           ├─{php}(18003)
           └─{php}(18004)
task_worker_num
作用:配置 Task 进程数量。
注意:配置 task_worker_num 参数后,务必在 Server 中注册 onTask、onFinish 事件回调。若没有注册,服务器程序将无法启动。
提示:
- Task进程是同步阻塞的;
- 最大值不得超过 swoole_cpu_num() * 1000;
- 
计算方法
- 单个 task的处理耗时,如100ms,那一个进程 1 秒就可以处理1/0.1=10个 task;
- 
task投递的速度,如每秒产生2000个task;
- 
2000/10=200,需要设置task_worker_num => 200,启用200个 Task 进程。
 
- 单个 
演示:
<?php
// *** 省略
$server->set([
	'worker_num' 	=> 2,
	'reactor_num' 	=> 3,
	'task_worker_num' => 2,
]);
// 监听异步任务
$server->on('Task', function($server, $taskId, $srcWorkerId, $data) {
});
// 监听异步任务完成
$server->on('Finish', function($server, $taskId, $data) {
});
// *** 省略
daemonize
作用:守护进程化【默认值:false】。设置 daemonize => true 时,程序将转入后台作为守护进程运行。长时间运行的服务器端程序必须启用此项。如果不启用守护进程,当 ssh 终端退出后,程序将被终止运行。
提示:
- 启用守护进程后,标准输入和输出会被重定向到 log_file;
- 如果未设置 log_file,将重定向到/dev/null,所有打印屏幕的信息都会被丢弃;
- 启用守护进程后,CWD(当前目录)环境变量的值会发生变更,相对路径的文件读写会出错。PHP程序中必须使用绝对路径。
$server->set([
    daemonize => true,
]);
方法
on
作用:用于注册 Server 的事件回调函数。
在之前的文章中见到它的次数很多了,监听某个事件回调就用它。要注意的是,重复调用同一个事件时,新的覆盖旧的,如下案例:
// 旧的
$server->on('Task', function($server, $taskId, $srcWorkerId, $data) {
});
// 新的
$server->on('Task', function($server, $taskId, $srcWorkerId, $data) {
});
start
作用:启动服务器,监听所有 TCP/UDP 端口。
reload
作用:安全地重启所有 Worker/Task 进程。
stop
作用:使当前 Worker 进程停止运行,并立即触发 onWorkerStop 回调函数。
shutdown
作用:关闭服务。
close
作用:关闭客户端连接。
send
作用:向客户端发送数据。
sendfile
发送文件到 TCP 客户端连接。
sendto
作用:向任意的客户端 IP:PORT 发送 UDP 数据包。
sendMessage
作用:向任意 worker 进程或 task  进程发送消息。在非主进程和管理进程中可调用。收到消息的进程会触发 onPipeMessage 事件。
exists
作用:检测 fd 对应的连接是否存在。
getClientInfo
作用:获取连接的客户端信息。
getClientList
作用:遍历当前 Server 所有的客户端连接,Server::getClientList 方法是基于共享内存的,不存在 IOWait,遍历的速度很快。另外 getClientList 会返回所有 TCP 连接,而不仅仅是当前 Worker 进程的 TCP 连接。别名是 Swoole\Server->connection_list()。
getWorkerId
作用:获取当前 Worker 进程 id(非进程的 PID)。
getWorkerPid
作用:获取当前 Worker 进程 PID。
getWorkerStatus
作用:获取 Worker 进程状态。
getManagerPid
作用:获取当前服务的 Manager 进程 PID。
getMasterPid
作用:获取当前服务的 Master 进程 PID。
案例演示
使用 send 向客户端发送消息
<?php
$server = new Swoole\Server('0.0.0.0', 9501, SWOOLE_PROCESS, SWOOLE_SOCK_TCP);
$server->on('Receive', function ($server, $fd, $reactorId, $data) {
	// 向客服端发送数据
	$server->send($fd, 'Server:Hello ' . $fd . ' ,你发送的消息是: ' . $data) . PHP_EOL;
});
$server->start();
使用 sendFile 发送文件信息
<?php
$server = new Swoole\Server('0.0.0.0', 9501, SWOOLE_PROCESS, SWOOLE_SOCK_TCP);
$server->on('Receive', function ($server, $fd, $reactorId, $data) {
	// 向客服端发送文件信息
	$server->sendFile($fd, './message.txt');
});
$server->start();
属性
setting
作用:获取 set() 函数设置的所有参数。
演示:
<?php
// 其他的省略
$server->set([
	'worker_num' 	=> 2,
	'reactor_num' 	=> 3,
	'task_worker_num' => 2,
]);
$server->on('Start', function($server) {
	print_r($server->setting);
});
输出结果如下:
$php 3-swoole-tcp-param.php 
Array
(
    [worker_num] => 2
    [reactor_num] => 3
    [task_worker_num] => 2
    [output_buffer_size] => 4294967295
    [max_connection] => 1024
)
$master_pid
作用:返回当前服务器主进程的 PID
$manager_id
作用:返回当前服务器管理进程的 PID
$worker_id
作用:获取当前 Worker 进程的编号,包含 Task 进程
$worker_pid
作用:获取当前 Worker 进程的操作系统进程 ID。
$taskworker
作用:当前进程是否是 Task 进程。
返回值:boolean。true 表示当前进程是 Task 进程;false 表示当前进程是 Worker 进程。
$connections
作用:包含所有 TCP 连接
综合演示:
<?php
$server = new Swoole\Server('0.0.0.0', 9501, SWOOLE_PROCESS);
$server->set([
	'worker_num' 	=> 2,
	'reactor_num' 	=> 3,
	'task_worker_num' => 2,
]);
$server->on('Connect', function ($server, $fd, $reactorId) {
        echo $fd . ' 连接了' . PHP_EOL;
});
$server->on('Start', function($server) {
});
$server->on('Receive', function ($server, $fd, $fromId, $data) {
	echo '主进程 ' . $server->master_pid . PHP_EOL;
	echo '管理进程 ' . $server->manager_pid . PHP_EOL;
	// 当前客户端连接的 Worker PID
	echo 'workerPid 进程 ' . $server->worker_pid . PHP_EOL;
	echo 'worker 进程 ' . $server->worker_id . PHP_EOL;
	
	foreach ($server->connections as $fd) {
		echo $fd . PHP_EOL;
	}
});
$server->on('Workerstart', function ($server) {
	if ($server->taskworker) {
		echo 'task pid ' . $server->worker_pid . PHP_EOL;
	} else {
		echo 'worker pid' . $server->worker_pid . PHP_EOL;
	}
});
// 监听异步任务
$server->on('Task', function($server, $taskId, $srcWorkerId, $data) {
});
// 监听异步任务完成
$server->on('Finish', function($server, $taskId, $data) {
});
$server->on('Close', function ($server,$fd) {
});
$server->start();
事件
onStart
作用:启动后在主进程(master)的主线程回调此函数。
onStart回调中,仅允许echo、打印Log、修改进程名称。不得执行其他操作 (不能调用server相关函数等操作,因为服务尚未就绪)。onWorkerStart和onStart回调是在不同进程中并行执行的,不存在先后顺序。
onWorkerStart
作用:此进程在 Worker 进程 / Task 进程启动时发生,这里创建的对象可以在进程生命周期内使用。
注意:onWorkerStart/onStart 是并发执行的,没有先后顺序。可以通过 taskworker 属性来判断是 worker 进程还是 task 进程。
onWorkerStop
作用:此事件在 Worker 进程终止时发生。在此函数中可以回收 Worker 进程申请的各类资源。
注意: 进程异常结束,如被强制 kill、致命错误、core dump 时无法执行 onWorkerStop 回调函数。
onConnect
作用:有新的连接进入时,在 worker 进程中回调。
注意:onConnect/onClose 这 2 个回调发生在 Worker 进程内,而不是主进程。
onReceive
作用:接收到数据时回调此函数,发生在 worker 进程中。
onPacket
作用:接收到 UDP 数据包时回调此函数,发生在 worker 进程中。
UDP 服务中,只需要监听这一个事件即可。
onTask
作用:在 task 进程内被调用。worker 进程可以使用 task 函数向 task_worker 进程投递新的任务。当前的 task 进程在调用 onTask 回调时会将进程状态切换为忙碌,这时将不再接收新的 task,当 onTask 函数返回时会将进程状态切换为空闲然后继续接收新的 Task。
onFinish
作用:此回调函数在 worker 进程被调用,当 worker 进程投递的任务在 task 进程中完成时,task 进程会通过 finish() 方法将任务处理的结果发送给 worker 进程。
onPipeMessage
作用:当工作进程收到由 $server->sendMessage() 发送的 unixSocket 消息时会触发 onPipeMessage 事件。worker/task进程都可能会触发onPipeMessage` 事件
onWorkerError
作用:当 Worker/Task 进程发生异常后会在 Manager 进程内回调此函数。
onManagerStart
作用:当管理进程启动时触发此事件
onManagerStop
onBeforeReload
作用:Worker 进程 Reload 之前触发此事件,在 Manager 进程中回调
onAfterReload
作用:Worker 进程 Reload 之后触发此事件,在 Manager 进程中回调
onShutdown
作用:此事件在 Server 正常结束时发生
onBeforeShutdown
作用:此事件在 Server 正常结束前发生
演示:
修改进程名称
<?php
$server = new Swoole\Server('0.0.0.0', 9501, SWOOLE_PROCESS);
$server->set([
    'worker_num' 	 => 3,
    'task_worker_num'=> 2,
]);
$server->on('Connect', function ($server, $fd) {
});
$server->on('Receive', function ($server, $fd, $reactorId, $data) {
});
// 设置 task 进程后,必须调用任务回调,不然会报错
$server->on('Task', function (Swoole\Server $server, Swoole\Server\Task $task) {
});
// 启动 master 进程时,设置进程名称
$server->on('Start', function ($server) {
    swoole_set_process_name('swoole:master');
});
// 管理进程启动时,设置名称
$server->on('ManagerStart', function ($server) {
    swoole_set_process_name('swoole:manager');
});
// worker 进程启动时,回调该事件,在这里我们对进程这是名称
$server->on('WorkerStart', function ($server, $workerId) {
    if($workerId >= $server->setting['worker_num']) {
        swoole_set_process_name("swoole:task worker");
    } else {
        swoole_set_process_name("swoole:php worker");
    }
});
$server->on('Close', function ($server, $fd) {
});
$server->start();
进程之前发送消息
<?php
// 进程之间发送消息
$server = new Swoole\Server('0.0.0.0', 9501, SWOOLE_PROCESS);
$server->set([
    'worker_num' => 5,
    'reactor_num' => 3,
]);
$server->on('Receive', function ($server, $fd, $reactorId, $data) {
	// 向其他进程发送消息
	$server->sendMessage('hello', 1 - $server->worker_id);
});
// 监听管道,接收其他 进程发送的消息
$server->on('pipeMessage', function ($server, $srcWorkerId, $data) {
	echo 'pipeMessage #' . $server->worker_id . ' message from #' . $srcWorkerId . $data . PHP_EOL;
});
$server->start();
输出结果:pipeMessage #1 message from #0hello
本篇文章至此就结束了,我是温新,我们下一篇文章见。