转载于:http://blog.hsatac.net/2012/01/php-resque-introduction/

Resque 是 Github 基於 Redis 开发的 background job 系统。相较其他肥大的 queue 系统, Resque 的设计真的非常单纯简洁,充分利用 Redis 的特性。更多介绍可以看原作者的 Blog

PHP-Resque 是把 Resque porting 到 PHP 的专案。使用和 原本 Resque 一样的概念和设计。甚至连 Redis 的 key 命名都一样,因此也可以使用 Ruby 版本的 resque-web 来监控 PHP-Resque 的运行状况。

设计

Resque 的设计有两个角色: Job 和 Worker。 每个 Job 都是定义成类别,新增 Job 的时候会将 Job 的类别和相关参数 json_encode 后储存到不同的 queue 裡面,而 Worker(s) 则会依序从 redis 读取 Job 出来执行。

执行的时候并不是这个 Worker 本身去执行,而是会 fork 一个 process 来执行。这样设计是為了避免时间一长, Worker 的记忆体管理不良导致卡死的状况。

读取 queue 时会依据你启动 worker 的时候给的 queue 顺序来读取,因此优先权较高的 queue 要设定在前面。 Redis 可以是单机或 RedisCluster。而许多不同伺服器上可以按需求部属执行不同 queue 的 worker。

Resque Job 执行失败并不会自动重试,而是把它丢到 fail 的 queue 裡面。如果你有重试的需求可能要自己处理。若是有特别重要的 Job 需要监控执行状态的,可以参考 README 中的 Tracking Job Statuses 一节。

以下先来介绍如何使用 PHP-Resque:

安装 PHP-Resque

安装非常容易,只要 git clone https://github.com/chrisboulton/php-resque.git 下来,放到你想要的地方,由於 Resque 没有 config 档的设计,设定都是写在环境变数中再执行就可以了。

环境变数

PHP-Resque 支援的环境变数有:

  • QUEUE – 这个是必要的,会决定 worker 要执行什麼任务,重要的在前,例如 QUEUE=notify,mail,log 。也可以设定為 QUEUE=* 表示执行所有任务。

  • APP_INCLUDE – 这也可以说是必要的,因為 Resque 的 Job 都是写成物件,那 worker 执行的时候当然要把物件的档案引入进来。可以设成 APP_INCLUDE=require.php 再在 require.php 中引入所有 Job 的 Class 档案即可。

  • COUNT – 设定 worker 数量,预设是1 COUNT=5

  • REDIS_BACKEND – 设定 Redis 的 ip, port。如果没设定,预设是连 localhost:6379

  • LOGGING, VERBOSE – 设定 log, VERBOSE=1 即可。

  • VVERBOSE – 比较详细的 log, VVERBOSE=1 debug 的时候可以开出来看。

  • INTERVAL – worker 检查 queue 的间隔,预设是五秒 INTERVAL=5

  • PIDFILE – 如果你是开单 worker,可以指定 PIDFILE 把 pid 写入,例如 PIDFILE=/var/run/resque.pid

有一个 Resque 支援,但 PHP-Resque 没有的参数叫 BACKGROUND 可以把 resque 丢到背景执行。不过这个其实不太重要,有需要的话自己加个 php resque.php & 就可以了。

所以,你的指令最后可能会变这样:

1
QUEUE=* APP_INCLUDE=require.php COUNT=5 VVERBOSE=1 php resque.php

如果觉得太长,可以写一支啟动 script 来辅助你,我有写一支可供参考:

