swoole / rfc

Swoole 提案
116 stars 3 forks source link

Swoole 5.0 版本请求意见稿 #34

Open twose opened 5 years ago

twose commented 5 years ago

Swoole 5.0 版本请求意见稿

项目方向

Swoole项目从创建至今已经有超过6年的历史了, 但Swoole协程却是一个全新的事物, 随着4.0版本Swoole的有栈协程问世, Swoole的协程化才真正步入了稳定发展阶段.

Swoole从4.0开始一直致力于提升底层代码的稳定性, 不断地做代码精简与优化, 但异步时代的Swoole遗留下来的历史包袱积重难返, 制约了Swoole的进一步发展, 因此我们Swoole开发组决定面对这些历史问题, 做出一个大胆的决定, 从内核中剔除掉一些会导致协程生态混乱的模块, 只保留纯协程的编码模式, 直接提供PHP协程的最佳实践方案, 开发者无需再去纠结于各种复杂繁琐的配置, 甚至在同步, 异步和协程之中迷茫. Swoole后续的生态将完全建立在协程之上, 并且我们会基于5.0版本重新书写文档, 提供Swoole的最佳实践指南, 最大程度减小Swoole开发者的学习成本.

如果你的应用已经完全基于协程实现(如你正在使用Swoft/EasySwoole3等纯协程框架/组件), 那么5.0的改动不会对你造成多少影响.

我将会在下方列出所有涉及删除或改动的内容, 以重要程度优先级排序, 如果你赞同某部分提案, 请点👍 以表明支持

twose commented 5 years ago

删除异步客户端

它们的存在严重的导致了协程生态的混乱, 你不可能在协程中混用它们, 协程可以100%甚至更好的实现异步, 你可以用轻松地用协程写出异步的效果(你只要使用go创建一个协程, 把代码帖进去, 它就是异步的了), 但异步却无法拥有协程强大的调度能力.

暂不考虑删除timer, 异步写文件等, 在很多场景下它们都很有用, 如异步写日志等, 你无需过多思考或者创建新的协程.

twose commented 5 years ago

删除一些无用的异步回调

这两个水位线回调只是在异步时代为了在缓冲区快满时避免发送失败, 增加了大量的心智负担, 你有了协程以后再也不用理会它了, 协程会帮你自动调度.

twose commented 5 years ago

删除同步阻塞TCP客户端

只应用于fpm模式下, 而且底层为此加入了一些环境判断.

twose commented 5 years ago

删除Runtime配置方法enable_coroutine选项并强制开启

我们要拥抱一个纯协程的生态, 我们就不再需要它们, 就像go语言那样简单纯粹, 既然你使用了Swoole协程, 那么你就要全面启用它, 你的代码里就不应该存在同步阻塞, 否则你写出来的程序将毫无意义.

因此, 协程化将强制开启, 各种事件回调中都会是协程的环境, 而PHP中曾经同步阻塞的一系列IO方法也会变成协程的, 你将不会有太多顾虑, 尽管书写你的协程代码:

twose commented 5 years ago

删除不必要的协程环境自动识别

现在的Swoole中, 如果你使用了coroutine_hook, 或是开启了Runtime::enableCoroutine, 在hook同步函数转为协程调度的时候, 底层会判断当前是否为协程环境, 如不是则退化为同步模式, 这一判断兼容完全没有必要, 而且增加了检查开销, 一旦你使用了协程化, 你就应该只在协程中使用它, 否则你的程序会立即退化为同步模式.

twose commented 5 years ago

最大程度地禁止同步阻塞的方法

目前的Runtime::enableStrictMode是一个比较鸡肋的方法, 而且会和Runtime::enableCoroutine冲突, 如实行了上一个提案内容, 那么严格模式也有了用武之地, Swoole内核将会强制开启严格模式, 禁止所有协程之外的阻塞IO操作, 一旦你在不小心使用了阻塞IO, 你的程序将会立即退化为同步模式, 损失大量的性能, 协程也将失去意义.

所以底层将会在开发者使用了协程的时候, 阻止开发者错误地使用阻塞方法, 并在此时抛出一个致命的错误警告.

twose commented 5 years ago

删除Process模式(有争议的内容)

