Golang Go语言中 PHP 部分改造为 go 与全部改造为 go 是否会提升性能?

发布于 1周前 作者 htzhanglong 来自 Go语言

由于 php-fpm 是以进程为单位提供服务的,大量 php-fpm 进程运行并接收客户端请求,当 php-fpm 极其依赖缓存、数据库等外部服务时,php-fpm 与外部服务之间的网络连接交互也会多,导致网络 IO 频繁,进而导致 php-fpm 进程间的频繁切换问题。这种情况经常在监控上显示为进程的墙钟时间比较大,cpu 消耗时间比较小。

所以在考虑如果用 go 改造的话,使用 go 去连接缓存、数据库等外部服务,php-fpm 充当纯前端 SSR 从 go 那里获取数据渲染页面。那么,在服务器资源配置不变的情况下,请求量与之前不变的情况下,应用性能是否会有所提高?这里主要指 RT 响应时间是否会缩短?

但是我觉得假设改造前是 100 个 fpm 进程,改造后还是 100 个 fpm 进程,并且还要增加一个 go 进程,100 个 fpm 依然要与 go 连接,依然会在 100 个 fpm 进程之间切换进程,所以在资源配置不变的情况下,RT 响应时间应该也不会变化太大吧?
难道需要 go 把 php-fpm 全部替代了?
Golang Go语言中 PHP 部分改造为 go 与全部改造为 go 是否会提升性能?


更多关于Golang Go语言中 PHP 部分改造为 go 与全部改造为 go 是否会提升性能?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

101 回复

可以一步到位,不过 golang 写业务有点难受

更多关于Golang Go语言中 PHP 部分改造为 go 与全部改造为 go 是否会提升性能?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


团队没人懂 golang 的话可以先试试 swoole

go 写业务还是有点难受的。。

你确定要这么干?

#3

而且 php 是弱类型。。。

迁移起来。。可能不太容易。

先确定是否真的需要走这一步,看看实际 QPS 是多少
如果你团队的技术栈都是 php ,换 swoole 比较好

部分业务并发高的地方, 可以用 go 写, 然后用 nginx 转发过去 这样 原来 100 个 fpm 就可以降低到 50 个以下了.

并不只有 Go 才有协程,PHP/C#/TS/Java/C++都有协程,你这个场景可以直接上协程,swoole 搞起来 IO 问题就解决了

不靠谱
建议不要做这种重构, 而是先把高负载高占用的服务挑出来, 重新设计实现.

其实 不建议用 swoole 如果是个大团队 有人可以搞 swoole 源码和二开可以搞搞, 没有不建议弄 可以试试 workman 或者 webman

主要 php 在组装数据方面写的比较爽。。所以我也不太想全部改掉

那一般 go 用来干啥啊?不是说用 go 来提升 php 性能是比较好的选择吗?

好像有点道理,可以减少 fpm 的数量了,go 的 rt 时间相比原先 fpm 缩短了,如果并发量不变的话,少量的 fpm 是可以承住的

#11

话是这么说。。但是得看你实际情况啊。

老项目除非真的项目瓶颈,不然不建议大改。

改最好也是慢慢改,go 跟 php 比虽然会提升性能,但是 php 的很多东西在 go 写起来是有些麻烦的。

他俩走的路子区别还是挺大的。

花精力研究这个,不如用 Go 重构。要么就别改

看你当下这个场景,我觉得 swoole 可能是成本最低的。

是啊。。所以我来这问问没有经历过类似这样情况的的朋友。。换语言改造提升性能我也是想着只把性能瓶颈的地方换了。。但在考虑的时候想了主题中提到的问题,所以怀疑只把这部分瓶颈的地方换掉是不是不会有提升?所以才有了这主题帖

之前团队有个项目,单纯把 php 翻译起 go,没做任何优化,性能翻倍了

换 go 不是一样依赖外部服务?先找到瓶颈在哪

具体怎么说?性能翻倍表现在哪里?相同 qps 下 cpu 降了?还是相同配置下 qps 升了?还是啥的?

#17

php 翻译到 go 。。

