Worker 与 Master 进程如何通信
底层在使用SWOOLE_PROCESS
模式时,会有Master
和Worker
两种角色,Master
收到数据后会投递(dispatch
)到Worker
进程
投递任务
Swoole
提供了5
种dispatch
方式。通过Server::set
方法设置dispatch_mode
来配置。
轮询模式
dispatch_mode = 1
收到的请求数据包会轮询发到每个Worker进程。
FD取模
dispatch_mode = 2
数据包根据fd
的值%worker_num
来分配,这个模式可以保证一个TCP
客户端连接发送的数据总是会被分配给同一个worker进程。
这种模式可能会存在性能问题,作为SOA服务器时,不应当使用此模式。因为客户端很可能用了连接池,客户端100个进程复用10个连接,也就是同时只有10个swoole worker进程在处理请求。这种模式的业务系统可以使用dispatch_mode = 3
,抢占式分配。
忙闲分配
dispatch_mode = 3
此模式下,Reactor
只会给空闲的Worker
进程投递数据。
这个模式的缺点是,客户端连接对应的Worker
是随机的。不确定哪个Worker
会处理请求。无法保存连接状态。
当然也可以借助第三方库来实现保存连接状态和会话内容,比如apc/redis/memcache
。
IP 取模
dispatch_mode = 4
如果客户端的连接不稳定,经常发生断线重连,fd
的值不是固定的,使用IP
进行取模分配可以解决此问题。同一个IP
地址会被分配到同一个Worker
进程。
UID 取模
dispatch_mode = 5
与fd
或IP
取模分配一致,dispatch_mode = 5
需要应用层调用bind
方法设置一个UID
Stream 模式
使用类似于php-fpm
的Unix Socket
短连接方式通信,Worker
进程会变成Leader-Follower
模式,争抢任务。
通信过程
底层实现使用了Unix Socket Dgram
进行通信。
低版本中超过8K
的包,会拆分成多次发送,Worker
进程中会进行数据合并。
4.3.2
对此进行了优化,改为使用动态缓存区,一次性发送一个很大的包([512K-4M]
),这取决于操作系统net.core.wmem_max
设定。一次性传输数据包可以减少一次内存copy
,同时也降低了系统调用的执行次数。
使用
cat /proc/sys/net/core/wmem_max
可以查看当前设置,例如数字为256K
时,可以一次传输512K
数据(wmem_max * 2
)