twosee

twosee 查看完整档案

长春编辑长春理工大学  |  电子信息工程 编辑  |  填写所在公司/组织 m.cust.edu.cn 编辑
编辑

Swoole核心开发者

个人动态

twosee 赞了文章 · 2020-06-05

swoole进程结构

clipboard.png

一、进程的基本知识

什么是进程,所谓进程其实就是操作系统中一个正在运行的程序,我们在一个终端当中,通过php,运行一个php文件,这个时候就相当于我们创建了一个进程,这个进程会在系统中驻存,申请属于它自己的内存空间系统资源并且运行相应的程序

对于一个进程来说,它的核心内容分为两个部分,一个是它的内存,这个内存是这进程创建之初从系统分配的,它所有创建的变量都会存储在这一片内存环境当中

一个是它的上下文环境我们知道进程是运行在操作系统的,那么对于程序来说,它的运行依赖操作系统分配给它的资源,操作系统的一些状态。

在操作系统中可以运行多个进程的,对于一个进程来说,它可以创建自己的子进程,那么当我们在一个进程中创建出若干个子进程的时候那么可以看到如图,子进程和父进程一样,拥有自己的内存空间和上下文环境

clipboard.png

二、Swoole进程结构

Swoole的高效不仅仅于底层使用c编写,他的进程结构模型也使其可以高效的处理业务,我们想要深入学习,并且在实际的场景当中使用必须了解,下面我们先看一下结构图:

clipboard.png

首先先介绍下swoole的这几种进程分别是干什么的:

从这些层级的名字,我们先大概说一下,下面这些层级分别是干什么的,做一个详细的说明。

  1. Master进程:主进程
  2. Manger进程:管理进程
  3. Worker进程:工作进程
  4. Task进程:异步任务工作进程

1、Master进程

第一层,Master进程,这个是swoole的主进程,这个进程是用于处理swoole的核心事件驱动的,那么在这个进程当中可以看到它拥有一个MainReactor[线程]以及若干个Reactor[线程],swoole所有对于事件的监听都会在这些线程中实现,比如来自客户端的连接,信号处理等。

clipboard.png

每一个线程都有自己的用途,下面多每个线程有一个了解

MainReactor(主线程)

主线程会负责监听server socket,如果有新的连接accept,主线程会评估每个Reactor线程的连接数量。将此连接分配给连接数最少的reactor线程,做一个负载均衡。

Reactor线程组

Reactor线程负责维护客户端机器的TCP连接、处理网络IO、收发数据完全是异步非阻塞的模式。
swoole的主线程在Accept新的连接后,会将这个连接分配给一个固定的Reactor线程,在socket可读时读取数据,并进行协议解析,将请求投递到Worker进程。在socket可写时将数据发送给TCP客户端。

心跳包检测线程(HeartbeatCheck)

Swoole配置了心跳检测之后,心跳包线程会在固定时间内对所有之前在线的连接
发送检测数据包

UDP收包线程(UdpRecv)

接收并且处理客户端udp数据包

2、管理进程Manager

Swoole想要实现最好的性能必须创建出多个工作进程帮助处理任务,但Worker进程就必须fork操作,但是fork操作是不安全的,如果没有管理会出现很多的僵尸进程,进而影响服务器性能,同时worker进程被误杀或者由于程序的原因会异常退出,为了保证服务的稳定性,需要重新创建worker进程。

Swoole在运行中会创建一个单独的管理进程,所有的worker进程和task进程都是从管理进程Fork出来的。管理进程会监视所有子进程的退出事件,当worker进程发生致命错误或者运行生命周期结束时,管理进程会回收此进程,并创建新的进程。换句话也就是说,对于worker、task进程的创建、回收等操作全权有“保姆”Manager进程进行管理。

再来一张图梳理下Manager进程和Worker/Task进程的关系。

clipboard.png

3、Worker进程