有点接近小重构了,这俩区别还是挺大的,你们原来 php 用的是 php-fpm 还是 workerman/swoole 这种?

我的建议是,先把系统拆分,按功能拆也行,按业务拆也行。拆开后,看哪个有性能问题,就哪个用 go 重写。
如果没办法拆,那就整个重写,或者保持现状。

瓶颈分析了啊。。就是依赖外部服务导致网络 IO 大,fpm 进程切换频繁消耗 cpu 资源。。用 go 的话至少是协程、线程级别的上下文切换。。。但是相同服务器配置下,两个放一起能否提升性能就是本文要问的问题

webman 和 swoole 改 go 提升是很有限的
改 go 的主要目的是提高单机并发数
至于原来的业务假如有调大量的外部接口和流式执行依赖查库性能并不会有多少提升。
提升比较大的是需要从数据库查询大量数据之后做处理这个部分的耗时
laravel 的性能确实比较垃圾 毫无疑义 但已经不是现代 php 了
用 laravel 的底线是要上 octane

意思是改用 go 的话对于响应时间优化并不会有太大帮助?依赖外部服务查询数据的瓶颈主要还是在于网络传输性能与外部服务的性能吗?

我是反着走,之前有 go 写的,业务一繁杂,go 写来相当难受,一个普通的用户权限控制,go 啥都没有,而 php 就几行代码搞定了

不知道这个结论是想出来的还是测出来的?进程大概有多少,IO 并发有多少?

#25
https://www.techempower.com/benchmarks/#section=data-r21&hw=ph&test=db&l=zijnjz-6bj
权威测评 不是我乱说

无理由臆想质疑拿数据说话吧。

会。比如 www.huabbao.com ,之前是 ThinkPHP+K8S ,后来瓶颈部分统统用 go 拆出来了。很不错

目前只是根据少部分监控数据猜测出来的。。php 的调用栈的监控数据显示,每个慢的请求中,都是慢在了从外部服务获取数据的过程(如 fread 、Memcached::get 、Redis::get 之类的),而且消耗的时间上,wall time 挺大的,但是 cpu time 很小。并且服务器网络监控上,服务器带宽、收发数据包 pps 都没有打满。。所以目前是猜测在等待网络 IO 传输数据的过程中进程切换导致的时间消耗。。。进程目前大概是 cpu 核数的 8 倍,但再增加导致 RT 时间变长,减少的话也会变长。。

基于你上面的分析,如果真的是你说的这个问题,是在请求外部服务的时候,延迟高,那你只能整个重构才能解决吧,具体的就是直接使用 外部服务的时候,由目前的单次连接,改成连接池?

我以前遇到过的是,redis 所在服务带宽满了,阿里的 redis ,出口带宽很低,缓存的单个 key 数据量不能大

感觉还要是基于 目前的 qps 和瓶颈解决问题
php 性能确实不如 go
但是绝大部分项目,都触碰不到 php 的性能瓶颈的
在团队主要技术栈是 php 的情况下,没有必要硬上 go 吧
如果真的要上,可以按功能,甚至按接口来拆分,这样影响最小,效果明显,代价也小

当然其实我还是建议上 swoole 的,切 hyperf

go 我用来解决 php 异步的问题切换了部分业务过去,单纯业务还是 php 舒服

之前重构过一个服务, 日 3000w 请求. 常见的缓存接口, 还有一些个人中心收藏接口. 从 16 个 pod 降到了 5 个.
你可以参考一下.

#25
举个例子说明下
情况 1
假设你提供一个接口 A
接口的功能是通过 Http 调用外部接口接口 B 接口响应时间是 100ms
那你的接口响应时间 100ms+ 无论是 go 还是 php 对吧。。。

情况 2
假设你提供一个接口 A
接口的功能是通过 Http 调用外部接口接口 B 接口响应时间是 100ms
同时还要再依赖接口 B 的返回值去调接口 C 接口响应时间是 100ms
那你的接口响应时间 200ms+ 无论是 go 还是 php 对吧。。。

