最近公司的项目越做越大,数据量越来越大,逐渐地要开始支持分布式的数据库,当然包括要缓存。经过了各种的讨论和认证,决定用redis服务器作为数据缓存的服务器,除了支持丰富的数据类型,string,list,hash,set ,sort set ,还有持久化的数据的功能。这一方面确实比memcache好很多。下面是我的整个测试过程(tp3.2以上)。
注意:首先要安装phpredis和配置好redis的主从复制,并且要启动各个redis的实例。
与tp自带的redis.class.php的缓存驱动不同,实现功能
1、可以实现主从分布,多个slave
2、master主要负责写,slave负责随机读
3、单例模式,一次实例化所有的redis,包括master,slave。不需要每操作一次redis,就连接redis一次,那样严重浪费资源。
4、自由拓展,可以根据自己的需要继续添加redis的API操作。
一、tp的redis配置
-
// REDIS配置
-
'DATA_CACHE_TYPE' =>'Redis',
-
'DATA_REDIS_HOST' =>'localhost,localhost',
-
'DATA_REDIS_PORT' =>'6379,6380',
-
'DATA_CACHE_TIME' =>30,
-
'DATA_CACHE_PREFIX' =>'redis_',
-
'DATA_PERSISTENT' =>true </span>
二、redis的缓存驱动
-
-
// +----------------------------------------------------------------------
-
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
-
// +----------------------------------------------------------------------
-
// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved.
-
// +----------------------------------------------------------------------
-
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
-
// +----------------------------------------------------------------------
-
// | Author: liu21st <[email protected]>
-
// +----------------------------------------------------------------------
-
namespace Think\ Cache\ Driver;
-
use Think\ Cache;
-
defined( 'THINK_PATH') or exit();
-
-
/**
-
* Redis缓存驱动
-
* 要求安装phpredis扩展:https://github.com/nicolasff/phpredis
-
* @category Think
-
* @package Cache
-
* @subpackage Driver
-
* @author huangzengbing
-
*/
-
class Redisrw extends Cache {
-
/**
-
*类对象实例数组
-
*共有静态变量
-
*@param mixed $_instance存放实例
-
*/
-
private static $_instance= array();
-
-
/**
-
*每次实例的句柄
-
*保护变量
-
*/
-
protected $handler;
-
-
/**
-
*redis的配置
-
*全局 静态变量
-
*静态的方法里调用静态变量和静态方法只能用self,不能出现$this
-
*/
-
static $option= array();
-
-
/**
-
*架构函数,必须设置为私有,防止外部new
-
*实例化redis驱动的实例,寄一个socket
-
*
-
*/
-
private function __construct($host,$port,$auth) {
-
if(! $this->handler) {
-
$this->handler= new \Redis;
-
}
-
$func = self::$option[ 'persistent'] ? 'pconnect' : 'connect';
-
if( self::$option[ 'timeout'] === false) {
-
$this->handler->$func($host,$port);
-
} else {
-
$this->handler->$func($host,$port, self::$option[ 'timeout']);
-
}
-
-
// 认证
-
if($auth){
-
$this->handler->auth($auth);
-
}
-
}
-
-
/**
-
*实例函数,单例入口
-
*共有,静态函数
-
*/
-
-
public static function getInstance($options=array()) {
-
// 判断是否存在redis扩展
-
if ( !extension_loaded( 'redis') ) {
-
E(L( '_NOT_SUPPERT_'). ':redis');
-
}
-
if( empty($options)) {
-
$options = array (
-
'host' => C( 'DATA_REDIS_HOST') ? C( 'DATA_REDIS_HOST') : '127.0.0.1',
-
'port' => C( 'DATA_REDIS_PORT') ? C( 'DATA_REDIS_PORT') : 6379,
-
'timeout' => C( 'DATA_CACHE_TIME') ? C( 'DATA_CACHE_TIME') : false,
-
'persistent' => C( 'DATA_PERSISTENT') ? C( 'DATA_PERSISTENT') : false,
-
'auth' => C( 'DATA_REDIS_AUTH') ? C( 'DATA_REDIS_AUTH') : false,
-
);
-
}
-
$options[ 'host'] = explode( ',', $options[ 'host']);
-
$options[ 'port'] = explode( ',', $options[ 'port']);
-
$options[ 'auth'] = explode( ',', $options[ 'auth']);
-
foreach ($options[ 'host'] as $key=>$value) {
-
if (! isset($options[ 'port'][$key])) {
-
$options[ 'port'][$key] = $options[ 'port'][ 0];
-
}
-
if (! isset($options[ 'auth'][$key])) {
-
$options[ 'auth'][$key] = $options[ 'auth'][ 0];
-
}
-
}
-
self::$option = $options;
-
self::$option[ 'expire'] = isset($options[ 'expire']) ? $options[ 'expire'] : C( 'DATA_EXPIRE');
-
self::$option[ 'prefix'] = isset($options[ 'prefix']) ? $options[ 'prefix'] : C( 'DATA_CACHE_PREFIX');
-
self::$option[ 'length'] = isset($options[ 'length']) ? $options[ 'length'] : 0;
-
// 一次性创建redis的在不同host的实例
-
foreach( self::$option[ 'host'] as $i=>$server) {
-
$host= self::$option[ 'host'][$i];
-
$port= self::$option[ 'port'][$i];
-
$auth= self::$option[ 'auth'][$i];
-
if(!( self::$_instance[$i] instanceof self)) {
-
self::$_instance[$i]= new self($host,intval($port),$auth);
-
}
-
}
-
-
// 默认返回第一个实例,即master
-
return self::$_instance[ 0];
-
}
-
-
/**
-
*判断是否master/slave,调用不同的master或者slave实例
-
*
-
*/
-
public function is_master($master=true) {
-
if($master) {
-
$i= 0;
-
} else {
-
$count=count( self::$option[ 'host']);
-
if($count== 1) {
-
$i= 0;
-
} else{
-
$i=rand( 1,$count - 1);
-
}
-
}
-
//返回每一个实例的句柄
-
return self::$_instance[$i]->handler;
-
}
-
-
/**
-
* 读取缓存,随机从slave服务器中读缓存
-
* @access public
-
* @param string $name 缓存变量名
-
* @return mixed
-
*/
-
public function get($name) {
-
$redis= $this->is_master( false);
-
N( 'cache_read', 1);
-
$value = $redis->get( self::$option[ 'prefix'].$name);
-
$jsonData = json_decode( $value, true );
-
//检测是否为JSON数据 true 返回JSON解析数组, false返回源数据
-
return ($jsonData === NULL) ? $value : $jsonData;
-
-
}
-
-
/**
-
* 写入缓存,写入master的redis服务器
-
* @access public
-
* @param string $name 缓存变量名
-
* @param mixed $value 存储数据
-
* @param integer $expire 有效时间(秒)
-
* @return boolean
-
*/
-
public function set($name, $value, $expire = null) {
-
$redis= $this->is_master( true);
-
N( 'cache_write', 1);
-
if(is_null($expire)) {
-
$expire = self::$option[ 'expire'];
-
}
-
$name = self::$option[ 'prefix'].$name;
-
//对数组/对象数据进行缓存处理,保证数据完整性
-
$value = (is_object($value) || is_array($value)) ? json_encode($value) : $value;
-
if(is_int($expire) && $expire > 0) {
-
$result = $redis->setex($name, $expire, $value);
-
} else{
-
$result = $redis->set($name, $value);
-
}
-
if($result && self::$option[ 'length']> 0) {
-
// 记录缓存队列
-
$this->queue($name);
-
}
-
return $result;
-
}
-
-
/**
-
* 删除缓存
-
* @access public
-
* @param string $name 缓存变量名
-
* @return boolean
-
*/
-
public function rm($name) {
-
$redis= $this->is_master( true);
-
return $redis->delete( self::$option[ 'prefix'].$name);
-
}
-
-
/**
-
* 清除缓存
-
* @access public
-
* @return boolean
-
*/
-
public function clear() {
-
$redis= $this->is_master( true);
-
return $redis->flushDB();
-
}
-
-
/**
-
*禁止外部克隆对象
-
*
-
*/
-
private function __clone() {
-
-
}
-
-
//可以根据需要,继续添加phpredis的驱动api.
-
-
/**
-
* 关闭长连接
-
* @access public
-
*/
-
public function __destruct() {
-
if ( self::$option[ 'persistent'] == 'pconnect') {
-
// 关闭master的长连接,不可以写,但slave任然可以读
-
$redis= $this->is_master( true);
-
$redis->close();
-
}
-
}
-
}
3、CONTROLLER中用法
-
$redis=\Think\Cache\Driver\Redisrw::getInstance();
-
$redis->set('address','beijing');
-
$result=$redis->get('address');
-
dump($result);
-