worker 进程属于swoole的主逻辑进程,用户处理客户端的一系列请求,接受由Reactor线程投递的请求数据包,并执行PHP回调函数处理数据生成响应数据并发给Reactor线程,由Reactor线程发送给TCP客户端可以是异步非阻塞模式,也可以是同步阻塞模式

4、Task进程

taskWorker进程这一进城是swoole提供的异步工作进程,这些进程主要用于处理一些耗时较长的同步任务,在worker进程当中投递过来。

三、进程查看及流程梳理

当启动一个Swoole应用时,一共会创建2 + n + m个进程,2为一个Master进程和一个Manager进程,其中n为Worker进程数。m为TaskWorker进程数。

默认如果不设置,swoole底层会根据当前机器有多少CPU核数,启动对应数量的Reactor线程和Worker进程。我机器为1核的。Worker为1。

所以现在默认我启动了1个Master进程,1个Manager进程,和1个worker进程,TaskWorker没有设置也就是为0,当前server会产生3个进程。

在启动了server之后,在命令行查看当前产生的进程

clipboard.png

这三个进程中,所有进程的根进程,也就是例子中的2123进程,就是所谓的Master进程;而2212进程,则是Manager进程;最后的2321进程,是Worker进程。

client跟server的交互

1、client请求到达 Main Reactor,Client实际上是与Master进程中的某个Reactor线程发生了连接。

2、Main Reactor根据Reactor的情况,将请求注册给对应的Reactor (每个Reactor都有epoll。用来监听客户端的变化) 

3、客户端有变化时Reactor将数据交给worker来处理

4、worker处理完毕,通过进程间通信(比如管道、共享内存、消息队列)发给对应的reactor。 

5、reactor将响应结果发给相应的连接请求处理完成

示意图:

clipboard.png

后续准备

本文是在自己学习Swoole接触到的一些知识,在初步整理后发送出来,希望能与大家一起学习,文章不足等问题大家可以一起讨论学习,欢迎骚扰~~。
后面准备从网络模型入手更好的理解swoole的实现原理,比较与传统PHP-FPM工作模式的问题,之前出过一篇关于(一)如何实现一个单进程阻塞的网络服务器大家可以先了解下,如何一步步演变为多进程master-worker模型。

欢迎大家指正文章问题~

查看原文

赞 39 收藏 24 评论 1

twosee 回答了问题 · 2020-02-26

swoole协程http每次请求,内存都会叠加,请问是怎么问题?

建议先升级一下Swoole版本
此外, 内存上涨≠内存泄漏, 内存泄漏需要长期大量的跟踪观察

关注 3 回答 2

twosee 赞了文章 · 2020-01-17

Swoole 2020 :4.5 新版本的规划

转眼 Swoole 开源项目已经历 8 个年头。这 8 年里,有 116 位开发者为 Swoole 贡献了内核代码。有无数 PHP 开发者为 Swoole 提供 BUG 反馈和改进建议。也有大量 Swoole 用户活跃在 Swoole 的问答社区、SegmentFault Swoole 专栏、QQ/微信技术交流群。在 GitHub 平台也累积了 1.5万 + 的 star。作为 Swoole 的创始人、核心开发者,倍感荣幸。感谢各位开发者为 Swoole 生态所做出的贡献。我们一定会不忘初心,坚持开源。

Swoole 4.5 版本

2019年12月份我们规划了新的 4.5 版本,这个版本的主题是 “代码架构重构”。4.4 将作为LTS分支长期支持。在 4.5 版本之前,Swoole 底层更多地是偏向于快速实现,没有完整的代码架构设计,并且代码规范做的较差。编程语言方面也较为混乱,同时存在 C 和 C++ 的源文件。头文件的引用也不够规范,如在非 Server 模块中引用了 server.h 。其实社区中早已有很多 C/C++ 方面的开发者对此提出了建议。在此之前我们团队有很多优先级更高的工作需要完成,在代码规范方面投入的时间精力较少。在新的 4.5 版本中,我们将投入大量时间精力,重新设计代码架构,彻底改变这个局面。

