共计 10754 个字符,预计需要花费 27 分钟才能阅读完成。
装置: composer require predis/predis 即可
predis 是 PHP 连贯 Redis 的操作库,因为它齐全应用 php 编写,大量应用命名空间以及闭包等性能,只反对 php5.3 以上版本,故实测性能个别,每秒 25000 次读写。
将 session 数据寄存到 redis 也很简略:
session.save_handler = redis
session.save_path =“tcp://127.0.0.1:6379″
// 应用 autoload 加载相干库, 这边重点就是为了 require $file;
spl_autoload_register(function($class) {
$file = __DIR__.'/lib/Predis/'.$class.'.php';
if (file_exists($file)) {
require $file;
return true;
}
});
// 配置连贯的 IP、端口、以及相应的数据库
$server = array(
'host' => '127.0.0.1',
'port' => 6379,
'database' => 15
);
$redis = new Client($server);
// 一般 set/get 操作
$redis->set(‘library’, ‘predis’);
$retval = $redis->get(‘library’);
echo $retval; // 显示 ‘predis’
//setex set 一个存储时效
$redis->setex(‘str’, 10, ‘bar’); // 示意存储有效期为 10 秒
//setnx/msetnx 相当于 add 操作, 不会笼罩已有值
$redis->setnx(‘foo’,12); //true
$redis->setnx(‘foo’,34); //false
//getset 操作,set 的变种, 后果返回替换前的值
$redis->getset(‘foo’,56);// 返回 34
// incrby/incr/decrby/decr 对值的递增和递加
$redis->incr(‘foo’); //foo 为 57
$redis->incrby(‘foo’,2); //foo 为 59
//exists 检测是否存在某值
$redis->exists(‘foo’);//true
//del 删除
$redis->del(‘foo’);//true
//type 类型检测, 字符串返回 string, 列表返回 list,set 表返回 set/zset,hash 表返回 hash
$redis->type(‘foo’);// 不存在, 返回 none
$redis->set(‘str’,’test’);
$redis->type(‘str’); // 字符串,返回 string
//append 连贯到已存在字符串
$redis->append(‘str’,’_123′); // 返回累加后的字符串长度 8, 此进 str 为 ‘test_123’
//setrange 局部替换操作
$redis->setrange(‘str’,0,’abc’); // 返回 3, 参数 2 为 0 时等同于 set 操作
$redis->setrange(‘str’,2,’cd’);// 返回 4, 示意从第 2 个字符后替换, 这时 ’str’ 为 ’abcd’
//substr 局部获取操作
$redis->substr(‘str’,0,2);// 示意从第 0 个起,取到第 2 个字符,共 3 个,返回 ’abc’
//strlen 获取字符串长度
$redis->strlen(‘str’); // 返回 4
//setbit/getbit 位存储和获取
$redis->setbit(‘binary’,31,1); // 示意在第 31 位存入 1, 这边可能会有大小端问题? 不过没关系,getbit 应该不会有问题
$redis->getbit(‘binary’,31); // 返回 1
//keys 含糊查找性能, 反对 * 号以及? 号(匹配一个字符)
$redis->set(‘foo1’,123);
$redis->set(‘foo2’,456);
$redis->keys(‘foo*’); // 返回 foo1 和 foo2 的 array
$redis->keys(‘f?o?’); // 同上
//randomkey 随机返回一个 key
$redis->randomkey(); // 可能是返回 ‘foo1’ 或者是 ’foo2’ 及其它任何一存在 redis 的 key
//rename/renamenx 对 key 进行改名, 所不同的是 renamenx 不容许改成已存在的 key
$redis->rename(‘str’,’str2′); // 把原先命名为 ’str’ 的 key 改成了 ’str2′
//expire 设置 key-value 的时效性,ttl 获取残余有效期,persist 从新设置为永恒存储
$redis->expire(‘foo’, 1); // 设置有效期为 1 秒
$redis->ttl(‘foo’); // 返回有效期值 1s
$redis->expire(‘foo’); // 勾销 expire 行为
//dbsize 返回 redis 以后数据库的记录总数
$redis->dbsize();
/*
队列操作
*/
//rpush/rpushx 有序列表操作, 从队列后插入元素
//lpush/lpushx 和 rpush/rpushx 的区别是插入到队列的头部, 同上,’x’ 含意是只对已存在的 key 进行操作
$redis->rpush(‘fooList’, ‘bar1’); // 返回一个列表的长度 1
$redis->lpush(‘fooList’, ‘bar0’); // 返回一个列表的长度 2
$redis->rpushx(‘fooList’, ‘bar2’); // 返回 3,rpushx 只对已存在的队列做增加, 否则返回 0
//llen 返回以后列表长度
$redis->llen(‘fooList’);//3
//lrange 返回队列中一个区间的元素
$redis->lrange(‘fooList’,0,1); // 返回数组蕴含第 0 个至第 1 个共 2 个元素
$redis->lrange(‘fooList’,0,-1);// 返回第 0 个至倒数第一个, 相当于返回所有元素, 留神 redis 中很多时候会用到正数, 下同
//lindex 返回指定程序地位的 list 元素
$redis->lindex(‘fooList’,1); // 返回 ’bar1′
//lset 批改队列中指定地位的 value
$redis->lset(‘fooList’,1,’123′);// 批改地位 1 的元素, 返回 true
//lrem 删除队列中左起指定数量的字符
$redis->lrem(‘fooList’,1,’_’); // 删除队列中左起(右起应用 -1)1 个字符 ’_'(若有)
//lpop/rpop 相似栈构造地弹出 (并删除) 最左或最右的一个元素
$redis->lpop(‘fooList’); //’bar0′
$redis->rpop(‘fooList’); //’bar2′
//ltrim 队列批改,保留右边起若干元素,其余删除
$redis->ltrim(‘fooList’, 0,1); // 保留右边起第 0 个至第 1 个元素
//rpoplpush 从一个队列中 pop 出元素并 push 到另一个队列
$redis->rpush(‘list1′,’ab0’);
$redis->rpush(‘list1′,’ab1’);
$redis->rpush(‘list2′,’ab2’);
$redis->rpush(‘list2′,’ab3’);
$redis->rpoplpush(‘list1′,’list2’);// 后果 list1 =>array(‘ab0’),list2 =>array(‘ab1′,’ab2′,’ab3’)
$redis->rpoplpush(‘list2′,’list2’);// 也实用于同一个队列, 把最初一个元素移到头部 list2 =>array(‘ab3′,’ab1′,’ab2’)
//linsert 在队列的两头指定元素前或后插入元素
$redis->linsert(‘list2’, ‘before’,’ab1′,’123′); // 示意在元素 ’ab1’ 之前插入 ’123′
$redis->linsert(‘list2’, ‘after’,’ab1′,’456′); // 示意在元素 ’ab1’ 之后插入 ’456′
//blpop/brpop 阻塞并期待一个列队不为空时,再 pop 出最左或最右的一个元素(这个性能在 php 以外能够说十分好用)
//brpoplpush 同样是阻塞并期待操作,后果同 rpoplpush 一样
$redis->blpop(‘list3’,10); // 如果 list3 为空则始终期待, 直到不为空时将第一元素弹出,10 秒后超时
/**
set 表操作
*/
//sadd 减少元素, 返回 true, 反复返回 false
$redis->sadd(‘set1′,’ab’);
$redis->sadd(‘set1′,’cd’);
$redis->sadd(‘set1′,’ef’);
//srem 移除指定元素
$redis->srem(‘set1′,’cd’); // 删除 ’cd’ 元素
//spop 弹出首元素
$redis->spop(‘set1’);
//smove 挪动以后 set 表的指定元素到另一个 set 表
$redis->sadd(‘set2′,’123’);
$redis->smove(‘set1′,’set2′,’ab’);// 挪动 ’set1’ 中的 ’ab’ 到 ’set2′, 返回 true or false
//scard 返回以后 set 表元素个数
$redis->scard(‘set2’);//2
//sismember 判断元素是否属于以后表
$redis->sismember(‘set2′,’123’); //true or false
//smembers 返回以后表的所有元素
$redis->smembers(‘set2’); //array(‘123′,’ab’);
//sinter/sunion/sdiff 返回两个表中元素的交加 / 并集 / 补集
$redis->sadd(‘set1′,’ab’);
$redis->sinter(‘set2′,’set1’); // 返回 array(‘ab’)
//sinterstore/sunionstore/sdiffstore 将两个表交加 / 并集 / 补集元素 copy 到第三个表中
$redis->set(‘foo’,0);
$redis->sinterstore(‘foo’,’set1′); // 这边等同于将 ’set1’ 的内容 copy 到 ’foo’ 中,并将 ’foo’ 转为 set 表
$redis->sinterstore(‘foo’,array(‘set1′,’set2’)); // 将 ’set1’ 和 ’set2’ 中雷同的元素 copy 到 ’foo’ 表中, 笼罩 ’foo’ 原有内容
//srandmember 返回表中一个随机元素
$redis->srandmember(‘set1’);
/**
有序 set 表操作
*/
//sadd 减少元素, 并设置序号, 返回 true, 反复返回 false
$redis->zadd(‘zset1′,1,’ab’);
$redis->zadd(‘zset1′,2,’cd’);
$redis->zadd(‘zset1′,3,’ef’);
//zincrby 对指定元素索引值的增减, 扭转元素排列秩序
$redis->zincrby(‘zset1′,10,’ab’);// 返回 11
//zrem 移除指定元素
$redis->zrem(‘zset1′,’ef’); //true or false
//zrange 按地位秩序返回表中指定区间的元素
$redis->zrange(‘zset1’,0,1); // 返回地位 0 和 1 之间(两个) 的元素
$redis->zrange(‘zset1’,0,-1);// 返回地位 0 和倒数第一个元素之间的元素(相当于所有元素)
//zrevrange 同上, 返回表中指定区间的元素, 按秩序倒排
$redis->zrevrange(‘zset1’,0,-1); // 元素程序和 zrange 相同
//zrangebyscore/zrevrangebyscore 按程序 / 降序返回表中指定索引区间的元素
$redis->zadd(‘zset1′,3,’ef’);
$redis->zadd(‘zset1′,5,’gh’);
$redis->zrangebyscore(‘zset1’,2,9); // 返回索引值 2 - 9 之间的元素 array(‘ef’,’gh’)
// 参数模式
$redis->zrangebyscore(‘zset1′,2,9,’withscores’); // 返回索引值 2 - 9 之间的元素并蕴含索引值 array(array(‘ef’,3),array(‘gh’,5))
$redis->zrangebyscore(‘zset1’,2,9,array(‘withscores’ =>true,’limit’=>array(1, 2))); // 返回索引值 2 - 9 之间的元素,’withscores’ =>true 示意蕴含索引值; ‘limit’=>array(1, 2), 示意最多返回 2 条, 后果为 array(array(‘ef’,3),array(‘gh’,5))
//zunionstore/zinterstore 将多个表的并集 / 交加存入另一个表中
$redis->zunionstore(‘zset3’,array(‘zset1′,’zset2′,’zset0′)); // 将 ’zset1′,’zset2′,’zset0’ 的并集存入 ’zset3’
// 其它参数
$redis->zunionstore(‘zset3’,array(‘zset1′,’zset2’),array(‘weights’ => array(5,0)));//weights 参数示意权重,其中示意并集后值大于 5 的元素排在前,大于 0 的排在后
$redis->zunionstore(‘zset3’,array(‘zset1′,’zset2’),array(‘aggregate’ => ‘max’));//’aggregate’ => ‘max’ 或 ’min’ 示意并集后雷同的元素是取大值或是取小值
//zcount 统计一个索引区间的元素个数
$redis->zcount(‘zset1’,3,5);//2
$redis->zcount(‘zset1′,'(3’,5)); //'(3’ 示意索引值在 3 - 5 之间但不含 3, 同理也能够应用 '(5’ 示意下限为 5 但不含 5
//zcard 统计元素个数
$redis->zcard(‘zset1’);//4
//zscore 查问元素的索引
$redis->zscore(‘zset1′,’ef’);//3
//zremrangebyscore 删除一个索引区间的元素
$redis->zremrangebyscore(‘zset1’,0,2); // 删除索引在 0 - 2 之间的元素(‘ab’,’cd’), 返回删除元素个数 2
//zrank/zrevrank 返回元素所在表程序 / 降序的地位(不是索引)
$redis->zrank(‘zset1′,’ef’);// 返回 0, 因为它是第一个元素;zrevrank 则返回 1(最初一个)
//zremrangebyrank 删除表中指定地位区间的元素
$redis->zremrangebyrank(‘zset1’,0,10); // 删除地位为 0 -10 的元素, 返回删除的元素个数 2
/**
hash 表操作
*/
//hset/hget 存取 hash 表的数据
$redis->hset(‘hash1′,’key1′,’v1′); // 将 key 为 ’key1’ value 为 ’v1’ 的元素存入 hash1 表
$redis->hset(‘hash1′,’key2′,’v2’);
$redis->hget(‘hash1′,’key1’); // 取出表 ’hash1’ 中的 key ‘key1’ 的值, 返回 ’v1’
//hexists 返回 hash 表中的指定 key 是否存在
$redis->hexists (‘hash1′,’key1’); //true or false
//hdel 删除 hash 表中指定 key 的元素
$redis->hdel(‘hash1′,’key2’); //true or false
//hlen 返回 hash 表元素个数
$redis->hlen(‘hash1’); //1
//hsetnx 减少一个元素, 但不能反复
$redis->hsetnx(‘hash1′,’key1′,’v2’); //false
$redis->hsetnx(‘hash1′,’key2′,’v2’); //true
//hmset/hmget 存取多个元素到 hash 表
$redis->hmset(‘hash1’,array(‘key3’=>’v3′,’key4’=>’v4’));
$redis->hmget(‘hash1’,array(‘key3′,’key4’)); // 返回相应的值 array(‘v3′,’v4’)
//hincrby 对指定 key 进行累加
$redis->hincrby(‘hash1′,’key5’,3); // 返回 3
$redis->hincrby(‘hash1′,’key5’,10); // 返回 13
//hkeys 返回 hash 表中的所有 key
$redis->hkeys(‘hash1’); // 返回 array(‘key1′,’key2′,’key3′,’key4′,’key5’)
//hvals 返回 hash 表中的所有 value
$redis->hvals(‘hash1’); // 返回 array(‘v1′,’v2′,’v3′,’v4’,13)
//hgetall 返回整个 hash 表元素
$redis->hgetall(‘hash1’); // 返回 array(‘key1’=>’v1′,’key2’=>’v2′,’key3’=>’v3′,’key4’=>’v4’,’key5’=>13)
/**
排序操作
*/
//sort 排序
$redis->rpush(‘tab’,3);
$redis->rpush(‘tab’,2);
$redis->rpush(‘tab’,17);
$redis->sort(‘tab’); // 返回 array(2,3,17)
// 应用参数, 可组合应用 array(‘sort’ => ‘desc’,’limit’ => array(1, 2))
$redis->sort(‘tab’,array(‘sort’ => ‘desc’)); // 降序排列, 返回 array(17,3,2)
$redis->sort(‘tab’,array(‘limit’ => array(1, 2))); // 返回程序地位中 1 的元素 2 个(这里的 2 是指个数, 而不是地位), 返回 array(3,17)
$redis->sort(‘tab’,array(‘limit’ => array(‘alpha’ => true))); // 按首字符排序返回 array(17,2,3), 因为 17 的首字符是 ’1’ 所以排首地位
$redis->sort(‘tab’,array(‘limit’ => array(‘store’ => ‘ordered’))); // 示意永久性排序, 返回元素个数
$redis->sort(‘tab’,array(‘limit’ => array(‘get’ => ‘pre_‘))); // 应用了通配符 ’‘ 过滤元素, 示意只返回以 ’pre_’ 结尾的元素
/**
redis 治理操作
*/
//select 指定要操作的数据库
$redis->select(‘mydb’); // 指定为 mydb, 不存在则创立
//flushdb 清空以后库
$redis->flushdb();
//move 挪动当库的元素到其它库
$redis->set(‘foo’, ‘bar’);
$redis->move(‘foo’, ‘mydb2’); // 若 ’mydb2’ 库存在
//info 显示服务当状态信息
$redis->info();
//slaveof 配置从服务器
$redis->slaveof(‘127.0.0.1’,80); // 配置 127.0.0.1 端口 80 的服务器为从服务器
$redis->slaveof(); // 革除从服务器
// 同步保留服务器数据到磁盘
$redis->save();
// 异步保留服务器数据到磁盘
$redis->bgsave();
//??
$redis->bgrewriteaof();
// 返回最初更新磁盘的工夫
$redis->lastsave();
//set/get 多个 key-value
$mkv = array(
'usr:0001' => 'First user',
'usr:0002' => 'Second user',
'usr:0003' => 'Third user'
);
$redis->mset($mkv); // 存储多个 key 对应的 value
$retval = $redis->mget(array_keys($mkv)); // 获取多个 key 对应的 value
print_r($retval);
// 批量操作
$replies = $redis->pipeline(function($pipe) {
$pipe->ping();
$pipe->flushdb();
$pipe->incrby('counter', 10); // 增量操作
$pipe->incrby('counter', 30);
$pipe->exists('counter');
$pipe->get('counter');
$pipe->mget('does_not_exist', 'counter');
});
print_r($replies);
//CAS, 事务性操作
function zpop($client, $zsetKey) {
$element = null;
$options = array(
'cas' => true, // Initialize with support for CAS operations
'watch' => $zsetKey, // Key that needs to be WATCHed to detect changes
'retry' => 3, // Number of retries on aborted transactions, after
// which the client bails out with an exception.
);
$txReply = $client->multiExec($options, function($tx)
use ($zsetKey, &$element) {@list($element) = $tx->zrange($zsetKey, 0, 0);
if (isset($element)) {$tx->multi(); // With CAS, MULTI *must* be explicitly invoked.
$tx->zrem($zsetKey, $element);
}
});
return $element;
}
$zpopped = zpop($redis, ‘zset’);
echo isset($zpopped) ? “ZPOPed $zpopped” : “Nothing to ZPOP!”, “\n”;
// 对存取的 key 加前缀, 如: ‘nrk:’
$redis->getProfile()->setPreprocessor(new KeyPrefixPreprocessor(‘nrk:’));
// 分布式存储的一些办法
$multiple_servers = array(
array(
'host' => '127.0.0.1',
'port' => 6379,
'database' => 15,
'alias' => 'first',
),
array(
'host' => '127.0.0.1',
'port' => 6380,
'database' => 15,
'alias' => 'second',
),
);
use Predis\Distribution\IDistributionStrategy;
class NaiveDistributionStrategy implements IDistributionStrategy {
private $_nodes, $_nodesCount;
public function __constructor() {$this->_nodes = array();
$this->_nodesCount = 0;
}
public function add($node, $weight = null) {$this->_nodes[] = $node;
$this->_nodesCount++;
}
public function remove($node) {$this->_nodes = array_filter($this->_nodes, function($n) use($node) {return $n !== $node;});
$this->_nodesCount = count($this->_nodes);
}
public function get($key) {
$count = $this->_nodesCount;
if ($count === 0) {throw new RuntimeException('No connections');
}
return $this->_nodes[$count > 1 ? abs(crc32($key) % $count) : 0];
}
public function generateKey($value) {return crc32($value);
}
}
// 配置键散布策略
$options = array(
'key_distribution' => new NaiveDistributionStrategy(),
);
$redis = new Predis\Client($multiple_servers, $options);
for ($i = 0; $i set(“key:$i”, str_pad($i, 4, ‘0’, 0));
$redis->get("key:$i");
}
$server1 = $redis->getClientFor(‘first’)->info();
$server2 = $redis->getClientFor(‘second’)->info();
printf(“Server ‘%s’ has %d keys while server ‘%s’ has %d keys.\n”,
'first', $server1['db15']['keys'], 'second', $server2['db15']['keys']
);