PHP中Redis的一点使用经验
1.生存时间
基本用法
$redis->expire($key,60); //使用秒为单位
$redis->pExpire($key,60000);//使用毫秒作为单位
$redis->expireAt($key,1476868380);//使用Unix timestamp,指定时间过期
$redis->pExpireAt($key,1476868380000);//使用Unix timestamp在指定时间过期,区别是毫秒作为单位
$redis->persist($key);//移除给定key的生存时间
$redis->ttl($key);//返回key剩余的过期时间,使用秒为单位
$redis->pttl($key);//返回key剩余的过期时间,使用毫秒作为单位
注意:
1. incr ,hset,lpush,sadd等操作 并不会改变key的生存时间
2. RENAME old-key new-key 后,new-key会继承原key的生存时间
3. 只有 SET GETSET DEL 命令才会清除生存时间
2.BLPOP / BRPOP
基本用法
BLPOP / BRPOP 是 LPOP/RPOP 的阻塞版本,在给定list无法弹出任何元素的时候阻塞连接,如果list被添加一个元素会及时弹出该元素
当有元素弹出时返回一个数组,第一个元素是弹出list的 key,第二个元素是 value。
$key1 = 'key-list1';
$key2 = 'key-list2';
$timeout = 100;
try {
while ($item = $redis->brPop($key1, $key2, $timeout)) {
var_dump($item);
/*
when >RPUSH key-list1 a
array(2) {
[0]=> string(9) "key-list1" list name
[1]=> string(1) "a" item value
}
*/
}
} catch (RedisException $e) {
//TODO
}
注意:
1.$timeout
超时后 会抛出一个RedisException 异常
2.$timeout
设置为0 表示没有超时时间
3. BRPOP里的$timeout
在PHP里会被public function connect( $host, $port = 6379, $timeout = 0.0 )
方法设置的$timeout
覆盖
3. SETBIT / BITCOUNT
SETBIT key offset value
:设置或者清空key的value(字符串)在offset处的bit值。
BITCOUNT key [start end]
: 统计字符串被设置为1的bit数.
默认整个字符串都会被进行计数,指定 start 、 end 参数,可以统计指定范围内。
这两个命令有个典型应用 来源官方文档
Bitmap 对于一些特定类型的计算非常有效。
例如,统计用户在指定日期范围内的上次频率等需求,可以使用 SETBIT 和 BITCOUNT 来实现。以某个日期作为起点,如果用户在第x天登录,就执行
SETBIT uid x 1
,以此类推。
想计算用户登录次数 执行BITCOUNT uid
即可,加上范围就可以获取更多个性化需求。
4.批量操作(linux cli)
有时候需要批量删除部分key,可以借助xargs
redis-cli -h host -p port -a auth -n db --scan --pattern Pattern|xargs redis-cli -h host -p port -a auth -n db DEL
不建议使用keys ,keys 时间复杂度为O(N),SCAN 时间复杂度为O(1)
SCAN 常见用法
$it = null;
$redis->setOption(Redis::OPT_SCAN, Redis::SCAN_RETRY);
while ( $ret = $redis->scan($it,'test*',3)){
foreach ($ret as $item){
echo $item.PHP_EOL;
}
}
5.PIPELINE
Redis::MULTI 默认开启一个事务,但是通过设置参数可以使用PIPELINE,能够节省时间
两种用法
$pip = $redis->multi(Redis::PIPELINE);
$re = $pip->incr($key1)->incr($key2)->del($key3)->exec();
或者
$pip = $redis->multi(Redis::PIPELINE);
$pip->incr($key1);
$pip->incr($key2);
$pip->del($key3);
$ret = $pip->exec();
$ret
包括了每一个执行的返回结果
6.事务 MULTI
执行使用
$redis->multi();
将开始一个事务,或者$redis->multi(Redis::MULTI);
$ret = $redis->multi()
->set('key1', 'val1')
->get('key1')
->set('key2', 'val2')
->get('key2')
->exec();
使用和PIPELINE 类似,但没有事务保证
7.WATCH/UNWATCH/DISCARD
WATCH key
watch 命令会监视给定的key,当exec时候如果key从调用watch后发生过变化,则整个事务会失败。
也可以调用watch多次监视多个key,这样就可以对指定的key加乐观锁了。
watch的key是对整个连接有效的,事务也一样。如果连接断开,监视和事务都会被自动清除。
exec,discard,unwatch命令都会清除连接中的所有监视.
$redis->watch($key2);
$ret = $redis->multi(Redis::MULTI)->get($key)
->incr($key1)->del($key2)->exec();
DISCARD
清空事务的命令队列并退出事务上下文,如果已使用WATCH,DISCARD将释放所有被WATCH的key。
Redis 事务仍然有一定不足
127.0.0.1:6379> incr test8
(integer) 2
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> incr test8
QUEUED
127.0.0.1:6379> hset test8 1 1
QUEUED
127.0.0.1:6379> exec
1) (integer) 3
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> get test8
"3"
redis只能保证事务的每个命令连续执行,但是如果事务中的一个命令失败了,并不回滚其他命令
8.Geo
Redis 3.2.0 以后的版本支持Geo查询
GEOADD key longitude latitude member [longitude latitude member ...]
添加一个地理位置点,经度必须在纬度前面
GEODIST key member1 member2 [unit]
计算两个点之间的距离(存在误差,因为地球不是标准球体)
unit: m 表示单位为米(默认),km 表示单位为千米,mi 表示单位为英里,ft 表示单位为英尺。
GEORADIUS key longitude latitude radius m|km|ft|mi
[WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
以给定的经纬度为中心, 返回与中心的距离不超过给定最大距离的所有位置元素。
GEORADIUSBYMEMBER key member radius m|km|ft|mi
[WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
与GEORADIUS类似,只不过计算与某个点距离不超过 radius的元素
GEOPOS key member [member ...] #返回元素的经纬度
GEOHASH key member [member ...]#返回一个标准Geohash
GEOHASH 有如下特点,应用广泛
字符串越长,表示的范围越精确。编码长度为9时,精度在2米左右,Redis 使用11位。
字符串相似的位置距离也相近,利用前缀匹配,可以快速查询某个坐标附近的地理位置。
geohash计算的字符串,可以反向解码出原来的经纬度。可以在 geohash.org 网站使用,网址
http://geohash.org/<geohash-string>