主要工作包括以下几个方面:

  • 改造 Event API ,屏蔽 int 型 fd 的使用,统一为 swSocket 对象
  • 移除 socket_array 全局变量
  • Server Master 彻底移除锁的使用,大幅提升并行能力
  • 全面切换为 C++
  • 优化从 Reactor -> Worker -> PHP onReceive 数据传递方式,减少内存 Copy,onReceive 事件回调函数的性能提升 4 倍

根据社区用户的反馈,在 4.5 版本中将会增加一些新特性:

  • HTTP2\Client 支持 pipeline recv
  • 内置 FastCGI 协程客户端,与短生命周期 fpm 服务完美融合
  • 增加 Coroutine/Batch API,可以并行执行 N 个函数,并接收返回值数组
  • 增加 onReload 事件回调,在发生 reload 之前触发

另外,我们发现使用 gRPC 、Http2 的 Swoole 用户越来越多,Http2 模块存在一些 BUG,在 4.5 版本中我们会对 Http2 Client & Server 做一次大的重构工作,解决所有已知问题,稳定性和健壮性大幅提升。

4.5 版本也将移除一些已废弃的特性:

  • 移除 Buffer 模块
  • 移除 Runtime::enableStrictMode

Swoole 文档计划

由于Swoole是非常底层的软件,内核开发者大量精力都放在了添加新特性,处理BUG上面,对于大家一致吐槽的文档问题一直没有精力解决,现在我们有了更多的开发者以及背后的商业化支持公司,已经有精力解决文档问题了,新的文档旨在解决大家一直吐槽的文档问题,采用现代化的文档组织形式,只包含Swoole4的内容,修改了大量老文档中错误的内容,优化了文档细节,增加了示例代码,新的文档预计在年后发布。

Swoole 核心开发者

由于现在公司项目的工作任务较多,没有过多精力参与到内核开发中。从 4.5 版本开始,我将逐渐减少代码贡献,分阶段退出核心开发组。交给新一代开发者们:Twosee、Shiguangqi、CodingHuang & 其他更多伙伴 。

Twosee 会作为 Swoole 开源项目新一代灵魂人物,就像 PHP 开源的 Nikic 。

Swoole 商业化

从 2018 年起 Swoole 开始了商业化的探索。经过一年半的努力,在 Swoole 项目核心开发者郭新华的带领下,公司勉强达到了自负盈亏的状态。其实创建这个公司的初心是通过提供一些商业服务,带来资金收入,这样可以支持我们整个 Swoole 内核研发团队继续投入到 Swoole 开源事业。也能有更多资源投在文档、测试、社区运营、布道推广上

在 2019年 识沃公司(Swoole 商业公司)赞助了 PHPCon 大会,向 Swoole 社区很多活跃的贡献者和用户赠送了 T恤、帽衫 等小礼物,并通过对企业的深入合作发现了很多需求,给社区反馈了很多高质量bug。

新华是 Swoole 开源和商业的核心力量。在开源领域,新华贡献了:

  • php-cp:MySQL 连接池软件,在聚美优品被大量使用
  • swoole_serialize:专门为 PHP7 设计的高性能二进制序列化模块,性能比 JSON/PHP串化高出很多、内存占用更少

另外,Swoole 商业公司中很多核心的项目也是新华完成开发的:

2019 年底 我们新开发了 Swoole Plus 软件,在 Swoole 社区版本之上,增加了一些性能调优的方案,以及安全防护、攻击检测、流量控制、Hbase/Solr-Cloud 支持。功能特性是其次的,主要是为企业提供商业支持服务。帮助企业解决 PHP & Swoole 项目的技术难题。让那些想大规模应用Swoole技术的公司可以放心的使用我们的技术。

明年我们将陆续推出很多应用级别的解决方案,即时通讯(IM)、安全网关、物联网(IOT)、游戏、客服系统等 Swoole 应用项目。

结语

即便我们没有 Google、Facebook、Microsoft 这些大厂那样的资金和光环,也绝不放弃。正是对开源技术的热爱,对 PHP 语言的热爱,才使得我们能够坚持下去。

