yaf整合swoole开发web应用

背景

公司的主要技术栈有php,golang,lua。php开发效率高,出活快主要服务于业务。golang由于稳定,并发性好,房间服务,长链服务都基于此。lua用于图床,抽奖等服务。phper都希望在开发效率高的情况下,服务性能也高些。公司发展前期php项目采用pylon框架(奇虎一位大神开发的php扩展),php7的出现,性能提升2倍,开发同学直接考虑到升级php,但pylon对php兼容不好。还有pylon本身难度比较大,新人上手速度慢。最后迁到了php7+yaf。但与golang项目相比还是差很多,以下数据是同事在测试环境下压测的结果,可供参考:

空跑是golang的25%

读redis性能是golang的30%

curl是golang的29%

so, 我们希望还是尽可能的提高性能

调研项目

1.swoole扩展:普通的扩展只是提供一个库函数。而swoole扩展在运行后会接管PHP的控制权,进入事件循环。当IO事件发生后,swoole会自动回调指定的PHP函数。也就是基于swoole开发不再依赖于php-fpm, 这个是与其他php扩展不一样的地方。swoole功能强大(可参考官方说明),但是直接开发项目成本太大。

2.easyswoole: 基于swoole封装的php框架,性能高,但项目在发展初期,代码也不太规范(后面作者开始2.0开发)。考虑到稳定,忍痛放弃。

改造

1.mvc功能

yaf扩展实现了一个完整的mvc框架。 接受请求,路由分发,逻辑执行,响应请求。而swoole在不同进程中都提供了事件接口,开发者根据需要实现对应事件处理方法即可,必须业务逻辑可在request事件中实现。

相比yaf, swoole_http_server解析http请求效率更高,它是一次性读取所有SOCKET数据到内存,然后再去解析,比php-fpm的逐个read节省了大量系统调用,效率要更高,单测空接口性能提升3倍左右。支持PHP对象和全局变量、资源持久化,所以不需要重复创建销毁某些对象/变量/资源,所以节省了很多CPU消耗。

swoole+yaf方案即可发挥两者的优点, 基本的路由实现是在swoole_http_server的request事件上让yaf来根据uri来分发路由。下面展示部分代码

2.异步任务

一般web应用开发中,都会遇到一些耗时操作。在php-fpm环境下,通过fastcgi_finish_request()处理,但是在还会阻塞当前的worker。在并发稍微高的情况下会大量请求得不到处理。或者投递到redis队列,然后异步消费,这样增加了代码的复杂。但这种情况,可以利用swoole很好的处理,我们先看看swoole的进程模型

相比php-fpm Master+Worker的工作默认,swoole除了manager管理进程还多了Task进程。一个更通俗的比喻,假设就是一个工厂,那就是销售,接受客户订单。而就是工人,当销售接到订单后,去工作生产出客户要的东西。而可以理解为行政人员,可以帮助干些杂事,让专心工作。那下面就是监听任务和投递任务了。

1. 任务监听通过swoole_http_server的Task事件完成,接受通过业务投递的数据,分发到任务执行者上。为了统一定义了一个interface,每个任务执行者实现excute方法即可。TaskServiceModel根据不同task实例化并调用其excute

2. 投递任务则调用swoole_http_server的task方法,序列化传递任务参数(为了方便截图和Task事件处理放在一起)

好处

1.迁移成本

swoole+yaf方案与yaf+php-fpm相比,在项目代码中区别最大的就是参数的获取方式,也是唯一的改变。前者必须通过swoole_http_server的request属性获取。别的都同yaf项目开发,迁移成本低。

2.异步task处理

在车队项目中,有多个场景要异步处理。比如用户发送红包要推送全组成员,有的小组成员过多,若阻塞执行可能接口超时。还有通过swoole tasker还能达到一个本地削峰的作用,有一个场景峰值qps 5w+ 对应redis有大量写,除了加redis实例分担写,还将50个worker的写请求通过任务投递给tasker进程,然后20个tasker在本地串行消费。

3.稳定性

最初还是担心改造后不如yaf+php-fpm稳定,还特意准备一个代码分支用来回退yaf+php-fpm,防止技术尝鲜遇坑影响项目进度。 后来线上压测发现性能比yaf+php-fpm高20%,现在已在线上稳定服务半年,若遇到一些大流量一天可处理上亿请求。

遇到的坑

1.qps压不上去

刚开始尝试,qps一直压不上去。还不如yaf+php-fpm,后来发现这与swoole的请求分发的算法有关,调整后(dispatch_mode=3,主进程会根据Worker的忙闲状态选择投递,只会投递给处于闲置状态的Worker)性能提升80%。swoole内含大量参数设置,看实际情况来设置。

2.单例

swoole worker单例是进程级, yaf+fpm是请求级

3.业务逻辑为什么不基于事件

看看swoole作者怎么说: “Swoole不仅支持异步,还支持同步。什么情况下使用同步,什么情况下使用异步。这里说明一下。我们不赞成用异步回调的方式去做功能开发,传统的PHP同步方式实现功能和逻辑是最简单的,也是最佳的方案。像node.js这样到处callback,只是牺牲可维护性和开发效率。

但有些时候很适合用异步,比如FTP、聊天服务器,smtp,代理服务器等等此类以通信和读写磁盘为主,功能和业务逻辑其次的服务器程序”

4.瓶颈master进程

php-fpm环境下,worker是通过拉的方式获取请求。 swoole环境下是通过master将请求分发到worker。通过压测也可以看出Master进程是swoole的瓶颈,也就是worker进程再多也利用不了。要想再高性能可以尝试golang。

总结

yaf整合swoole,开发人员既可以像之前在yaf中快速开发,在迁移成本很低的情况又可以使用到一些swoole的异步处理,定时器等特性来提高服务性能,扩展服务功能。最近swoole作者又在4.0中实现了协程,后面我们会不会像golang一样处理并发问题,拭目以待!

参考

https://github.com/LinkedDestiny/swoole-yaf.git

http://www.laruence.com/manual/

https://wiki.swoole.com/

微信公众号:

溜溜技术

简介:

来自各大移动互联网服务端程序员的思想碰撞平台。技术、逻辑、思辩、进步、创新。有没有干货,拉出来溜溜!

投稿联系:

oscersong007

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180617G14PAH00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券