情况 3
假设你提供一个接口 A
接口的功能是通过 Http 调用外部接口接口 B 接口响应时间是 100ms
另外去调接口 C 不需要依赖 B 的返回值 接口响应时间是 100ms
使用 go 和 swoole A 接口响应时间是 100ms+ 因为是协程并发调用 等待时间以最长的为准。
这种情况下用 go/swoole 可以改善响应时间 但 swoole 和 go 的差距并没有那么大

同样逻辑适用于写库 调接口各种 io 等待的同理
串行依赖意义不大,可以并行才能降低响应时间

你需要考虑有哪些业务是适合用 go/swoole 去写 而不是说上来就重构。。。
几个接口的任务量和一个系统重构的业务量是两码事。。。

go 的学习成本没那么高,用业务切入边写边学,几天就能上手了,哪怕用的不精通,写出来的东西性能也吊打 php-fpm ,所以收益非常高投入低。
切多少就看你想投入多少精力动老代码了。

什么框架啊,如果是 laravel ,把版本升到 8 ,用 go 或者 swoole 开个 octane 加速,从此告别 fpm ,除了手写的单例代码基本不用改

看描述是 php-fpm 由于没有连接池不能复用 IO 导致的 IO 拥堵,切换到 Go 可以用连接池来解决这个问题,那为什么不把这部分用 swoole 这类支持连接池的来重构呢?还能复用之前的 PHP 代码。

或者另一个角度,能否优化缓存来降低 IO 呢?前端页面缓存,API 缓存,数据库缓存这些

mysql redis 这些配置成长连接,算是连接池了吧。

qps cpu 我当时没看 因为也不是我重构的 季会的时候 做的那个人汇报的

php-fpm 用的 larval 框架

相同配置下 qps 升了

go 写业务我觉得还行啊


要确认进程等待时间是在等待 IO 还是等待调度(大致看一下 CPU 利用率和 load ,做 profiling )。考虑把一些同步阻塞的 IO 异步化。

说不定用 php 重写一遍 qps 也升了

golang 发展到如今,其实在微服务领域已经有一些不错的方案了,字节也好,bilibili 也好。都有开源的项目。我局的吧,如果你要用 golang 来重构,心里上要接受一些不同,甚至是认知上的改变,比如我很多同事,以前搞 java 的,喜欢了封装继承多态那套东西,用了 golang 水土不服了很长一段时间。但是,当你能驾驭 golang 这批烈马之后,你会发现,以前你看不上的 2 核 4G 的 ESC 原来也可以这么顺眼。还有就是,当我们进入了 golang 的世界后。你写微服务方式大概率都会改变。

你可以试试哈哈哈哈哈

我们公司项目日活百万+,目前用的 php 绰绰有余,一些业务 PHP 不好搞用的 GO ,比如某个时间点要推送几十万营销消息,go 协程速度才能满足需求。

“从 A 语言换为 B 语言导致性能提升 XYZ 倍”这种事一般不是因为换语言本身,而是换语言这个大动作不可能以对旧版系统慢慢重构的方式进行,那么本质上就是重写一遍,那么就要重新架构,重新思考,“终于特喵的有机会偿还技术债了” ^_^

用 go 写业务挺爽的, 就是你原来是 php ,迁移到 go 强类型,数据库等各个方面很可能有字段类型不一致的坑。

这不就是我司吗,从 php 逐渐迁移到 go ,机器数量少了 90%(当然一部分原因是旧 php 代码写的太烂)

go 写业务主要是 orm 不顺畅, 其他很爽的

F 墙( base64 ) aHR0cHM6Ly9jaG5yb3V0ZS5jb20vYXV0aC9yZWdpc3Rlcj9jb2RlPUZUSzZJRQ==

业务还是 php 吧,一些要求高性能的点可以切到 go

请问这个 orm 不顺畅 具体是哪些问题啊?

试试 roadrunner ?

增加性能我不确定
但是能增加就业

