reactor_num
Reactor
线程数,reactor_num => 2
,通过此参数来调节主进程内事件处理线程的数量,以充分利用多核。默认会启用CPU
核数相同的数量。
reactor_num
一般设置为CPU
核数的1-4
倍,在swoole中reactor_num
最大不得超过CPU核数*4
。
swoole
的Reactor
线程是可以利用多核,如:机器有128
核,那么底层会启动128
线程。每个线程能都会维持一个EventLoop
。线程之间是无锁的,指令可以被128
核CPU
并行执行。考虑到操作系统调度存在一定程度的性能损失,可以设置为CPU核数*2
,以便最大化利用CPU
的每一个核。
reactor_num
必须小于或等于worker_num
。如果设置的reactor_num
大于worker_num
,那么swoole会自动调整使reactor_num
等于worker_num
1.7.14
以上版本在超过8
核的机器上reactor_num
默认设置为8
worker_num
设置启动的worker进程数。
- 业务代码是全异步非阻塞的,这里设置为CPU的
1-4
倍最合理 - 业务代码为同步阻塞,需要根据请求响应时间和系统负载来调整
比如1
个请求耗时100ms
,要提供1000QPS
的处理能力,那必须配置100
个进程或更多。但开的进程越多,占用的内存就会大大增加,而且进程间切换的开销就会越来越大。所以这里适当即可。不要配置过大。
- 每个进程占用
40M
内存,那100
个进程就需要占用4G
内存
max_request
设置worker进程的最大任务数,默认为0,一个worker进程在处理完超过此数值的任务后将自动退出,进程退出后会释放所有内存和资源。
这个参数的主要作用是解决PHP进程内存溢出问题。PHP应用程序有缓慢的内存泄漏,但无法定位到具体原因、无法解决,可以通过设置max_request
解决。
max_request
只能用于同步阻塞、无状态的请求响应式服务器程序- 在swoole中真正维持客户端TCP连接的是master进程,worker进程仅处理客户端发送来的请求,因为客户端是不需要感知Worker进程重启的
- 纯异步的Server不应当设置
max_request
- 使用Base模式时
max_request
是无效的
当worker进程内发生致命错误或者人工执行
exit
时,进程会自动退出。master进程会重新启动一个新的worker进程来继续处理请求
max_conn (max_connection)
服务器程序,最大允许的连接数,如max_connection => 10000
, 此参数用来设置Server
最大允许维持多少个TCP
连接。超过此数量后,新进入的连接将被拒绝。
max_connection
最大不得超过操作系统ulimit -n
的值,否则会报一条警告信息,并重置为ulimit -n
的值max_connection
默认值为ulimit -n
的值
WARN swServer_start_check: serv->max_conn is exceed the maximum value[100000].
最大上限
底层使用了SESSION_LIST
来实现session_id
(虚拟fd
)与真实fd
的对应,因此除了max_sockets
限制之外,max_connection
还受限于SW_SESSION_LIST_SIZE
宏的设置。
目前SW_SESSION_LIST_SIZE
底层的值为1M
,请勿设置max_connection
超过1M
内存占用
max_connection
参数不要调整的过大,根据机器内存的实际情况来设置。Swoole会根据此数值一次性分配一块大内存来保存Connection
信息,可使用gdb
跟踪运行中的进程,打印p sizeof(swConnection)
得到准确的数值。在1.9.16
版本中一个TCP连接的Connection
信息,需要占用224
字节。
最小设置
此选项设置过小底层会抛出错误,并设置为ulimit -n
的值。
最小值为
(serv->worker_num + SwooleG.task_worker_num) * 2 + 32
serv->max_connection is too small.
dispatch_mode
数据包分发策略。可以选择3种类型,默认为2
- 1,轮循模式,收到会轮循分配给每一个worker进程
- 2,固定模式,根据连接的文件描述符分配worker。这样可以保证同一个连接发来的数据只会被同一个worker处理
- 3,抢占模式,主进程会根据Worker的忙闲状态选择投递,只会投递给处于闲置状态的Worker
- 4,IP分配,根据客户端IP进行取模hash,分配给一个固定的worker进程。可以保证同一个来源IP的连接数据总会被分配到同一个worker进程。算法为
ip2long(ClientIP) % worker_num
- 5,UID分配,需要用户代码中调用 $serv-> bind() 将一个连接绑定1个uid。然后swoole根据UID的值分配到不同的worker进程。算法为
UID % worker_num
,如果需要使用字符串作为UID,可以使用crc32(UID_STRING)
使用建议
- 无状态
Server
可以使用1
或3
,同步阻塞Server
使用3
,异步非阻塞Server
使用1
- 有状态使用
2
、4
、5
dispatch_mode 4,5
两种模式,在1.7.8
以上版本可用dispatch_mode=1/3
时,底层会屏蔽onConnect
/onClose
事件,原因是这2种模式下无法保证onConnect
/onClose
/onReceive
的顺序
非请求响应式的服务器程序,请不要使用模式1或3
UDP协议
dispatch_mode=2/4/5
时为固定分配,底层使用客户端IP取模散列到不同的worker进程,算法为ip2long(ClientIP) % worker_num
dispatch_mode=1/3
时随机分配到不同的worker进程
BASE模式
dispatch_mode
配置在BASE模式是无效的,因为BASE不存在投递任务,当Reactor线程
收到客户端发来的数据后会立即在当前线程/进程回调onReceive
,不需要投递Worker进程。
daemonize
守护进程化。设置daemonize => 1
时,程序将转入后台作为守护进程运行。长时间运行的服务器端程序必须启用此项。
如果不启用守护进程,当ssh终端退出后,程序将被终止运行。
- 启用守护进程后,标准输入和输出会被重定向到
log_file
- 如果未设置
log_file
,将重定向到/dev/null
,所有打印屏幕的信息都会被丢弃 - 启用守护进程后,
CWD
(当前目录)环境变量的值会发生变更,相对路径的文件读写会出错。PHP程序中必须使用绝对路径
systemd
使用systemd
管理Swoole
服务时,请勿设置daemonize = 1
。主要原因是systemd
的机制与init
不同。init
进程的PID
为1
,程序使用daemonize
后,会脱离终端,最终被init
进程托管,与init
关系变为父子进程关系。
但systemd
是启动了一个单独的后台进程,自行fork
管理其他服务进程,因此不需要daemonize
,反而使用了daemonize = 1
会使得Swoole
程序与该管理进程失去父子进程关系。