#!/bin/bash
export APP_INCLUDE=resque/require.php
export QUEUE=*
export COUNT=1
export VVERBOSE=1 # for debugging
export REDIS_BACKEND=localhost:6379
. /etc/rc.d/init.d/functions start() {
/usr/bin/php ../lib/sdk/php-resque/resque.php
} stop() {
ps -ef | grep resque | grep -v grep | grep -v resque-web | awk '{print $2}' | xargs kill -15
}
kill() {
ps -ef | grep resque | grep -v grep | grep -v resque-web | awk '{print $2}' | xargs kill -9
}
case "$1" in
start)
number=$(ps aux | grep php-resque/resque.php | grep -v grep | wc -l)
if [ $number -gt 0 ]
then
echo "php-resque is running. ($number workers)"
echo "You may wanna stop them before you start."
else
start
fi
;; stop)
stop
;; kill)
kill
;; status)
number=$(ps aux | grep php-resque/resque.php | grep -v grep | wc -l)
if [ $number -gt 0 ]
then
echo "php-resque is running. ($number workers)"
else
echo "php-resque is not running."
fi
;; *)
echo -n "Usage: $0 {start|stop|status}"
esac

使用 PHP-Resque

把档案抓下来以后一定想先试验看看的,确定你的 redis-server 都有正常啟动后,在 demo 资料夹下面有几个档案可以先试验看看。

切到 demo 目录后,执行 VVERBOSE=1 QUEUE=* php resque.php 应该会看到 resque 已经开始执行了。

执行 php queue.php PHP_Jobphp queue.php Bad_PHP_Jobphp queue.php Long_PHP_Jobphp queue.php PHP_Error_Job 可以把工作丢进 queue 裡面,看看执行的结果。

后面带的名称其实就是 Job class 的名称,所以 PHP-Resque 在执行时也要把相关的 class 档案设定在 APP_INCLUDE 引入才行。

Job 的 class 很简单,大概长这样:

<?php
class My_Job
{
public function perform()
{
// Work work work
echo $this->args['name'];
}
}
?>

只要定义 perform 方法, Worker 就会把 Job new 出来以后执行 perform 。

当然,也可以定义 setUp()tearDown() 方法,前者会在 perform() 执行前执行,后者会在 perform() 执行后执行。

需要注意的是,Job exit 后都视為正常执行,如果要让他判断失败丢到 fail queue 中的话,需要 throw exception。

将 Job 塞入 queue 的方式是:

<?php
require_once 'lib/Resque.php'; Resque::setBackend('localhost:6379'); $args = array(
'name' => 'Chris'
);
Resque::enqueue('default', 'My_Job', $args);
?>

其中第一个参数 default 就是你的 queue 名称,例如你可以设定 notify, mail, image 之类,至於為什麼要这样设计,在后面的篇幅再叙述。

值得一提的是,在原 ruby 版 rescue 每个 Job 属於哪个 queue 是直接定义在 class 中的,PHP 版则是 enqueue 时才传入,不知道為什麼要这样设计,可能会导致一些意料之外的结果,需要注意。

PHP-Resque 的使用方法大致就是这样,接下来讲一些其他的小细节。

Hooks

PHP-Resque 可以定义 Event Hooks 让你能在相对应的事件发生时执行你想要的动作。支援的事件有很多,请各位自行参考原专案的 README。在专案目录下的 extra 目录下有 sample.plugin.php 可以看 Event hook 的范例写法。

有一点需要注意的是,很直觉我们会把这隻 sample.plugin.php 丢到 APP_INCLUDE 变数中,这样没错,但要注意跟 enqueue 有关的 event 并不是由 worker 来触发,因此你在新增 Job 的那段程式也需要引入 sample.plugin.php 才能触发到 AFTERENQUEUE

监控

resque-web

前面有提到可以直接使用 resque-web 来监控 PHP-Resque 的状态,相当建议使用,非常清楚易懂,要看 Redis 相关的数据也可以看,不用进 redis-cli 自己打指令。

安装方法:gem install resque

执行:resque-web -p 3000 即可运行在 3000 port。

首页有 live reload 按钮可以按, debug 时非常方便。

screenshot:

Supervisord

在专案的 extra 目录下另有 resque.monit 档案,这是供 Supervisord 使用的设定档。他会在 worker 吃掉 300MB 以上的记忆体,或者是跑了 10 次轮迴后砍掉重开。可以参考看看。

proctitle

