Swoole

Author Avatar
A Man Has No Name 8月 18, 2017
  • 在其它设备中阅读本文章

关于PHP处理多进程的一个模块

关于几个概念

  1. 进程: 是正在运行的程序的实例。
  2. 线程: 调度进程的资源的东西,几乎不占有资源。

关于使用场景

  1. 希望解决,GM并发大量的发送操作
  2. 希望解决,定时执行
  3. 提供PHP的多进程解决方案。

思考点:
关于分布式部署,提供高可用支持。

关于namespace的使用

namespace 函数名
Swoole\Server swoole_server
Swoole\Client swoole_client
Swoole\Process swoole_process
Swoole\Timer swoole_timer
Swoole\Table swoole_table
Swoole\Lock swoole_lock
Swoole\Atomic swoole_atomic
Swoole\Buffer swoole_buffer
Swoole\Redis swoole_redis
Swoole\Event swoole_event
Swoole\MySQL swoole_mysql
Swoole\Channel swoole_channel
Swoole\Http\Server swoole_http_server
Swoole\Http\Client swoole_http_client
Swoole\Http\Request swoole_http_request
Swoole\Http\Response swoole_http_response
Swoole\WebSocket\Server swoole_websocket_server

多进程模型

进程和线程模式

Swoole\Server

配置参数:

  • max_conn, 此参数设置Server最大允许维持的tcp连接数,超过这个限制,服务器会拒绝(不要设置的过大)
  • max_request, 表示worker进程做多接受多少个请求,如果超过这个数值,manager进程负责回收,并且新建一个worker进程。
    • 0 表示永远不重启(不建议)
  • worker_num, worker进程数
  • task_worker_num, task进程数
  • daemonize,是否启用后台处理
  • dispatch_mode, 1平均分配,2按FD取模固定分配,3抢占式分配,默认为取模(dispatch=2)

  • log_file

Swoole Worker进程模式

  1. dispatch_mode = 1: 轮询方式处理
  2. dispatch_mode = 1(默认): 数据包根据fd 的值%worker_num来分, 这样可以保证每次TCP连接,都会被同一个worker连接。
  3. dispatch_mode = 3: 争抢模式,只有空闲的进程可以获取处理权限。

Reactor线程

  • 负责维护客户端机器的TCP连接、处理网络IO、收发数据完全是异步非阻塞的模式
  • 全部为C代码,除Start/Shudown事件回调外,不执行任何PHP代码
  • 将TCP客户端发来的数据缓冲、拼接、拆分成完整的一个请求数据包
  • Reactor以多线程的方式运行

Worker进程

  • 接受由Reactor线程投递的请求数据包,并执行PHP回调函数处理数据
  • 生成响应数据并发给Reactor线程,由Reactor线程发送给TCP客户端
  • 可以是异步非阻塞模式,也可以是同步阻塞模式
  • Worker以多进程的方式运行

Task进程

  • 接受由Worker进程通过swoole_server->task/taskwait方法投递的任务
  • 处理任务,并将结果数据返回给Worker进程
  • 完全是同步阻塞模式
  • Task以多进程的方式运行

关系

  • 可以理解为reactor就是nginx,worker就是php-fpm。reactor线程异步并行地处理网络请求,然后再转发给worker进程中去处理。reactor和worker间通过IPC方式通信。

  • swoole的reactor,worker,task_worker之间可以紧密的结合起来,提供更高级的使用方式。

  • 一个更通俗的比喻,假设Server就是一个工厂,那reactor就是销售,帮你接项目订单。而worker就是工人,当销售接到订单后,worker去工作生产出客户要的东西。而task_worker可以理解为行政人员,可以帮助worker干些杂事,让worker专心工作。

  • 底层会为Worker进程、Task进程分配一个唯一的ID

  • 不同的task/worker进程之间可以通过sendMessage接口进行通信

引申的PHP知识

闭包

只是了解一下,别用它(其实你可以写一个类实现)

匿名函数

1
2
3
4
5
6
7
8
9
10
11
$func = function($params){
echo $params;
};
$func('ok')
// 输出
// ok

声明变量,返回一个匿名函数,此变量可以被调用。

那么我们就可以实现PHP闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 第一种
function printStr() {
$func = function( $str ) {
echo $str;
}
$func('ok');
}
printStr();
// 第二种
function tF() {
$func = function( $str ) {
echo $str;
}
return $func;
}
$f = tF();
$f('ok');
// 第三种
function callFunc( $func ) {
$func('ok');
}
$func = function( $str );
callFunc( func );

闭包可以保存所有代码块上下文的一些变量。PHP在默认情况下,匿名函数不允许调用代码块的上下文变量, 而需要使用use关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function getMoney() {
$rmb = 1;
$dollar = 6;
$func = function() use ( $rmb ) {
echo $rmb;
echo $dollar;
};
$func();
}
getMoney();
//输出:
//1
//报错,找不到dorllar变量

那么问题来了,能不能改变上下文的变量呢(答案是不能,如果我们想改变呢,答案是换一种写法&)