根据Swoole创始人Rango的意见, Process是一个不那么必要的设计, Process模式最大的作用是在worker进程异常退出的时候Master能够保持长连接不断开. 但是Process模式增加了两次IPC开销, 不支持一些高级功能, 其性能相比于Base模式相差巨大(Base简单高效, 能快速承载海量连接), 并且开发者时常在各种投递模式(dispatch_mode)中作无谓的纠结, 且由于Proces模式的复杂性, 它可能会更容易出错.

Process模式完全可以被nginx等专业的代理替代, 并且在对外的生产环境中, nginx总是必须的, 如http服务, swoole只实现了基本的应用服务器级别的协议解析支持, 而nginx则是拥有最为完备的协议解析支持.

就算没有Process模式, Base模式也支持异步安全重启特性和max_request等特性

twose commented 5 years ago

删除Swoole\Serialize

此功能与PHP内核各种设计和数据结构强依赖, 而PHP内核每个版本都有很大变动, 已经无法继续兼容维护各个版本, 且该功能在一些场景下稳定性无法保证, php的serialize十分稳定且能满足绝大部分开发者的需求, 无需为了节省一些小小的内存而去使用Swoole\Serialize.

twose commented 5 years ago

Swoole\Server协程化

目前Swoole协程还是异步化回调模式的, 如果使用了协程模式, 思路就会非常清晰, 而且代码也是如同同步模式一般, 像长连接的tcp协议(如websocket), 可以直接同步顺序书写每个请求的处理代码, 而不是每次都在回调里处理.

$socket = new Swoole\Coroutine\Socket(AF_INET, SOCK_STREAM, IPPROTO_IP); // 创建服务器socket
$socket->bind('127.0.0.1', 9501); // 绑定端口
$socket->listen(128); // 监听并设置backlog大小
while ($conn = $socket->accept()) {
    // 每接收到一个请求, 就创建一个协程去并发地处理它
    go (function () use ($conn) {
        // 打个招呼
        $conn->send(tcp_pack('Hello~'));
        // 先接收TCP包头长度的数据, 解析包长数据, 再接收包长长度的主体数据
        $data = $conn->recv(tcp_length($conn->recv(tcp_type_length())));
        // 打包后原封不动地发回去
        $conn->send(tcp_pack($data));
        // 开始循环接收, 直到超时或者对方关闭了连接
        while ($len = $conn->recv(tcp_type_length(), 1)) {
            $data = $conn->recv($len);
            echo "{$data}\n";
        }
        // 退出循环体就关闭了
        $conn->close();
    });
}
huangzhhui commented 5 years ago

不赞成删除同步阻塞TCP客户端,Swoole的TCP客户端可以与基于Swoole的TCP服务端很好的配合使用,几乎所有非全新项目,都会存在PHP-FPM和Swoole共存的情况,因此保留同步阻塞TCP客户端有必要。

matyhtf commented 5 years ago

@huangzhhui 可以用 php 的 stream_socket_client 来替换。删除同步阻塞的客户端,可以停止对 fpm 的支持。彻底转变为 cli 的扩展。

youmingdot commented 5 years ago

增加协程切换回调

支持设置协程切换回调方法,并在协程切换时进行调用。这个机制能够给予用户或框架更大的自由,以方便在协程切换前,程序能够对本身所设计的上下文进行切换。

以下为示例:

\Swoole\Coroutine::setYieldCallback(function ($leaving, $coming) {
    echo "协程正在切换,切出协程编号:{$leaving};切入协程编号:{$coming}";
});
TonyChen-SH commented 5 years ago

不支持xdebug,代码怎么读。好像关于调试的便捷性问题,各位大佬好像都不怎么关注。

niwsmbulai1989 commented 5 years ago

什么时候可以出一些有关swoole的组件以及demo,那该多好

bnubobby commented 5 years ago

有没有办法加强TCP封包,解包,可做成c扩展的形式,动态调用 目前的形式限制过大,比如通过tcp传过来,json格式的协议(正确的json格式,没有包长度、末尾没有\r\n)没办法解析,xml格式协议也没办法解析,等。 目前的貌似只能通过接收原始数据,把数据根据客户端 fd 放到缓存里,再用php逐字解析?

sayid commented 5 years ago

希望能默认支持更多的客户端

assert6 commented 5 years ago

删除Process 的话, 那swoft 的Process 功能要用Task 实现?