如果你 ps | grep resque 只会看到 php resuqe.php 的讯息,还记得 Worker 会 fork 出一个 process 来执行 Job 吗?这样就有两倍的 processes 但是你完全分不出来哪个是哪个。原本 ruby 版本的设计是可以轻易看出 Worker fork 了哪个 process 而被 fork 出来的正在执行什麼工作。

Ruby 只要改 $0 就可以了, PHP 就没这麼简单了,要使用 setproctitle

但是这要安装 pecl 的 proctitle 模组才能使用。

安装方式:pecl install proctitle channel://pecl.php.net/proctitle-0.1.1

记得要去 php.ini 读进 .so 的 extension 。

完成后再执行 ps -e -o pid,command | grep [r]esque 时,就会从原本的

 php resque.php
php resque.php

变成好读易懂的:

 resque-1.0: Waiting for notify,mail,image,default
resque-1.0: Forked at -- ::
resque-1.0: Processing default since -- ::

佈署

之前提到可以除了预设的 default 以外,还可以设定不同的 queue,為什麼要这样做呢?除了执行优先权外,(捞 queue 时会按你给 worker 的设定,在前面 queue 的会先捞,就会先执行到) 还有多伺服器佈署的原因。

假如今天你有个 queue 专门要处理使用者图片的东西,当然一般图片会有自己的伺服器。於是在你的主 web 伺服器上你就可以执行 QUEUE=notify,mail 而在图片伺服器上就可以执行 QUEUE=images 的 worker。

另外就是由於 Worker 啟动时已经将 APP_INCLUDE 的档案都读入,持续执行。因此如果有修改引入的 Job 或 hook plugin 等档案的话,deploy 时要将 worker 停止,重新啟动才会读入新的 APP_INCLULDE 档案。

已知问题

首先,PHP-Resque 使用的是 Redisent 这套 Redis interface。但因為和另一套 php module phpredis 同样都定义了 RedisException 这个类别,所以会衝突,必须把 phpredis 移除才能使用。