PHP 哪有你说的这么高级,有进程切换都笑哭了。。应该就是你的 io 慢吧? 下面是网上找的:
1 、nginx 和 php-fpm 都是多进程,一个进程只有一个线程;
2 、nginx 一个线程是非阻塞/io 多路复用/epoll 模型,将请求分发后无需等待,仅监听回调结果
3 、php-fpm 一个线程是阻塞模型,必须等待该客户端请求 php 服务端返回数据,下一个 nginx 发过来的请求才能被受理

https://habr.com/en/articles/646397/

nginx php-fpm
nginx unit
Laravel octane(roadrunner, swoole)

说实话不如加机器,除非重构

如果是 Laravel 的话,可以尝试下 https://github.com/hhxsv5/laravel-s 用 swoole 跑,代码改造不会太大,改造方法按照文档改即可
当然 Laravel 官方也出了个 octane ,也差不太多




我们一个 Larvel 5.8 的老项目,用 laravel-s 后 Response Time 变低了、所支持的 QPS 也更高了,改造成本低见效很快
现在我们这个项目新的迭代功能( api )准备用 Hyperf 搞了,用的携程还比较舒服

我正在 go 重构,很满意

#60 对呀,不是说,机器便宜,程序猿贵吗?

花这么多工时重构,足够加多少机器了都。。

差不多就是你说的意思,你举的例子是 php 在单个请求处理中,有着多个串行依赖请求外部接口,如果不是串行依赖的,来用 go/swoole 协程并发处理。我所想的是,把多个 php 请求处理(进程级别的,每个进程中处理着串行依赖外部请求)使用 go 协程并发来处理(协程级别的,并发处理多个请求,每个请求里还是处理串行依赖外部请求或者还可以再并发处理外部请求)。。

我目前还没打算重构,我还在评估我的问题用这种方式能否得以解决。。。除了你提到的这些,我这个主题帖的主要问题是在想这种部分重构的情况下,响应时间是否会有所提升。

目前 6 楼的朋友应该是 get 到了我当前的主要问题。。可以把这主题中的 go 换成 swoole 、java 等,但问题是原 100 个 fpm 进程还保留的情况下、机器配置不变的情况下,增加 go/swoole 是否会优化单个请求的响应时间

可能你的场景 直接上 Swoole 会比重构 Go 更好吧?
首先是 Swoole 基于 PHP ,对于来说该有的都有
第二 Swoole 在 TP 、Laravel 等框架中都有官方、三方提供的 Swoole 集成方案。可以在较少的成本下完成 Swoole 的接入

我缓存也是走的网络 IO 。。。现在拿缓存数据也是慢。数据库也已经做过一轮优化了。我在 30 楼回复中留有了一些监控信息。。所以不知道是不是网络 IO 阻塞导致的频繁进程切换

https://www.workerman.net/doc/webman/
带数据库查询业务,webman 单机吞吐量达到 39 万 QPS ,比传统 php-fpm 架构的 laravel 框架高出近 80 倍。
带数据库查询业务,webman 比同类型 go 语言的 web 框架性能高一倍左右。
https://www.workerman.net/doc/assets/img/benchmarks-go.png

直接上 php8 cli 一把梭

哈哈 其实这才是 php 真正的用法 我写了那么多年 c# java 依然热爱 php

我的项目已经慢慢的从 laravel 切换为 hyperf 了,
laravel 虽然有 octane , 但不支持协程之类 swoole 的特性,
而且 hyperf 很多是用 laravel 的东西,迁移框架的成本不是很大

使用 go 去连接缓存、数据库等外部服务

并不会有明显改善。。。不但做不到肉眼可见的那种改善,有可能是整体对外都没有变化。。。

现代的服务器,语言导致的性能问题基本上属于可以忽略不计的,或者应该是做为最后阶段才需要去考虑的。

php-fpm 模式下也是支持连接池的呀

https://www.php.net/manual/en/function.stream-socket-client.php
开启 STREAM_CLIENT_PERSISTENT flag ,就是连接池了

php 本质上是 C 的超集,做了再封装而已。性能应该跟 Go 没什么区别。
问题是很多人喜欢给 PHP 添砖加瓦,整一些模块化,框架化之类的,做得好了方便业务,做得不好就会变成你所想的那样,不知道哪里的地方拖后腿。