lizhichao commented 5 years ago

纯粹,极致,简单,稳定,高效

onanying commented 5 years ago

删除Runtime配置方法enable_coroutine选项并强制开启

我们要拥抱一个纯协程的生态, 我们就不再需要它们, 就像go语言那样简单纯粹, 既然你使用了Swoole协程, 那么你就要全面启用它, 你的代码里就不应该存在同步阻塞, 否则你写出来的程序将毫无意义.

因此, 协程化将强制开启, 各种事件回调中都会是协程的环境, 而PHP中曾经同步阻塞的一系列IO方法也会变成协程的, 你将不会有太多顾虑, 尽管书写你的协程代码:

  • phpredis扩展
  • 使用mysqlnd模式的pdomysqli扩展,如果未启用mysqlnd将不支持协程化 (PHP默认就是mysqlnd)
  • soap扩展
  • file_get_contentsfopen等一系列文件函数
  • stream_socket_client (和所有基于它实现的库, 如predis)
  • stream_socket_server(和所有基于它实现的库)
  • fsockopen, gethostbyname(dns查询)
  • sleep, usleep, time_nanosleep, time_sleep_until

协程必然是好的,但是现有 github ,composer 中的库,包括大公司ali, tx这些云平台提供的库,都多少有一些全局变量的问题,导致无法使用协程方式开发,强制只能使用协程,虽然可以全部写到一个子协程里保证兼容,但是不是太浪费了一些?

onanying commented 5 years ago

最大程度地禁止同步阻塞的方法

目前的Runtime::enableStrictMode是一个比较鸡肋的方法, 而且会和Runtime::enableCoroutine冲突, 如实行了上一个提案内容, 那么严格模式也有了用武之地, Swoole内核将会强制开启严格模式, 禁止所有协程之外的阻塞IO操作, 一旦你在不小心使用了阻塞IO, 你的程序将会立即退化为同步模式, 损失大量的性能, 协程也将失去意义.

所以底层将会在开发者使用了协程的时候, 阻止开发者错误地使用阻塞方法, 并在此时抛出一个致命的错误警告.

我要用 redis 的 brpop 怎么办?在 golang 里也是能用的。

jonny77 commented 5 years ago

弱弱地问一下 啥时候出 从入门到精通的教程 如果能像thinkphp的文档一样牛皮 推进速度会快100倍

onanying commented 5 years ago

删除Process模式(有争议的内容)

根据Swoole创始人Rango的意见, Process是一个不那么必要的设计, Process模式最大的作用是在worker进程异常退出的时候Master能够保持长连接不断开. 但是Process模式增加了两次IPC开销, 不支持一些高级功能, 其性能相比于Base模式相差巨大(Base简单高效, 能快速承载海量连接), 并且开发者时常在各种投递模式(dispatch_mode)中作无谓的纠结, 且由于Proces模式的复杂性, 它可能会更容易出错.

Process模式完全可以被nginx等专业的代理替代, 并且在对外的生产环境中, nginx总是必须的, 如http服务, swoole只实现了基本的应用服务器级别的协议解析支持, 而nginx则是拥有最为完备的协议解析支持.

就算没有Process模式, Base模式也支持异步安全重启特性和max_request等特性

移除 Process 的话,那得要像 go 一样支持 runtime.GOMAXPROCS 才行啊,不然开多个相同代码的进程才能使用到其他 cpu ,感觉有些不太好吧。

limingxinleo commented 5 years ago

@onanying 如果开启了严格模式,brpop将无法使用么?严格模式应该是避免在协程里面有阻塞的方法吧。。如果本来就是同步的cli,使用brpop应该没事吧。。我没研究过这里,不太清楚。。。

motecshine commented 5 years ago

在现有代码里 没有看到 corouting 调度的策略 , 也就是每个go 都是 新的thread么

mojianyuan commented 5 years ago

请考虑一下exec、curl原生协程的支持,特别是curl这个组件在composer, tx, aliyun的sdk中应用太多, 要替换成stream之类的库是个丰常麻烦的事。

xianqiangzhao commented 5 years ago

swoole 扩展功能模块很多,同步,异步,协程,未来的方向是什么? 更快,更易维护,更稳定,更好的生态。 刚开始是做加法,什么功能都加进入,现在是做减法,去掉包袱,更好的前行。 还要考虑老用户,老版本要维护,是不是令开辟一个产品线去主攻协程更好呢?

