swoole学习(一)

swoole简介

  基于异步事件驱动和协程的并行网络通信引擎。

TCP服务器

  start/onConnect/onReceive/onClose

UDP服务器

  start/onPacket

Http服务器

  start/onRequest()

WebSocket服务器

  start/onOpen/onMessage/onClose

异步任务

  onTask/onFinish

协程

  一键协程化,可以实现底层io自动异步。
  Swoole\Runtime::enableCoroutine();      //开启协程
  Co\run(function(){//携程容器
        go(function(){      //创建一个协程
              
        })
  })

Master 进程、Reactor 线程、Worker 进程、Task 进程、Manager 进程的区别与联系



Master 进程

  Master 进程是一个多线程进程

Reactor 线程

  Reactor 线程是在 Master 进程中创建的线程
  负责维护客户端 TCP 连接、处理网络 IO、处理协议、收发数据
  不执行任何 PHP 代码
  将 TCP 客户端发来的数据缓冲、拼接、拆分成完整的一个请求数据包

Worker 进程

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

TaskWorker 进程

  接受由 Worker 进程通过 Swoole\Server->task/taskwait/taskCo/taskWaitMulti 方法投递的任务
  处理任务,并将结果数据返回(使用 Swoole\Server->finish)给 Worker 进程
  完全是同步阻塞模式
  TaskWorker 以多进程的方式运行

Manager 进程

  负责创建 / 回收 worker/task 进程

他们之间的关系可以理解为 Reactor 就是 nginx,Worker 就是 PHP-FPM。Reactor 线程异步并行地处理网络请求,然后再转发给 Worker 进程中去处理。Reactor 和 Worker 间通过 unixSocket 进行通信。

在 PHP-FPM 的应用中,经常会将一个任务异步投递到 Redis 等队列中,并在后台启动一些 PHP 进程异步地处理这些任务。Swoole 提供的 TaskWorker 是一套更完整的方案,将任务的投递、队列、PHP 任务处理进程管理合为一体。通过底层提供的 API 可以非常简单地实现异步任务的处理。另外 TaskWorker 还可以在任务执行完成后,再返回一个结果反馈到 Worker。

Swoole 的 Reactor、Worker、TaskWorker 之间可以紧密的结合起来,提供更高级的使用方式。

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

注意事项

  不要在代码中执行 sleep 以及其他睡眠函数,这样会导致整个进程阻塞;协程中可以使用 Co::sleep() 或在一键协程化后使用 sleep;参考:sleep/usleep 的影响
  exit/die 是危险的,会导致 Worker 进程退出;参考:exit/die 函数的影响
  可通过 register_shutdown_function 来捕获致命错误,在进程异常退出时做一些清理工作;参考:捕获 Server 运行期致命错误
  PHP 代码中如果有异常抛出,必须在回调函数中进行 try/catch 捕获异常,否则会导致工作进程退出;参考:捕获异常和错误
  不支持 set_exception_handler,必须使用 try/catch 方式处理异常;
  Worker 进程不得共用同一个 Redis 或 MySQL 等网络服务客户端,Redis/MySQL 创建连接的相关代码可以放到 onWorkerStart 回调函数中。参考 是否可以共用 1 个 Redis 或 MySQL 连接

内存管理

  注意静态变量、golbal变量,超全局变量,在回调函数执行后,不会被回收,需要特别注意是否需要重置。 特别注意拼接和数组,防止造成长度过长。
  可以通过设置 max_request 和 task_max_request 参数,在worker/task进程运行指定次数后,自动退出。
  或者可以在onClose()或者定时器中使用unset()清理变量,回收资源。

进程隔离

  修改了全局变量的值,为什么不生效?原因就是全局变量在不同的进程,内存空间是隔离的,所以无效。
  所以使用 Swoole 开发 Server 程序需要了解进程隔离问题,Swoole\Server 程序的不同 Worker 进程之间是隔离的,在编程时操作全局变量、定时器、事件监听,仅在当前进程内有效。
  不同的进程中 PHP 变量不是共享,即使是全局变量,在 A 进程内修改了它的值,在 B 进程内是无效的
  如果需要在不同的 Worker 进程内共享数据,可以用 Redis、MySQL、文件、Swoole\Table、APCu、shmget 等工具实现
  不同进程的文件句柄是隔离的,所以在 A 进程创建的 Socket 连接或打开的文件,在 B 进程内是无效,即使是将它的 fd 发送到 B 进程也是不可用的

  Swoole 提供的 Table、Atomic、Lock 组件是可以用于多进程编程的,但必须在 Server->start 之前创建。另外 Server 维持的 TCP 客户端连接也可以跨进程操作,如 Server->send 和 Server->close。

使用影响

sleep/usleep 的影响

  在异步 IO 的程序中,不得使用 sleep/usleep/time_sleep_until/time_nanosleep。(下文中使用 sleep 泛指所有睡眠函数)      

  sleep 函数会使进程陷入睡眠阻塞
  直到指定的时间后操作系统才会重新唤醒当前的进程
  sleep 过程中,只有信号可以打断
  由于 Swoole 的信号处理是基于 signalfd 实现的,所以即使发送信号也无法中断 sleep
  Swoole 提供的 swoole_event_add、swoole_timer_tick、swoole_timer_after、Swoole\Process::signal、在进程 sleep 后会停止工作。Swoole\Server 也无法再处理新的请求

exit/die 函数的影响

  在 Swoole 程序中禁止使用 exit/die,如果 PHP 代码中有 exit/die,当前工作的 Worker 进程、Task 进程、User 进程、以及 Swoole\Process 进程会立即退出。
  使用 exit/die 后 Worker 进程会因为异常退出,被 master 进程再次拉起,最终造成进程不断退出又不断启动和产生大量警报日志.
  建议使用 try/catch 的方式替换 exit/die,实现中断执行跳出 PHP 函数调用栈

  Swoole\ExitException 是 Swoolev4.1.0 版本及以上直接支持了在协程和 Server 中使用 PHP 的 exit,此时底层会自动抛出一个可捕获的 Swoole\ExitException,开发者可以在需要的位置捕获并实现与原生 PHP 一样的退出逻辑

while 循环的影响

  异步程序如果遇到死循环,事件将无法触发。异步 IO 程序使用 Reactor模型,运行过程中必须在 reactor->wait 处轮询。如果遇到死循环,那么程序的控制权就在 while 中了,reactor 无法得到控制权,无法检测事件,所以 IO 事件回调函数也将无法触发。

其他知识

socket
它是网络通信过程中端点的抽象表示,包含进行网络通信必需的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
tcp协议
TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。

进程
进程的数据结构中,有pid,file_fds, children等,所以不同进程的变量和文件占位符是互相分割的,不能共用的。

posted @ 2021-01-25 11:17  FZ-august  阅读(332)  评论(0)    收藏  举报