38

yaf 整合 Swoole 开发 Web 应用

 5 years ago
source link: https://mp.weixin.qq.com/s/MdzLjv1KxeqNOwwq6Ayg4w?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

背景

公司的主要技术栈有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来分发路由。下面展示部分代码

Yj2AVfY.jpg!web

2. 异步任务

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

yamu6ny.jpg!web

相比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事件处理放在一起)

NfMbuaJ.jpg!web

好处

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/

AjQBVvu.gif

QbE7riy.jpg!web

微信公众号

溜溜技术

简介: 

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

投稿联系

oscersong007

长按二维码, 发现惊喜!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK