Worker 与 Master 进程如何通信

底层在使用SWOOLE_PROCESS模式时,会有MasterWorker两种角色,Master收到数据后会投递(dispatch)到Worker进程

投递任务

Swoole提供了5dispatch方式。通过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

fdIP取模分配一致,dispatch_mode = 5 需要应用层调用bind方法设置一个UID

Stream 模式

使用类似于php-fpmUnix 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



  • 希望

    我strace 每个woker进程,都在epoll_wait(55, 也就是都在epoll_wait同一个句柄, 我理解reactor线程通过 unixsocket,将请求给worker里, unix 0xffff88078e725080 0t0 1481150375 socket unix 0xffff88078e722d80 0t0 1481150376 socket 我发现unixsocket的个数是worker数的两倍;为什么是两倍? 再就是每个woker将请求放到同一个epool里,在epool外面是加锁了吗? 为什么所有worker都epoll_wait同一个句柄?