我们的目标是将 Swoole 做成工业级的软件,作为 PHP 语言网络通信方向的基石。

查看原文

赞 41 收藏 4 评论 12

twosee 赞了文章 · 2019-10-21

记json与serialize性能测试

最近在观看swoole官方的课程时,其中有一小段专门说到了json_decode这个函数的效率问题,其慢的原因是在进行转化时需要遍历文中每一个字符去寻找EOF(end of file:文字流的结尾,关于EOF阮一峰大神这篇文章解释得很详细),而只有在确认整个字符串的格式和长度后,json格式才可以被decode,也就是说假设整个字符串的长度为N,那程序就必须进行N+1次的遍历,那如果对于一些高并发的场景时,是否有更好的解决办法呢?

关于序列化还有另外一个常用的函数就是serialize,serialize在序列化后会将数值的类型和长度都一一记录在序列化后的字符串中,如果依照这个思路,serialize在进行反序列化时应该可以依照之前生成的字符直接去进行格式化,而无需再进行全文的遍历寻找EOF,那是否在长字符串的情况下unserialize会比json_decode效率更高呢?

于是做了如下的实验,分别用了三种类型的数组数据作为测试,别为中文,英文,以及数字,进行一次序列化和反序列化为一个循环进行测试,其中基数为循环的次数:

$array = [
    "I'm a gooPHP 是免费的,并且使用非常广泛。同时,对于像微软 ASP 这样的竞争者来说,PHP 无疑是另一种高效率的选项。PHP 极其适合网站开发,其代码可以直接嵌入 HTML 代码.",
    "I'm a good boy.",
    "a" => "PHP 是免费的,并且使用非常广泛。同时,对于像微软 ASP 这样的竞争者来说,PHP 无疑是另一种高效率的选项。PHP 极其适合网站开发,其代码可以直接嵌入 HTML 代码",
    2 =>"PHP 是免费的,并且使用非常广泛。同时,对于像微软 ASP 这样的竞争者来说,PHP 无疑是另一种高效率的选项。PHP 极其适合网站开发,其代码可以直接嵌入 HTML 代码",
    'PHP 是免费的,并且使用非常广泛。同时,对于像微软 ASP 这样的竞争者来说,PHP 无疑是另一种高效率的选项。PHP 极其适合网站开发,其代码可以直接嵌入 HTML 代码',
    "I'm a good boy.",
    "I'm a good boy.",
    "I'm a good boy.",
    "I'm a good boy.",
    "I'm a good",
    "asdfnsadofhasd"];
$array = [
    "I'm a boy",
    "I'm a boy",
    "I'm a boy",
    "I'm a boy",
    "I'm a boy",
    "I'm a boy",
    "I'm a boy",
    "I'm a boy",
    "I'm a boy",
    "I'm a boy",
];
$array = [
    0 => 9115,
    1 => 9115,
    2 => 9115,
    3 => 9115,
    4 => 9115,
    5 => 9115,
    6 => 9115,
    7 => 9115,
    8 => 9115,
    9 => 9115,
];

得出的测试结果如下
TIM图片20191021163119.png

可以看到在英文和数字的序列化中,json的序列化效率是serialize的2-3倍,而在中文数组的测试中,serialize的效率为json的8-10倍,也印证了前面的猜测:json在序列化和反序列数据时,字符串长度越长,cpu需要去执行寻找EOF的次数便越多,而serialize因为在序列化的时候便记录了字符串的长度,所以在反序列化的时候会比json花更少的时间

但serialize也有其自身的不足:
1.因为在序列化时记录了对应的字符串的长度和类型,所以在相同的数据下,serialize会比json更占用空间,用空间换取了时间。
2.serialize序列化后的内容对比起json可读性较差,在进行问题排查时相对麻烦一些。

看到这里大家应该明白这两种序列化的适用场景:
如果是短内容的场景下,使用json作序列化是比较好的方法,不仅效率高且更字符串体积更小
如果是在长字符串的场景下,可以考虑用serialize,程序的执行效率会比json高不少!

文末附上swoole课堂的地址,满满的干货:https://course.swoole-cloud.com/course-video/52

查看原文

赞 20 收藏 13 评论 1

twosee 回答了问题 · 2019-08-27

如何理解这里代码的协程执行和情况?

Swoole协程是单线程的, 最底下的while循环占用了这个进程1秒的CPU时间, 导致底层异步定时器延后了
这种情况需要开启抢占式调度, 防止有恶意协程占用CPU导致其它协程饿死
https://wiki.swoole.com/wiki/...

关注 3 回答 2

twosee 赞了文章 · 2019-06-20

🚀 Hyperf v1.0 发布,全新企业级的 PHP 协程微服务框架

Hyperf

Hyperf 是基于 Swoole 4.3+ 实现的高性能、高灵活性的 PHP 协程框架,内置协程服务器及大量常用的组件,性能较传统基于 PHP-FPM 的框架有质的提升,提供超高性能的同时,也保持着极其灵活的可扩展性,标准组件均均基于 PSR 标准 实现,基于强大的依赖注入设计,保证了绝大部分组件或类都是 可替换可复用 的。

框架组件库除了常见的协程版的 MySQL 客户端Redis 客户端,还为您准备了协程版的 Eloquent ORMJSON RPC 服务的及客户端GRPC 服务端及客户端Zipkin (OpenTracing) 客户端Guzzle HTTP 客户端Elasticsearch 客户端Consul 客户端ETCD 客户端AMQP 组件Apollo 配置中心阿里云 ACM 应用配置管理基于令牌桶算法的限流器通用连接池熔断器Swagger 文档生成 等组件,省去了自己实现对应协程版本的麻烦,Hyperf 还提供了 基于 PSR-11 的依赖注入容器注解AOP 面向切面编程基于 PSR-15 的中间件自定义进程基于 PSR-14 的事件管理器Redis/RabbitMQ 消息队列自动模型缓存基于 PSR-16 的缓存 等非常便捷的功能,满足丰富的技术场景和业务场景,开箱即用。

框架初衷

尽管现在基于 PHP 语言开发的框架处于一个百花争鸣的时代,但仍旧未能看到一个优雅的设计与超高性能的共存的完美框架,亦没有看到一个真正为 PHP 微服务铺路的框架,此为 Hyperf 及其团队成员的初衷,我们将持续投入并为此付出努力,也欢迎你加入我们参与开源建设。

设计理念

Hyperspeed + Flexibility = Hyperf,从名字上我们就将 超高速灵活性 作为 Hyperf 的基因。

  • 对于超高速,我们基于 Swoole 协程并在框架设计上进行大量的优化以确保超高性能的输出。
  • 对于灵活性,我们基于 Hyperf 强大的依赖注入组件,组件均基于 PSR 标准 的契约和由 Hyperf 定义的契约实现,达到框架内的绝大部分的组件或类都是可替换的。

基于以上的特点,Hyperf 将存在丰富的可能性,如实现 Web 服务,网关服务,分布式中间件,微服务架构,游戏服务器,物联网(IOT)等。

文档齐全

我们投入了大量的时间用于文档的建设,以解决各种因为文档缺失所带来的问题,文档上也提供了大量的示例,对新手同样友好。

生产可用

我们为组件进行了大量的单元测试以保证逻辑的正确,同时维护了高质量的文档,在 Hyperf 正式对外开放(2019年6月20日)之前,便已在一家 C轮 和一家 B轮 互联网公司上线了多个服务并以稳定的姿态完美的运行了超过半年时间,经过了严酷的生产环境 (如618) 的考验,我们才正式的对外开放该项目。

官网及交流

Github <- 点 Star 支持我们
Hyperf 官网
QQ 群: 862099724

查看原文

赞 115 收藏 43 评论 25

twosee 赞了文章 · 2019-04-11

【宇润日常疯测-007】Swoole 协程与传统 fpm 同步模式比较