因此很多人把业务从 php 迁移到 go 重做,就是把以前 php 时代胡来的坑都填了。
另外可能公司有钱了会请个架构师把业务梳理一遍,合理设计架构来避免短板。

那如果是这样,我觉得迁移到 go 也不是不好,只是苦了研发部的各位就是了。

不懂 PHP ,但好像有个 ReactPHP ,好像就是参考了 Node.js 的事件驱动设计,专门处理 I/O 密集型任务。

没写过 go ,想请教下 go 为什么写业务难受,我倒是做过 php 重构成 java ,不知道 php2go 跟 php2java 是一个难受级别吗?

有时间想学技术可以改,不然别没事找事。

楼上说用 go 写业务难的,是难在哪里了?数据绑定么?
业务逻辑不都是一堆 if else 怎么 php 就不难 用 go 就难了?
是你思路不对 还是不想写

100 个进程的切换还好吧,切换不会造成性能数量级的降低。这种由于外部请求造成的请求慢,换了 GO 也是一样的,没区别。
如果只是想让监控数据好看,可以这样,把事件等待和回调全部放在一个进程里做,其他进程只管预处理和分发请求。这样 wall time 就转移到单个进程,就会感觉几乎每个进程都在很努力的干活了。

fpm 不能通过池来复用链接,TCP 连接的大量建立和销毁,也是会拖累 IO 的

swoole/swow 就是解决 io 阻塞问题的,swoole 不能缩短单个请求的响应时间,但是可以搞定并发。php-fpm 下 100 个请求就要 100 个进程,swoole 下单进程就可以

完全改造就不需要 PHP-fpm 了,参照 alist https://github.com/alist-org/alist

为什么这么多人认为 go 写业务难的,我从 php 转 go 感觉可顺畅了,php 能做的 go 能做,不好做的 go 也能做

不过重构容易踩坑 可以考虑下 webman

新项目无所谓,改造的话,业务包袱重,不建议。为了绩效,那就选自己不熟悉的吧

以我处理过的情况来看, 只要把 php 和 go 的 session 同步起来, 改造起来应该是比较顺畅的. 如果是前后端分离的架构就更好了, 通过 nginx 或 apache 代理来转发请求, 也可以做到无感切换. 处理效率上来说肯定是有提升的, 这个都不用怀疑. 也可以用 swoole 来做这个事, 看团队更熟悉哪个吧.


因为写业务有更好用的语言,那不当然显得 Go 麻烦嘛。

如果你的 php 代码都是请求第三方接口的,时间不会减少。go 能加速的只有中间件连接的时间跟微软的代码执行时间。像我司的业务很多都是请求内部大数据接口的业务,接口本身都 1-2s 的时间,go 能加速这个时间?

都是内部接口的话,直接 rpcx 会不会是更好的选择

ssh 哥挺活跃

业务有需求吗?

没有需求这不就是面向简历编程吗。。。。不建议拿生产系统玩票。

没啥问题 我就是无缝切换 看公司给你不给你时间了

不如升高 php 版本

我们日均千万 PV 并没遇见 PHP 语言方面性能的瓶颈,OP 确定是语言的问题?

swoole 还不如用 golang 重写呢,工具链及相关生态极度不完善,用起来一堆坑

题中所说 100 个 fpm 进程只是举个例子,当然还得看机器配置。。最主要的意思是如果本身 100fpm 出现了当前的问题,那么我再在当前机器上加入改写的 go 的应用,把一些依赖外部网络请求的部分放到 go 里,是否能降低 web 请求响应时间、是否能降低机器 cpu 消耗


是的,大量的 tcp 连接建立和销毁以及 php 进程在网络 IO 阻塞导致的切换。。我现在是想对这方面进行优化


你所说的“时间不会减少”要看是什么的时间吧。。。如 34 楼老兄所说,如果我有非串行依赖请求,那么我可以用 go/swoole 尝试进行并发请求。。另外把 php 没有连接池、频繁建立和销毁 tcp 连接、频繁网络 io 阻塞导致的进程切换时间都用 go/swoole 来尝试改造,这部分的时间还是能减少的吧。。我所指的能减少的时间是“我服务端对客户端的响应时间”



