您的位置:首页 > 数据库 > Redis

Linux下Redis+crontab实现任务队列

2014-03-07 10:10 302 查看
前段时间由于一个控制方法要实现的逻辑任务太多了,无论怎么优化都还是有瓶颈。网上介绍可以使用任务队列的机制,把一些不是立即需要相应的逻辑处理放在队列中,让某个程序时时去执行。举个例子:用户上来我的网站注册,注册完后,我需要给用户的邮箱帐号推送一些邮件,这个推送邮件所发的时间可能远比注册保存用户资料所花的时间多些,也不是立即就需要响应到前端给客户知道。所以,是可以把推送邮件这一动作作为一个任务添加到队列中。

说明下我测试调试的环境是在Ubuntu12.04下的,安装redis和添加crontab命令是通过终端命令的,我测试的项目是基于yii框架,调用redis是通过框架提供的yiiredis插件,可能不太符合你的环境,但其中的思路或许还是可以借鉴的。

1、安装Redis

进入终端命令窗口(快捷键Ctrl+Alt+T)切换至/usr/local/src(命令:cd /usr/local/src)下,下载并安装redis:

$ wget http://redis.googlecode.com/files/redis-2.6.12.tar.gz $ tar xzf redis-2.6.12.tar.gz
$ cd redis-2.6.12
$ make
进入redis-2.6.12(命令:cd redis-2.6.12)目录,修改redis.conf:

daemonize yes
启动服务端:

$ src/redis-server redis.conf
进入命令行验证服务是否启动:

$ src/redis-cli
redis> set foo bar
OK
redis> get foo
"bar"


2、安装Yii的Redis插件

目前主要有两种Yii插件:

1> Rediscache:基于predis(Redis的纯PHP实现客户端),无需安装Redis for PHP扩展。

2> YiiRedis:基于phpredis客户端,需要安装Redis for PHP扩展。

这里采用Rediscache插件,避免线上安装Redis for PHP扩展。

从以下地址下载Rediscache插件:
http://www.yiiframework.com/extension/rediscache/files/redis.zip
将插件解压到helloyii/app/protected/extensions中:

插件文件部署后的位置应为:helloyii/app/protected/extensions/redis/CredisCache.php

配置Rediscache

return array(
'components' => array(
…
'cache'=>array(
'class'=>'ext.redis.CRedisCache', //对应protected/extensions/redis/CredisCache.php
'servers'=>array(
array(
'host'=>'127.0.0.1',
'port'=>6379,
),
),
),
),
…
);


3、测试redis使用

编写一个读写缓存的控制器IndexController进行测试。

class IndexController extends CController{
public function actionSetRedisValue() {
$key = $_POST['key'];
$value = $_POST['value'];
if ( !empty( $key ) && !empty( $value ) ) {
try {
$redis = Yii::app()->cache;
$data = ( array ) $redis->get( 'test' );
$data[$key] = $value;
$redis->set( 'test', $data );
die( json_encode( array( 'status' => 1, 'msg' => 'set ok!' ) ) );
} catch ( Exception $e ) {
die( json_encode( array( 'status' => 0, 'msg' => 'set faile!' ) ) );
}
} else {
die( json_encode( array( 'status' => 0, 'msg' => 'must input!' ) ) );
}
}
public function actionGetRedisValue() {
try {
$redis = Yii::app()->cache;
$data = ( array ) $redis->get( 'test' );
$log_file = Yii::app()->runtimePath . '\redis_log.txt';
if ( file_exists( $log_file ) ) {
$handle = fopen( $log_file, "a+" );
$log = "----" . date( 'Y-m-d H:i:s' ) . "-----" . "\n";
foreach ( $data as $key => $value ) {
$log .= '->' . $key . ' = ' . $value . "\n";
}
fwrite( $handle, $log );
fclose( $handle );
}
} catch ( Exception $e ) {
echo $e->getMessage();
}
}
}


视图文件index内容。

<?php Yii::app()->clientScript->registerCoreScript( 'jquery' ); ?>
<p>Redis</p>
<form id="redis_form" action="<?php echo $this->createUrl( '/cata/index/setRedisValue' ); ?>" method="post">
Key:<input id="key" type="text" value=""/>
Value:<input id="val" type="text" value=""/>
<input id="set" type="button" value="set"/>
<input id="get" type="button" value="get"/>
<span></span>
</form>
<script>
$(document).ready(function() {
$('#redis_form #set').on('click', function() {
var redisForm = $('#redis_form');
var action = redisForm.attr('action');
var key = redisForm.children('#key');
var value = redisForm.children('#val');
$.post(action, {key: key.val(), value: value.val()}, function(data) {
redisForm.find('span').html(data.msg);
setTimeout(function() {
redisForm.find('span').html('');
}, 3000);
}, 'json');
});

$('#redis_form #get').on('click', function() {
$.post('<?php echo $this->createUrl( '/cata/index/getRedisValue' ); ?>', {}, function(data) {
}, 'json');
});

});
</script>

现在访问:http://helloyii.com/app/index.php?r=cache/fetch&key=a&value=b

然后通过redis-cli命令行客户端查看下缓存的变化:

可以通过redis-cli客户端查看缓存:

$ src/redis-cli
redis> keys '*'


4、添加crontab命令,每10秒获取redis缓存数据进行处理

很多时候,我们计划任务需要精确到秒来执行,但linux最小只支持分钟,很多linux自带的版本都不直接支持以秒来执行,根据以下方法,可以很容易地以秒执行任务。

进入终端编辑crontab(命令:crontab -e

* * * * * /usr/bin/wget -q http://localhost/suixingv3/index.php/cata/index/getRedisValue 
* * * * * sleep 10; /usr/bin/wget -q http://localhost/suixingv3/index.php/cata/index/getRedisValue 
* * * * * sleep 20; /usr/bin/wget -q http://localhost/suixingv3/index.php/cata/index/getRedisValue 
* * * * * sleep 30; /usr/bin/wget -q http://localhost/suixingv3/index.php/cata/index/getRedisValue 
* * * * * sleep 40; /usr/bin/wget -q http://localhost/suixingv3/index.php/cata/index/getRedisValue 
* * * * * sleep 50; /usr/bin/wget -q http://localhost/suixingv3/index.php/cata/index/getRedisValue[/code] 
5、调试

当你通过redis往内存中设置多几个值之后,再获取的时候redis可能会报一下的这种错误:

Exception in thread "main" redis.clients.jedis.exceptions.JedisDataException: MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please
check Redis logs for details about the error.

产生时的条件:

数据持续写入,读取速度远低于写入速度,持续1H以上(中途开了一个较长时间的会,一直写入数据,没管),内存占用量为80%。

由于我目前并未对redis做详细深入理解,故根据网上资料说明:

stop-writes-on-bgsave-error yes

默认情况下,如果在RDB snapshots持久化过程中出现问题,设置该参数后,Redis是不允许用户

进行任何更新操作(set...)。避免人为强制停止redis 快照

解决:

进入redis/src目录下启动客户端:

$ ./redis-cli
输入:

config set stop-writes-on-bgsave-error no


6、参考资料
官方安装手册
http://redis.io/download
Yii的Redis插件1:rediscache
http://www.yiiframework.com/extension/rediscache/
Yii的Redis插件2:yiiredis
https://github.com/phpnode/YiiRedis
Yii CCache接口的API
http://www.yiichina.com/api/CCache#get-detail
Redis在YiiFramework中的使用
http://denghai260.blog.163.com/blog/static/726864092012323101628773/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: