项目切换到Swoole实践

项目背景

用PHP封装的一套接口系统。主要实现调用第三方API接口并按自定义协议解析后返回给上层。通常情况PHP实现的项目效率问题不那么明显,但这种接口调用场景下性能问题变得很突出。由于PHP采用的php-fpm的方式执行,系统一般会启动N个进程解析PHP脚本,但当某个请求延时严重的时候,处理请求的php-fpm只能阻塞不能处理其他请求。所以,

服务的可用性大大折扣,可用性也直接跟对方系统强关联。而此系统又是核心业务,通过增加机器的方式资源利用率极低,线上已有10多台机器用于此服务。为了达到服务的可用性指标,做了一些尝试:

除了熔断之外,其他点对服务稳定性的帮助很微弱,问题跟PHP的进程模型有关系。所以考虑在一定程度上尝试项目重构。

徘徊一圈后还是尝试在试一下swoole。

Swoole重构

Swoole已经是4.3.x的版本,在使用之前做了个初步的压测,相比前一次Swoole的评估好了很多,没有出现明显问题。重构主要是框架层面,尽量不对业务代码的实现做调整,前期的开发过程相对来说还好,需要注意的是:

总体上,对照文档,了解下服务端编程的注意事项,问题不大。但接下来需要做测试,确保服务的稳定系和功能的准确性。所以尝试做压测。

压力测试

前面做评估的时候业务代码较少,嵌入业务代码后压测还真出问题了,4.3.4当访问量大的时候主进程挂了,这意味着服务就完全不可用了。心都凉了一截。一方面复现会麻烦,另一方面Swoole里做了封装,如果是swoole层级的问题很难定位,于是在Github上提Issue找解决思路。也尝试将版本切换到4.2.3过,没有出现主进程退出的问题,但执行一段时间后会有连接不释放的问题,CPU会跑满,即便停止请求,连接也不会释放。后面给Rango提供日志,调试,大概定位到中间版本有问题,对方修复后发布4.3.5,这个问题算是告一段落。

灰度上线

评估后尝试上线,两个版本同时运行,将部分请求切换到Swoole机器。SOAP这类请求就还是回到老机器。上线还比较顺利,资源的利用率上还不错,初步评估一台16核16G的机器,可以跑到800到1000QPS。比之前不稳定的1到200QPS提升不少。

上线后发现过某些请求丢掉的情况,是数据包太大的问题,调整了buffer_output_size参数,正当窃喜的时候,遇到一个新的问题。

Coroutine\Http\Client发请求, 会存在少量状态码返回-3的情况,很快就断开了。客户端请求发出后,服务器强制切断连接。但PHP版本CURL方式的调用上没有出现这个问题。不确定是服务层面的拒绝还是Swoole的问题,要抓异常包也很麻烦,期间做了很多尝试。

配合Rango定位,排查到是底层使用了全局变量,导致并发的时候被其他的协程改写了。

正式上线

经过上个问题后,服务顺利上线了,当然还有一些功能层面的测试,但相比性能这块自己更可控。上线后整体吞吐量提升不少。调用方的QPS翻倍,机器资源减少一半。这还没完,运行一段时间后,发现会存在某个worker死锁的情况,需要重启整个服务才行。影响相对较小一些。后来Rango在4.4的版本把底层共享内存都移除了。切到4.4.15后没再出现。

(运行一年左右了,比较稳定)

感谢Rango的耐心指导,Swoole目前的思路感觉是对的,后续的版本应该会越来越好。Python里有gevent,可方便的实现异步IO。swoole也是在不影响使用的情况下协程化。

总结

-- EOF --
最后更新于: 2020-07-29 16:09
发表于: 2019-10-12 07:40
标签: PHP Swoole