背景
由于用户不断增加,业务功能不断积累,redis的使用也变的越多,单机扩展内存已不是最优解,采用了升级redis集群的方案。
官方地址
兼容改动
1.keys 命令不再允许使用,可改用基于游标的迭代器来完成 scan,最后我会列举使用示例。
2.exists 命令也不再允许使用,可通过ttl判断时间来替代,时间复杂度为O(1),或者根据hash,set等类型长度来替代。
3.multi事务中,需要增加watch。这也暗藏着一个bug。
主要修改的是这三个命令。
scan示例
class pro
{
public function output($str = '') {
echo $str . PHP_EOL;
return true;
}
public function formatList($data) {
$data = explode(PHP_EOL, $data);
$list = [];
$cursor = 0;
foreach ($data as $item) {
if (empty($item)) continue;
if (!$cursor) {
$cursor = $item; //没有值,第一个是游标值
} else {
$list[] = $item;
}
}
return [$cursor, $list];
}
public function main() {
$config = config::get('redis_api'); //获取配置
$host = $config[0]['host'];
$pwd = $config[0]['pwd'];
$port = $config[0]['port'];
sleep(2);
$redis = new Redis(); //实例化redis
$cursor = 0; //游标值,为0表示结束
$size = 100;
try {
do {
//命令行方式执行redis scan
$shell = "redis-cli -h $host -a $pwd -p $port scan $cursor match " . $this->redisKey . "* count $size";
$result = shell_exec($shell);
//格式化游标和内容
list($cursor, $list) = $this->formatList($result);
foreach ($list as $key) {
//进行对结果的操作,如下删除key
$redis->del($key);
}
} while ($cursor != 0);
} catch (Exception $e) {
$this->output('error:' . $e->getMessage());
}
}
}
$pro = new pro();
$pro->main();
redis事务中的坑
$redis = new redis();
$key = 'test_zp';
//升级集群增加的watch
$redis->watch($key);
//实例化事务
$multi = $redis->multi(Redis::PIPELINE);
//批量执行插入操作
foreach ($list as $item) {
$redis->ZADD($key, time(), $item . random_int(100, 500));
}
$multi->exec();
// 重点,因为集群升级所加的watch必须用unwatch配合使用
// unwatch必须加
$redis->unwatch($key);
Redis::PIPELINE是为了管道方式执行为了避免多次链接,一次请求完成多个操作。
由于使用了管道,导致了必须使用unwatch,不然会导致exec后面的redis操作失败。