[另外最后再补充下啊] 当前公司给的目标是服务器等成本降本,当前服务器配置下日均 pv 也是千万,业务应用能正常承受,是没问题的。。。所以我的重点目标还是继续优化性能,看看能否再减少服务器。。所以目前找到的优化点是这个 php-fpm 下的网络请求 IO 阻塞问题。具体大家可以看下前面和大家的对话。。实际上 swoole 与 go 都可以,但再出于后期找工作的考虑,所以想选 go ,咱就不再在 go 还是 swoole 等上面纠结了。。咱们就讨论用异步 IO 、连接池、协程处理并发等方面看看能否将传统 php-fpm 模式下的这个问题进行优化?

典型的 PHP-FPM 进程模型的低效 IO 等待问题,你换任何一个异步非阻塞的语言/框架都可以解决。
引用我以前的回复 https://v2ex.com/t/822487#reply65
“很多人说你的项目压根用不到语言的瓶颈,但他们往往说的是计算瓶颈,而不是 io 瓶颈。很多 php 用户没搞清楚“异步里面不能套同步”就上 swoole ,就和很多 python 用户在 tornado/fastapi/asyncio 里用内置 file 等 io 阻塞型函数,java 用户在 netty 里用 jdbc 那样”

识别出来之后,其实剩下的方案选择更多是“政治”问题,因为不同的公司文化在这种情况会出现不同的选择。很多技术选型其实是最上面的技术管理当时拍的脑袋决定的,就看现在这个脑袋由谁来拍了。


坚持用 PHP 方案解决的理由无非是团队里擅长这个,你贸然更换技术栈之后出了事故没人兜底,各种疑难杂症没人解决,看你决心而已。当然为了让其他人更好的支持你,你最好写完之后,把各种常见 PHP 代码片段的 Go 实现贴出来,搞点技术分享,帮大家快速入门,大家爽了之后就会更愿意支持你。

这里可以给一个说服你用 Go 的理由:现在百度旧项目要让用 go 重写,新项目不能用 PHP 。

另外,你的问题其实就是要做到“全链路异步 IO”,需要从最入口的位置开始做全链路异步的方案替换,这种问题都是越早改造收益越大,很多问题一开始选对方案就根本不会出现,加班都不需要。

反例就是各种 java 技术栈公司累死累活的改造,还有经常在站里吹的“动态线程池”方案,没有问题愣是给你创造问题:
https://my.oschina.net/u/4273516/blog/4543708
https://juejin.cn/post/7239895900296888376

没有性能瓶颈,没必要。。go 更容易出问题

肯定会提升性能,但是增加开发成本与维护成本。go 程序员与 php 程序员薪资考虑一下

异步里面不能套同步? swoole 下 io 阻塞都能 hook 掉,不存在阻塞啊

针对“Golang中PHP部分改造为Go与全部改造为Go是否会提升性能”的问题,作为IT领域GO语言方面的专家,我的分析如下:

将PHP部分改造为Go语言,确实有可能提升性能。Go语言以其编译速度快、并发处理能力强以及语法简单清晰等特点著称。相比PHP,Go语言在性能上通常具有优势,尤其是在需要高效并发处理的场景下。

然而,性能提升的程度取决于多个因素:

  1. 改造范围:如果只是将PHP中的关键部分或瓶颈部分改造为Go,那么性能提升可能较为有限。相反,如果进行全面改造,理论上可以获得更大的性能提升。
  2. 代码质量:无论是PHP还是Go,代码质量都是影响性能的关键因素。优化算法、数据结构以及减少不必要的计算等,都可以显著提升性能。
  3. 系统架构:系统架构的合理设计也是提升性能的重要因素。在改造过程中,需要确保新的Go代码能够很好地融入现有系统架构,并充分利用Go语言的并发处理能力。

综上所述,将PHP部分或全部改造为Go语言,在理论上都有可能提升性能。但具体提升程度需要根据实际情况进行评估,并通过测试来验证。

回到顶部