php 处理耗时任务
11 September 2018

这个背景是虚拟的,但是遇到的问题是一样的。
负责的是一个 app 的项目,该项目需要对用户的上传的 app 做一些修改操作,比如给 app 的每个页面里面再加一段自定义的代码,每个 app 平均有 500 个页面要处理,这个是个耗时任务,大概需要 3 分钟。如果直接用 nginx 跑 php-fpm,那么肯定会是 504 超时

思路是将用户上传的 app 任务丢到 rabbitmq 里面,将代码包放到七牛云,php 跑 worker 作为 rabbitmq 的消费者,方式如下

现在的操作就是前端 ajax 轮询,大概 3 分钟处理完任务后,前端就会显示操作成功之类的成功提示。这里遇到的问题是用户需要等待 3 分钟,这个项目上线了一段时间。

由于开的 worker 比较多,只要 3 分钟内,增加的任务次数不比 worker 多,就不会导致任务堆积。例如有 8 个 worker,那么 3 分钟只来了 8 个任务,那么是刚好可以处理完的,如果 3 分钟内来了 9 个任务,那么就会有一个任务不能及时处理,需要等到其中 1 个 worker 处理完任务了,再来处理第 9 个任务。

问题就是发生在这里,即使是多个 worker 跑队列,这 3 分钟的耗时还是需要 3 分钟,这是变不了的。一旦任务量上来的时候,这个系统就处理不了。

如果 worker 接到任务之后,再开启 10 个进程同时去处理这 500 个页面,那么需要的时间就会变成原来的 1/10 。但是我们不能在 worker 里面直接 fork 多个进程(因为 worker 连接着 rabbitmq,直接 fork worker 就相当于多了一个 rabbitmq 的 worker)。如果是 go 那么可以用 goroutinechannel 解决,这里是 php,由于线上的 swoole 版本比较低,swoole 也不考虑了。

解决的方法是在 localhost 里面多开一个 rabbitmq(这个 rabbitmq 不能放在远程,如果是远程,因为从七牛云里面下载出来的 app 存在了本地,每次去远程下载 app 也挺麻烦的)

-EOF-
水完