Swoole 再深入

问即是学

基础编程知识

阻塞非阻塞 的区别?

  • 同步(Synchronous)IO

当一个程序发起调用的时候,在程序没有处理完成返回结果时,调用方会一直等待,等待结果的返回。

  • 异步(Asynchronous)IO

当一个程序发起调用的时候,程序立即返回调用成功的消息,但不会马上返回结果,而是需要通过回调的方式把返回结果返回给调用方。

  • 阻塞(Blocking)IO

阻塞就是在程序调用之后,结果返回之前,当前的进程/线程是被挂起的

  • 非阻塞(non-Blocking)IO

非阻塞是指程序调用之后,结果返回之前,不会挂起该进程/线程的。

异步的优势 ?

  • 高并发,同步阻塞IO模型的并发能力依赖于进程/线程数量
  • 无IO等待,同步模型无法解决IOWait很高的场景

同步的优势 ?

  • 编码简单,同步模式编写/调试程序更轻松
  • 可控性好,同步模式的程序具有良好的过载保护机制

PHP的GC机制 ?

GC机制: 垃圾回收机制

PHP5.3: 当变量容器的ref_count计数清0时,表示该变量容器就会被销毁,实现了内存回收
PHP5.3版本之后引入根缓冲机制,即php启动时默认设置指定zval数量的根缓冲区(默认是10000),当php发现有存在循环引用的zval时,就会把其投入到根缓冲区,当根缓冲区达到配置文件中的指定数量(默认是10000)后,就会进行垃圾回收,以此解决循环引用导致的内存泄漏问题

PHP面向对象编程: 对象引用机制和对象与内存之间的关系 ?

对象释放的时候调用了__destruct(),释放内存;

多进程编程

fpmswoole 的多进程模型及其区别 ?

  • PHP-FPM

php-fpm 就是通过 FastCGI 协议来处理 PHP 与第三方 WEB 服务器之间的通信
比如 Nginx + php-fpm 的组合,这种方式运行的 fpmMaster/Worker 模式,启动一个 Master 进程监听来自 Nginx 的请求,再 fork 多个 Worker 进程处理请求。每个 Worker 进程只能处理一个请求,单一进程的生命周期大体如下:

  1. 初始化模块。
  2. 初始化请求。此处请求是请求 PHP 执行代码的意思,并非 HTTP 的请求。
  3. 执行 PHP 脚本。
  4. 结束请求。
  5. 关闭模块。
  • Swoole

Swoole 采用的也是 Master/Worker 模式,不同的是 Master 进程有多个 Reactor 线程,Master 只是一个事件发生器,负责监听 Socket 句柄的事件变化。Worker 以多进程的方式运行,接收来自 Reactor 线程的请求,并执行回调函数(PHP 编写的)。启动 Master 进程的流程大致是:

  1. 初始化模块。
  2. 初始化请求。因为 swoole 需要通过 cli 的方式运行,所以初始化请求时,不会初始化 PHP 的全局变量,如 $_SERVER, $_POST, $_GET 等。
  3. 执行 PHP 脚本。包括词法、语法分析,变量、函数、类的初始化等,Master 进入监听状态,并不会结束进程。

对比不同:

  • PHP-FPM

    • Master 主进程 / Worker 多进程模式。
    • 启动 Master,通过 FastCGI 协议监听来自 Nginx 传输的请求。
    • 每个 Worker 进程只对应一个连接,用于执行完整的 PHP 代码。
    • PHP 代码执行完毕,占用的内存会全部销毁,下一次请求需要重新再进行初始化等各种繁琐的操作。
    • 只用于 HTTP Server。
  • Swoole

    • Master 主进程(由多个 Reactor 线程组成)/ Worker 多进程(或多线程)模式
    • 启动 Master,初始化 PHP 代码,由 Reactor 监听 Socket 句柄的事件变化。
    • Reactor 主线程负责子多线程的均衡问题,Manager 进程管理 Worker 多进程,包括 TaskWorker 的进程。
    • 每个 Worker 接受来自 Reactor 的请求,只需要执行回调函数部分的 PHP 代码。
    • 只在 Master 启动时执行一遍 PHP 初始化代码,Master 进入监听状态,并不会结束进程。
    • 不仅可以用于 HTTP Server,还可以建立 TCP 连接、WebSocket 连接。

进程间通信? 进程隔离? 进程信号量?

