注册
登录

您现在的位置是:首页 > 学无止境

yaf整合swoole开发web应用

木木彡82 2018-06-19 20:20:28 0人围观
yaf整合swoole开发web应用

转载自:https://mp.weixin.qq.com/s/MdzLjv1KxeqNOwwq6Ayg4w

背景

     公司的主要技术栈有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进程。一个更通俗的比喻,假设Server就是一个工厂,那Reactor就是销售,接受客户订单。而Worker就是工人,当销售接到订单后,Worker去工作生产出客户要的东西。而TaskWorker可以理解为行政人员,可以帮助Worker干些杂事,让Worker专心工作。那下面就是监听任务和投递任务了。

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/

文章评论

  • 登录后评论

点击排行