如果说数组是 PHP 的精髓,数组玩得不6的,根本不能算是会用PHP。那协程对于 Swoole 也是同理,不理解协程去用 Swoole,那就是在瞎用。

首先,Swoole 只能运行在命令行(Cli)模式下,所以我们开发调试都是使用命令行,而不是 php-fpm/apache 等。

在 Swoole 中,我们可以使用\Swoole\Coroutine::create()创建协程,或者你也可以使用简写go()

初识 Swoole 协程

go(function(){
    go(function(){
        echo 0, PHP_EOL;
    });
    echo 1, PHP_EOL;
});
go(function(){
    echo 2, PHP_EOL;
});
go(function(){
    echo 3, PHP_EOL;
});

执行结果:

0
1
2
3

Swoole 协程与同步模式比较

我们一直在说 Swoole 协程适合用于 I/O 密集场景,在同样的硬件配置环境下,它会比传统的同步模式承载更多的访问量。

我们熟悉的文件读写、网络通讯请求(MySQL、Redis、Http等)都是属于 I/O 密集型场景。

假设一次 SQL 查询为 100ms,在传统同步模式下,当前进程在这 100ms 的时间里,是不能做其它操作的。如果要执行十次这个 SQL,可能需要耗费 1s 以上。

而如果用协程,虽然不同协程之间也是按顺序执行,但是在前一个等待 100ms 期间,底层会调度 CPU,去执行其它协程的操作。也就是说,可能第一个查询还没返回结果,其它几个查询就已经发送给了 MySQL 并正在执行中了。如果开启十个协程,分别执行这个 SQL,可能只需要耗费 100+ms 即可完成。

测试代码如下:

Swoole\Runtime::enableCoroutine(); // 开启一键协程化

function work()
{
    $pdo = new \PDO('mysql:host=127.0.0.1;dbname=db_test', 'root', 'root');
    $pdo->exec('select SLEEP(0.1)'); // 模拟sql需要执行 100ms 的情况
}

$time = microtime(true);
for($i = 0; $i < 10; ++$i)
{
    work();
}
echo 'time: ', (microtime(true) - $time), 's', PHP_EOL;

$time = microtime(true);
for($i = 0; $i < 10; ++$i)
{
    go('work');
}
swoole_event_wait(); // 等待所有协程执行完
echo 'time: ', (microtime(true) - $time), 's', PHP_EOL;

执行结果:

time: 1.0326268672943s
time: 0.10734605789185s

上面的代码可以假想为,单进程处理 10 个请求所需的时间。每个请求需要执行一次耗费 100ms 的 SQL 语句。

同步模式,耗费 1s 左右的是 fpm。可以看出,在等待 100ms 期间是不能做任何事情的。

协程模型,耗费 0.1s 左右的是 Swoole。在等待 100ms 期间会挂起当前协程,底层调度会让 CPU 去执行其它协程的操作。

查看原文

赞 7 收藏 3 评论 0

twosee 回答了问题 · 2019-03-28

关于swoole fd的值范围问题

是的, 目前的单机应用不可能达到这么大的连接数

关注 3 回答 2

twosee 回答了问题 · 2019-03-26

swoole httpserver性能真的有比nginx+php-fpm好吗

不建议做这种极其不专业的测试, 机器信息, 系统配置, 调优情况, 预热情况, 测试代码, 什么都没有, 压测工具也没有开启长连接, 最新版本的swoole的benchmark目录下benchmark.php可以一键跑ab测试, 甚至受限于ab客户端的并发能力, 测试结果可能不如wrk+pipeline高

https://wiki.swoole.com/wiki/...

关注 3 回答 2

twosee 回答了问题 · 2019-03-26

Swoole 初学者第一问:这样使用 go 函数对吗?

用的是同步的guzzle的话, 开协程也是没有用的

关注 3 回答 2

认证与成就

  • 获得 5 次点赞
  • 获得 1 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 1 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2017-08-16
个人主页被 908 人浏览