twose commented 5 years ago

计划中的5.0版本就是这样的一个纯协程版本,4.x转为lts,同步异步协程并存。

GXhua commented 5 years ago

删除Process模式(有争议的内容)

根据Swoole创始人Rango的意见, Process是一个不那么必要的设计, Process模式最大的作用是在worker进程异常退出的时候Master能够保持长连接不断开. 但是Process模式增加了两次IPC开销, 不支持一些高级功能, 其性能相比于Base模式相差巨大(Base简单高效, 能快速承载海量连接), 并且开发者时常在各种投递模式(dispatch_mode)中作无谓的纠结, 且由于Proces模式的复杂性, 它可能会更容易出错.

Process模式完全可以被nginx等专业的代理替代, 并且在对外的生产环境中, nginx总是必须的, 如http服务, swoole只实现了基本的应用服务器级别的协议解析支持, 而nginx则是拥有最为完备的协议解析支持.

就算没有Process模式, Base模式也支持异步安全重启特性和max_request等特性

来自开发组内部的争议主要是我反对 - - 1 base模式下如果用户没有解决内存泄漏通过 max_request来规避内存泄漏 会造成连接意外断开,如果内部服务或者直接用swoole写自定义的网关 相当于服务器频繁重启 这个是很难接受的。 2 如果用户解决了内存泄漏问题 很多状态会保存在进程的静态变量里面,会用到Server->bind来将用户请求指定worker进程,base模式也是支持不了的。

twose commented 5 years ago

@onanying @limingxinleo brpop只是会阻塞对应的协程客户端和客户端所绑定的单个协程, 其它协程仍在运行, 不受影响, 在协程里曾经的阻塞方法都会被自动调度, 让出控制权.

luohonen commented 5 years ago

强烈支持纯协程版本,5.0出来立马再捐献一波

twose commented 5 years ago

@niwsmbulai1989 @jonny77

弱弱地问一下 啥时候出 从入门到精通的教程 如果能像thinkphp的文档一样牛皮 推进速度会快100倍

什么时候可以出一些有关swoole的组件以及demo,那该多好

如果5.0版本计划确定, 我们将会推出一个全新的Swoole协程开发最佳实践手册

twose commented 5 years ago

@TonyChen-SH

不支持xdebug,代码怎么读。好像关于调试的便捷性问题,各位大佬好像都不怎么关注。

Xdebug设计上大量依赖了全局变量导致无法支持协程, swoole现在有协程迭代器, 协程调用栈跟踪, 协程gdb调试工具, 基本能满足一般的调试或者断点, 可能你只是固守了xdebug的方式, 没有了解. https://wiki.swoole.com/wiki/page/968.html https://wiki.swoole.com/wiki/page/967.html https://wiki.swoole.com/wiki/page/1011.html

twose commented 5 years ago

@bnubobby @motecshine

在现有代码里 没有看到 corouting 调度的策略 , 也就是每个go 都是 新的thread么

有没有办法加强TCP封包,解包,可做成c扩展的形式,动态调用 目前的形式限制过大,比如通过tcp传过来,json格式的协议(正确的json格式,没有包长度、末尾没有\r\n)没办法解析,xml格式协议也没办法解析,等。 目前的貌似只能通过接收原始数据,把数据根据客户端 fd 放到缓存里,再用php逐字解析?

两位对swoole的认知有误, 可以去多读一读例子和文档.

windrunner414 commented 5 years ago

@zcmzc 删除的是server的process模式,不是swoole_process @onanying swoole_base模式同样支持worker_num设置,brpop不等于阻塞IO,协程客户端支持brpop

process模式又复杂又影响性能,有base就够了

twose commented 5 years ago

协程必然是好的,但是现有 github ,composer 中的库,包括大公司ali, tx这些云平台提供的库,都多少有一些全局变量的问题,导致无法使用协程方式开发,强制只能使用协程,虽然可以全部写到一个子协程里保证兼容,但是不是太浪费了一些?

不去创建协程, 就不会强制协程, 对原有同步无影响.

1019227215 commented 5 years ago

文档太少,案例太少,成熟技术社区太少;真正懂的人不是很多

