Yii框架中内置好几个缓存类,其中有memcache的类,但是没有redis缓存类,由于项目中需要做主从架构,所以扩展了一下:
/**
* FileName:RedisCluster
* 配置说明
* 配置为1主多从 或者 1个独立的服务器
* 写往主的里面写
* 读是从从的里面读
* 'class'=>'RedisCache',
* 'servers'=>array(
* array(
* 'host'=>'IP1',
* 'port'=>'6380',
* 'master'=>true //主机
* ),
* array(
* 'host'=>'IP2',
* 'port'=>'6381'
* )
*
* 单独
* 'class'=>'RedisCache',
* 'servers'=>array(
* array(
* 'host'=>'IP1',
* 'port'=>'6380',
* ), * @author zhonghailin
* @version v1.0
* @since v1.0
* @Date 2015-3-10 下午4:57:02
*/
class ERedisCache extends CCache{ // 是否使用 M/S 的读写集群方案
private $_isUseCluster = false; // Slave 句柄标记
private $_sn = 0; // 服务器连接句柄
private $_linkHandle = array(
'master'=>null,// 只支持一台 Master
'slave'=>array(),// 可以有多台 Slave
);
//配置文件
private $_servers=array();
/**
* 构造函数
*
* @param boolean $isUseCluster 是否采用 M/S 方案
*/
/*
* 初始化
*/
public function init()
{
$this->keyPrefix = "";
parent::init();
if(is_array($this->_servers)){
foreach($this->_servers as $servers){
if($servers->master){
$this->_isUseCluster = true;//如果设置了主服务器那么就是1主多从
$this->connect($servers,true);
}else{
$this->connect($servers);
}
}
}
} /**
* @return array list of memcache server configurations. Each element is a {@link CMemCacheServerConfiguration}.
*/
public function getServers()
{
return $this->_servers;
} /**
* @param array $config list of memcache server configurations. Each element must be an array
* with the following keys: host, port, persistent, weight, timeout, retryInterval, status.
* @see http://www.php.net/manual/en/function.Memcache-addServer.php
*/
public function setServers($config)
{
foreach($config as $c)
$this->_servers[]=new CRedisServerConfiguration($c);
}
/**
* 连接服务器,注意:这里使用长连接,提高效率,但不会自动关闭
*
* @param array $config Redis服务器配置
* @param boolean $isMaster 当前添加的服务器是否为 Master 服务器
* @return boolean
*/
public function connect($config, $isMaster=false){
// default port
if(!isset($config->port)){
$config->port = 6379;
}
// 设置 Master 连接
if($isMaster){
$this->_linkHandle['master'] = new Redis();
$ret = $this->_linkHandle['master']->pconnect($config->host,$config->port);
}else{
// 多个 Slave 连接
$this->_linkHandle['slave'][$this->_sn] = new Redis();
$ret = $this->_linkHandle['slave'][$this->_sn]->pconnect($config->host,$config->port);
++$this->_sn;
}
return $ret;
} /**
* 关闭连接
*
* @param int $flag 关闭选择 0:关闭 Master 1:关闭 Slave 2:关闭所有
* @return boolean
*/
public function close($flag=2){
switch($flag){
// 关闭 Master
case 0:
$this->getRedis()->close();
break;
// 关闭 Slave
case 1:
for($i=0; $i<$this->_sn; ++$i){
$this->_linkHandle['slave'][$i]->close();
}
break;
// 关闭所有
case 2:
if(!empty( $this->_linkHandle['master'])){
$this->_linkHandle['master']->close();
}
for($i=0; $i<$this->_sn; ++$i){
$this->_linkHandle['slave'][$i]->close();
}
break;
}
return true;
} /**
* 得到 Redis 原始对象可以有更多的操作
*
* @param boolean $isMaster 返回服务器的类型 true:返回Master false:返回Slave
* @param boolean $slaveOne 返回的Slave选择 true:负载均衡随机返回一个Slave选择 false:返回所有的Slave选择
* @return redis object
*/
public function getRedis($isMaster=true,$slaveOne=true){
// 只返回 Master
if($isMaster){
return $this->_linkHandle['master'];
}else{
return $slaveOne ? $this->_getSlaveRedis() : $this->_linkHandle['slave'];
}
} /**
* 写缓存
*
* @param string $key 组存KEY
* @param string $value 缓存值
* @param int $expire 过期时间, 0:表示无过期时间
*/
public function setValue($key, $value, $expire=0){
// 永不超时
if($expire == 0){
if($this->_isUseCluster){
$ret = $this->getRedis()->set($key, $value);
}else{
$ret = $this->getRedis(false)->set($key, $value);
}
}else{
if($this->_isUseCluster){
$ret = $this->getRedis()->setex($key, $expire, $value);
}else{
$ret = $this->getRedis(false)->setex($key, $expire, $value);
}
}
return $ret;
} /**
* 读缓存
*
* @param string $key 缓存KEY,支持一次取多个 $key = array('key1','key2')
* @return string || boolean 失败返回 false, 成功返回字符串
*/
public function getValue($key){
// 是否一次取多个值
$func = is_array($key) ? 'mGet' : 'get';
// 使用了 M/S
return $this->_getSlaveRedis()->{$func}($key);
} /**
* 条件形式设置缓存,如果 key 不存时就设置,存在时设置失败
*
* @param string $key 缓存KEY
* @param string $value 缓存值
* @return boolean
*/
public function setnx($key, $value){
if($this->_isUseCluster){
return $this->getRedis()->setnx($key, $value);
}else{
return $this->getRedis(false)->setnx($key, $value);
} } /**
* 删除缓存
*
* @param string || array $key 缓存KEY,支持单个健:"key1" 或多个健:array('key1','key2')
* @return int 删除的健的数量
*/
public function remove($key){
if($this->_isUseCluster){
return $this->getRedis()->delete($key);
}else{
return $this->getRedis(false)->delete($key);
}
} /* (non-PHPdoc)
* @see BaseCache::delete()
*/
public function deleteValue($key){
if($this->_isUseCluster){
return $this->getRedis()->delete($key);
}else{
return $this->getRedis(false)->delete($key);
}
}
/**
* 值加加操作,类似 ++$i ,如果 key 不存在时自动设置为 0 后进行加加操作
*
* @param string $key 缓存KEY
* @param int $default 操作时的默认值
* @return int 操作后的值
*/
public function incr($key,$default=1){
if($default == 1){
return $this->getRedis()->incr($key);
}else{
return $this->getRedis()->incrBy($key, $default);
}
} /**
* 值减减操作,类似 --$i ,如果 key 不存在时自动设置为 0 后进行减减操作
*
* @param string $key 缓存KEY
* @param int $default 操作时的默认值
* @return int 操作后的值
*/
public function decr($key,$default=1){
if($default == 1){
return $this->getRedis()->decr($key);
}else{
return $this->getRedis()->decrBy($key, $default);
}
} /**
* 添空当前数据库
*
* @return boolean
*/
public function clear(){
if(!empty( $this->_linkHandle['master'])){
$this->_linkHandle['master']->flushDB();
}
for($i=0; $i<$this->_sn; ++$i){
$this->_linkHandle['slave'][$i]->flushDB();
}
return true;
} /* =================== 以下私有方法 =================== */ /**
* 随机 HASH 得到 Redis Slave 服务器句柄
*
* @return redis object
*/
private function _getSlaveRedis(){
// 就一台 Slave 机直接返回
if($this->_sn <= 1){
return $this->_linkHandle['slave'][0];
}
// 随机 Hash 得到 Slave 的句柄
$hash = $this->_hashId(mt_rand(), $this->_sn);
return $this->_linkHandle['slave'][$hash];
} /**
* 根据ID得到 hash 后 0~m-1 之间的值
*
* @param string $id
* @param int $m
* @return int
*/
private function _hashId($id,$m=10)
{
//把字符串K转换为 0~m-1 之间的一个值作为对应记录的散列地址
$k = md5($id);
$l = strlen($k);
$b = bin2hex($k);
$h = 0;
for($i=0;$i<$l;$i++)
{
//相加模式HASH
$h += substr($b,$i*2,2);
}
$hash = ($h*1)%$m;
return $hash;
} }// End Class class CRedisServerConfiguration extends CComponent
{
/**
* @var string memcache server hostname or IP address
*/
public $host;
/**
* @var integer memcache server port
*/
public $port=11211; public $master = false;
/**
* Constructor.
* @param array $config list of memcache server configurations.
* @throws CException if the configuration is not an array
*/
public function __construct($config)
{
if(is_array($config))
{
foreach($config as $key=>$value)
$this->$key=$value;
if($this->host===null)
throw new CException(Yii::t('yii','CMemCache server configuration must have "host" value.'));
}
else
throw new CException(Yii::t('yii','CMemCache server configuration must be an array.'));
}
}