再来,在部属时常常 REDIS_BACKEND 是设到别台机器的,而且一般我们都会开不只一个 worker ,这时候有一个已知 issue 就是有时 lpop 拉回来的 Job 错误,是一个阵列,导致喷出 json_decode 的错误,而且这个 Job 就不会执行,会 missing 。 (see #32)

目前还不清楚确实问题所在,不过有一个 workaround 的解法是,不要用 COUNT=5 去开,而是设 COUNT=1 然后执行 5 次,就不会有这个问题產生。

结语

Resque 真的是一个很棒很轻巧的设计,感谢有人把它 porting 到 PHP 。希望越来越多人来使用,一起来发展维护 PHP-Resque。

PHP-Resque 简介的更多相关文章

  1. Redis数据类型简介(十分钟快速学习Redis)

    如何在ubuntu18.04上安装和保护redis 如何连接到Redis数据库 如何管理Redis数据库和Keys 如何在Redis中管理副本和客户端 如何在Redis中管理字符串 如何在Redis中 ...

  2. ASP.NET Core 1.1 简介

    ASP.NET Core 1.1 于2016年11月16日发布.这个版本包括许多伟大的新功能以及许多错误修复和一般的增强.这个版本包含了多个新的中间件组件.针对Windows的WebListener服 ...

  3. MVVM模式和在WPF中的实现(一)MVVM模式简介

    MVVM模式解析和在WPF中的实现(一) MVVM模式简介 系列目录: MVVM模式解析和在WPF中的实现(一)MVVM模式简介 MVVM模式解析和在WPF中的实现(二)数据绑定 MVVM模式解析和在 ...

  4. Cassandra简介

    在前面的一篇文章<图形数据库Neo4J简介>中,我们介绍了一种非常流行的图形数据库Neo4J的使用方法.而在本文中,我们将对另外一种类型的NoSQL数据库——Cassandra进行简单地介 ...

  5. REST简介

    一说到REST,我想大家的第一反应就是“啊,就是那种前后台通信方式.”但是在要求详细讲述它所提出的各个约束,以及如何开始搭建REST服务时,却很少有人能够清晰地说出它到底是什么,需要遵守什么样的准则. ...

  6. Microservice架构模式简介

    在2014年,Sam Newman,Martin Fowler在ThoughtWorks的一位同事,出版了一本新书<Building Microservices>.该书描述了如何按照Mic ...

  7. const,static,extern 简介

    const,static,extern 简介 一.const与宏的区别: const简介:之前常用的字符串常量,一般是抽成宏,但是苹果不推荐我们抽成宏,推荐我们使用const常量. 执行时刻:宏是预编 ...

  8. HTTPS简介

    一.简单总结 1.HTTPS概念总结 HTTPS 就是对HTTP进行了TLS或SSL加密. 应用层的HTTP协议通过传输层的TCP协议来传输,HTTPS 在 HTTP和 TCP中间加了一层TLS/SS ...

  9. 【Machine Learning】机器学习及其基础概念简介

    机器学习及其基础概念简介 作者:白宁超 2016年12月23日21:24:51 摘要:随着机器学习和深度学习的热潮,各种图书层出不穷.然而多数是基础理论知识介绍,缺乏实现的深入理解.本系列文章是作者结 ...

  10. Cesium简介以及离线部署运行

    Cesium简介 cesium是国外一个基于JavaScript编写的使用WebGL的地图引擎,一款开源3DGIS的js库.cesium支持3D,2D,2.5D形式的地图展示,可以自行绘制图形,高亮区 ...

随机推荐

  1. Unity ScriptObject创建Asset文件

    创建ScriptObject可以创建带序列化的资源,只保存数据不用绑定在游戏对象上.创建出来的本子资源可以通过资源加载到游戏里使用.这里介绍一下使用Resources加载. 创建好的asset文件也可 ...

  2. Java容器-引用分类与部分Map用法

    目录 1.引用分类 2.了解WeakHashMap.IdentityHashMap.EnumMap 3.同步控制与只读设置 代码实现 1.引用分类(面试) 强引用(StrongReference):引 ...

  3. Java容器-引用数据类型排序+TreeSet、TreeMap底层实现

    目录 1.冒泡排序的实现 2.比较接口(普通数据类型.引用数据类型) 普通数据类型:冒泡排序 引用数据类型:包装类(Integer.String.Character.Date) 自定义类型:实体类:i ...

  4. Windows UWP开发系列 – 控件默认样式

    今天用一个Pivot控件的时候,想修改一下它的Header样式,却发现用Blend和VS无法导出它的默认样式了,导致无法下手,不知道是不是Blend的bug. 在网上搜了一下,在MSDN上还是找到了它 ...

  5. 【redis】redis五大类 用法 【转载:https://www.cnblogs.com/yanan7890/p/6617305.html】

    转载地址:https://www.cnblogs.com/yanan7890/p/6617305.html

  6. .NET:CLR via C# The CLR’s Execution Model

    The CLR’s Execution Model The core features of the CLR memory management. assembly loading. security ...

  7. Eclipse中设置背景颜色与字体大小和xml文件中字体大小调整

    Eclipse中代码编辑背景颜色修改: 代码编辑界面默认颜色为白色.对于长期使用电脑编程的人来说,白色很刺激我们的眼睛,所以改变workspace的背景色,可以使眼睛舒服一些.设置方法如下: 1.打开 ...

  8. http://blog.csdn.net/steveguoshao/article/details/38414145

    http://blog.csdn.net/steveguoshao/article/details/38414145

  9. 引导工具GRUB详解

    导读 引导程序是驻留在硬盘第一个扇区(MPR.主引导记录)的程序.GRUB是一个功能强大的多系统引导程序,专门处理Linux与其它操作系统共存的问题.下面就由我介绍一下grub.conf文件里的具体内 ...

  10. UIWebView页面的控制(二)

    1.UIWebView的内容控制的属性/方法列表 loading属性               确认当前页面是否在读入中 canGoForward属性   确认goForward  方法是否可运行, ...