Swoole从入门到入土(3)——TCP服务器[基本配置项]

在这一节的开篇,让我们先解决上一节的“配置”话题。对于server对象,有很多配置项决定了服务端的行为,可以用set的函数进行配置的设置。

 

1、函数set:用于设置运行时的各项参数。服务器启动后通过 $serv->setting 来访问 Server->set 方法设置的参数数组。

Swoole\Server->set(array $setting): void

$setting:配置项数组。

注意:函数set必须在 Server->start() 前调用。

示例:

$server->set(array(
    'reactor_num'   => 2,     // reactor thread num
    'worker_num'    => 4,     // worker process num
    'backlog'       => 128,   // listen backlog
    'max_request'   => 50,
    'dispatch_mode' => 1,
));

每个配置项的意义,下面会进行介绍。

 

 

2、常用配置项

1) 属性reactor_num:设置启动的 Reactor 线程数。【默认值:CPU 核数】什么是reactor线程呢?点击这里查看上一节常识科普

说明:

通过此参数来调节主进程内事件处理线程的数量,以充分利用多核。默认会启用 CPU 核数相同的数量。
Reactor 线程是可以利用多核,如:机器有 128 核,那么底层会启动 128 线程。
每个线程能都会维持一个 EventLoop。线程之间是无锁的,指令可以被 128 核 CPU 并行执行。
考虑到操作系统调度存在一定程度的性能损失,可以设置为 CPU 核数 * 2,以便最大化利用 CPU 的每一个核。

建议设置为 CPU 核数的 1-4 倍,但最大不得超过 swoole_cpu_num() * 4。

 

2) worker_num:设置启动的 Worker 进程数。【默认值:CPU 核数】什么是Worker进程呢?点击这里查看上一节常识科普

说明:

如果业务代码是全异步 IO 的,这里设置为 CPU 核数的 1-4 倍最合理。
如果业务代码为同步 IO,需要根据请求响应时间和系统负载来调整,例如:100-500
默认设置为 swoole_cpu_num(),最大不得超过 swoole_cpu_num() * 1000
假设每个进程占用 40M 内存,100 个进程就需要占用 4G 内存,如何正确查看进程的内存占用请参考 Swoole 官方视频教程

举例:

如 1 个请求耗时 100ms,要提供 1000QPS 的处理能力,那必须配置 100 个进程或更多。
但开的进程越多,占用的内存就会大大增加,而且进程间切换的开销就会越来越大。所以这里适当即可。不要配置过大。

 

3) max_request:设置 worker 进程的最大任务数。【默认值:0 即不会退出进程】

说明:

一个 worker 进程在处理完超过此数值的任务后将自动退出,进程退出后会释放所有内存和资源。

这个参数的主要作用是解决由于程序编码不规范导致的 PHP 进程内存泄露问题。PHP 应用程序有缓慢的内存泄漏,但无法定位到具体原因、无法解决,可以通过设置 max_request 临时解决,但是项目要持久运行还是必须找到内存泄漏的代码并修复。

达到 max_request 不一定马上关闭进程,参考 max_wait_time。

SWOOLE_BASE 下,达到 max_request 重启进程会导致客户端连接断开。

当 worker 进程内发生致命错误或者人工执行 exit 时,进程会自动退出。master 进程会重新启动一个新的 worker 进程来继续处理请求。

 

4) max_wait_time:设置 Worker 进程收到停止服务通知后最大等待时间【默认值:3】

说明:

经常会碰到由于 worker 阻塞卡顿导致 worker 无法正常 reload, 无法满足一些生产场景,例如发布代码热更新需要 reload 进程。所以,我们加入了进程重启超时时间的选项。

管理进程收到重启、关闭信号后或者达到 max_request 时,管理进程会重起该 worker 进程。分以下几个步骤:

    · 底层会增加一个 (max_wait_time) 秒的定时器,触发定时器后,检查进程是否依然存在,如果是,会强制杀掉,重新拉一个进程。

    · 需要在 onWorkerStop 回调里面做收尾工作,需要在 max_wait_time 秒内做完收尾。

    · 依次向目标进程发送 SIGTERM 信号,杀掉进程。

 

5) backlog:设置 Listen 队列长度

举例:

如 backlog => 128,此参数将决定最多同时有多少个等待 accept 的连接。

说明:

关于 TCP 的 backlog

    · 我们知道 TCP 有三次握手的过程,客户端 syn=>服务端 syn+ack=>客户端 ack,当服务器收到客户端的 ack 后会将连接放到一个叫做 accept queue 的队列里面(linux2.2 之后握手过程分为 syn queue 和 accept queue 两个队列,syn queue 长度由 tcp_max_syn_backlog 决定)

    · 队列的大小由 backlog 参数和配置 somaxconn 的最小值决定,我们可以通过 ss -lt 命令查看最终的 accept queue 队列大小,Swoole 的主进程调用 accept(高版本内核调用的是 accept4,为了节省一次 set no block 系统调用)

    · 从 accept queue 里面取走。 当 accept queue 满了之后连接有可能成功(成功是通过 TCP 的重传机制,相关的配置有 tcp_synack_retries 和 tcp_abort_on_overflow)

    · 也有可能失败,失败后客户端的表现就是连接被重置( 客户端收到 syn+ack 包就认为连接成功了,实际上服务端还处于半连接状态,有可能发送 rst 包给客户端,客户端的表现就是 Connection reset by peer

    · 或者连接超时,而服务端会记录失败的记录,可以通过 netstat -s|grep 'times the listen queue of a socket overflowed 来查看日志。如果出现了上述现象,你就应该调大该值了。 幸运的是 Swoole 的 SWOOLE_PROCESS 模式与 PHP-FPM/Apache 等软件不同,并不依赖 backlog 来解决连接排队的问题。所以基本不会遇到上述现象。

 

6) dispatch_mode:数据包分发策略。【默认值:2】

说明:

建议:

无状态 Server 可以使用 1 或 3,同步阻塞 Server 使用 3,异步非阻塞 Server 使用 1

有状态使用 2、4、5

在UDP模式下:

dispatch_mode=2/4/5 时为固定分配,底层使用客户端 IP 取模散列到不同的 Worker 进程,算法为 ip2long(ClientIP) % worker_num

dispatch_mode=1/3 时随机分配到不同的 Worker 进程

dispatch_mode 配置在 SWOOLE_BASE 模式是无效的,因为 BASE 不存在投递任务,当收到客户端发来的数据后会立即在当前线程 / 进程回调 onReceive,不需要投递 Worker 进程。

注意:

dispatch_mode=1/3 时,底层会屏蔽 onConnect/onClose 事件,原因是这 2 种模式下无法保证 onConnect/onClose/onReceive 的顺序;

非请求响应式的服务器程序,请不要使用模式 1 或 3。例如:http 服务就是响应式的,可以使用 1 或 3,有 TCP 长连接状态的就不能使用 1 或 3。

 

 

Swoole最基本配置项就以上这些啦,这一篇到这里就结束了,其它的配置项,包括重启、心跳机制会在之后的文章中慢慢介绍。大家下期见

 

---------------------------  我是可爱的分割线  ----------------------------

最后博主借地宣传一下,漳州编程小组招新了,这是一个面向漳州青少年信息学/软件设计的学习小组,有意向的同学点击链接,联系我吧。

posted on 2020-09-03 21:50  咚..咚  阅读(693)  评论(0编辑  收藏  举报

导航