进程间通信

  • 管道
  1. 我们知道进程直接是相互独立的,那如果在进程之间通信就需要通过特殊介质,建立管道是其中一种方式。
  2. 管道分无名管道(pipe)和有名管道(FIFO),无名管道只能用于父子进程或者兄弟进程这些具有亲缘关系的进程;
  3. 为了克服这个缺点,就有了有名管道,提供非亲缘关系直接进程间通信
  • 信号
  1. 比如我们kill命令来杀死一个进程,就是内核生成一个信号,当系统捕获到是这个信号就会做出相应得操作。
  2. 信号可以作为进程间通信或修改行为的一种方式,明确地由一个进程发送给另一个进程。一个信号的产生叫生成,接收到一个信号叫捕获。
  • 消息队列
  • 共享内存

进程隔离

  • 不同的进程中PHP变量不是共享,即使是全局变量,在A进程内修改了它的值,在B进程内是无效的
  • 如果需要在不同的Worker进程内共享数据,可以用RedisMySQL、文件、Swoole\TableAPCushmget等工具实现
  • 不同进程的文件句柄是隔离的,所以在A进程创建的Socket连接或打开的文件,在B进程内是无效,即使是将它的fd发送到B进程也是不可用的

基础的TCP/UDP认知

TCPUDP的区别 ?

TCP(Transmission Control Protocol, 传输控制协议)
TCP 三次握手 四次挥手

UDP(User Data Protocol, 用户数据报协议)

区别

    1. 基于连接与无连接;
    1. 对系统资源的要求 (TCP较多,UDP少);
    1. UDP程序结构较简单;
    1. 流模式与数据报模式;
    1. TCP保证数据正确性,UDP可能丢包;
    1. TCP保证数据顺序,UDP不保证

OSI七层模型中的上四层 ?

应用层 表示层 会话层 传输层 网络层 数据链路层 物理层

协程

Swoole的协程工作模式 ?

  • 内存栈

4.0版本使用了PHP+C的双栈模式。创建协程时会创建一个C栈,默认尺寸为2M,创建一个PHP栈,默认为8K

C栈主要用于保存底层函数调用的局部变量数据,用于解决call_user_funcarray_map等C函数调用在协程切换时未能还原的问题。4.0版本无论如何切换协程,底层总是能正确地切换回原先的C函数栈帧继续向下执行。

  • 协程切换

C栈切换使用了boost.context 1.60汇编代码,用于保存寄存器,切换指令序列。主要是jump_fcontext这个ASM函数提供。
PHP栈的切换是跟随C栈切同步进行的。底层会切换EG(vm_stack)使得PHP恢复到正确的PHP函数栈帧。4.0.2版本还增加了ob输出缓存区的切换,ob_start等操作也可以用于协程。

  • 协程调度

4.0协程实现中,主协程即为Reactor协程,负责整个EventLoop的运行。主协程实现事件监听,在IO事件完成后唤醒其他工作协程。

    • 协程挂起

在工作协程中执行一些IO操作时,底层会将IO事件注册到EventLoop,并让出执行权。

    • 协程恢复

当主协程的Reactor接收到新的IO事件,底层会挂起主协程,并恢复IO事件对应的工作协程。该工作协程挂起或退出时,会再次回到主协程。

Swoole常见的”坑”

为何全局变量无法共享呢 ?

这是在于出现了进程克隆,而每个进程之间的数据都是不一致的。

echo var_dump 无法输出到浏览器(http响应) ?

原因在于模式的变更,swoole的运行模式不再是fpm,而是cli,如果你需要把数据响应给浏览器,你只能 通过Http request回调中的response对象进行响应

http请求参数获取 ?

在同swoolehttp服务的时候,很多人会发现$_GET$_POST等常见全局变量无法使用。这是因为$_GET$_POST等变量都是全局的,在swoole当中会出现问题,如果想获取请求参数,可以用swoole回调时提供的Request对象来进行获取

swoole不能使用die/exit ?

phper都习惯用die/exit来调试代码,这是因为这个命令会直接退出当前进程,对于fpm来讲,每个请求都对应一个独立进程,退出了问题不大,但是在swoole当中,可能一个进程中会有多个请求同时在处理,如果你exit或者die来退出当前进程,会导致数据丢失。

swoole下为何需要断线重连 ?

swoole常驻内存的情况下, 请求结束后,该连接并不会被清理,依旧保留在内存空间内,而该连接若是长时间没有使用,或者是因为网络波动,那么就会断开。下次请求进来的时候,你没有判断连接状态,就直接去执行sql语句,那么就意味着你操作了一个断线的数据库连接,因此肯定会报错。

Powered by Hexo and Hexo-theme-hiker

Copyright © 2017 - 2023 Keep It Simple And Stupid All Rights Reserved.

访客数 : | 访问量 :