iiQi commented 5 years ago

@TonyChen-SH

不支持xdebug,代码怎么读。好像关于调试的便捷性问题,各位大佬好像都不怎么关注。

Xdebug设计上大量依赖了全局变量导致无法支持协程, swoole现在有协程迭代器, 协程调用栈跟踪, 协程gdb调试工具, 基本能满足一般的调试或者断点, 可能你只是固守了xdebug的方式, 没有了解. https://wiki.swoole.com/wiki/page/968.html https://wiki.swoole.com/wiki/page/967.html https://wiki.swoole.com/wiki/page/1011.html

能支持IDE的断点调试么?

simoole commented 5 years ago

强烈支持5.0纯净版,虽然应用后我写的框架可能会需要大改,不过这都不是事儿。那些依赖github、composer上一些过时代码的人,大可以继续使用旧版本的swoole。 这里我有个建议,希望5.0之后swoole研发团队能更加重视生态的发展,例如文档精化、社区激励、视频和图文教程、以及与各大PHP培训公司沟通等。

fdreamsu commented 5 years ago

Base模式是否可以做到支持设置 dispatch_func ? 我这边在跑的一个有状态的ws server很依赖 dispatch_func ,使得在对战中同一个房间的连接可以处于同一个worker中。

onanying commented 5 years ago

@onanying @limingxinleo @twose brpop只是会阻塞对应的协程客户端和客户端所绑定的单个协程, 其它协程仍在运行, 不受影响, 在协程里曾经的阻塞方法都会被自动调度, 让出控制权.

那你写的这个描述要修改一下了,我以为使用就会抛出错误。

所以底层将会在开发者使用了协程的时候, 阻止开发者错误地使用阻塞方法, 并在此时抛出一个致命的错误警告.
fdreamsu commented 5 years ago

Base模式下貌似sendMessageonPipeMessage都不支持?这对于已有逻辑的影响还是挺大的

youmingdot commented 5 years ago

支持 CURL 协程

这个关键性就不说了,很多工具库都直接用了 curl,改是很难,如果底层直接支持协程,效果非同凡响。

donknap commented 5 years ago

去掉 SWOOLE_PROCESS 模式,是否就是现在使用 addProcess 不能使用了,创建 Process 需要在 server start 之前手动 start? 那这个自定义 process 怎么和 server 进行通信?刚才试了一下 4.x 的 BASE 模式下,好像 $server->sendMessage 也不能使用了。

tw2066 commented 5 years ago

希望能增加 1.协程回收,超时处理 2.协程监控,内存泄漏 3.文档更加完善

ligaofeng commented 5 years ago

希望从5.0起文档详细点,样例多点。以往的文档对普通开发者要求要掌握的理论太多了

tw2066 commented 5 years ago

多进程开发,数据同步问题, 比golang还考虑的多; 很多需要借助第三方工具,希望5.0能有好的解决方案;

daydaygo commented 5 years ago

删除同步阻塞TCP客户端

只应用于fpm模式下, 而且底层为此加入了一些环境判断.

可以拆分出来单独维护么? swoole 的一些 client 确实比其他的好用, 特别是 socket\client

windrunner414 commented 5 years ago

@fdreamsu 理论上可以实现dispatch_mode 但是会稍微复杂一点……

matyhtf commented 5 years ago

删除同步阻塞TCP客户端

只应用于fpm模式下, 而且底层为此加入了一些环境判断.

可以拆分出来单独维护么? swoole 的一些 client 确实比其他的好用, 特别是 socket\client

这个建议很好,我们考虑一下。拆分成几个独立的扩展。Swoole 5.0 core 目前只会保留协程的模式。

Yurunsoft commented 5 years ago
  1. 希望能够监听协程的创建和销毁,以便管理上下文
  2. 协程MySQL和协程Redis是否也可以砍掉,直接上PDOphpredis,减少不必要的维护工作,因为有很多新特性,可能不能及时去支持,虽然一键协程化后的性能要比Swoole实现的差一些
  3. xdebug调试不兼容,如果用gdb那根本不现实,也不利于推广swoole
  4. 如果禁止协程中跑阻塞代码,那如果有某个sdk不支持协程,一键协程化也不能支持,那想要在项目里将就用都做不到,那肯定很难受