在哨兵模式已经部署好的情况下,如何让php能监听到redis呢?
比如说,在主服务7269端口中断后,7270端口变成主服务,但是在项目代码中,redis的端口号是默认的,是不会变的,所有还是会造成
redis连接不上,从而出现错误。
在写这篇文章前,本人已经查了很多方法。
网上有一种公共的方法,就是下载php-redis扩展,然后使用
$redis->rawCommand('SENTINEL', 'masters');
这个方法来获取redis信息,我不用这个方法是因为我本人通过这个方法只返回了false,可能是我配置或者代码有问题。
于是我自己写了一个方法:
function sentinelPort(){
try{
$redis = new \Redis();
$fileurl = Env::get('config_path') . 'redis.php';
$config = Rconfig::load($fileurl,'redis');
$host = $config['host'];
$port = $config['port'];
$password = $config['password'];
$redis->connect($host, $port);
$redis->auth($password);
$redis->ping();
$redisInfo = $redis->info();
if(is_array($redisInfo)&&isset($redisInfo['role'])&&$redisInfo['role']=='master'){
return $redis;
}else{
throw new \Exception($port.'是从服务器');
}
}catch(\Exception $e){
write_error_log($e);
$portArr = [7269,7270,7271];//端口号
$portArr = array_flip($portArr);
unset($portArr[$port]);
$newPort = array_rand($portArr,1);
if(setconfig('redis.php',['port'],[$newPort])){
return sentinelPort();
}
}
}
这个方法是用户获取redis对象的方法,并且当主服务中断后,也是可以重新获取到新的主服务的,不会出现报错。
1、利用try catch来捕捉redis连接错误信息
2、我这个是基于Thinkphp方法写的,把redis的基本信息都存到redis.php配置文件中,当然redis.php是自己创建的。
之所以用这种方法来获取redis信息是因为在哨兵模式下,主服务的端口号会变动,所以redis.php也是要动态修改的。但是
config去取redis.php信息时,总是取到修改之前的信息。
3、redis.php配置文件内容如下:
能用到的参数host,ip地址;port,端口号;password,密码;
4、当主服务中断后,redis连接会出错,就会执行catch中的方法。
write_error_log($e);//记录错误日志,这个方法在https://chengzhigang.cn/index/article/index.html?id=40中提到过。
$portArr;//当前redis的所有端口号;
健值对调,删除当前错误的端口,并且错剩下的端口中随机取出一个来。
setconfig('redis.php',['port'],[7270]);//假设当前随机取到的端口号是7270,然后把7270记入到redis.php配置中,替换原先的7279,
这个是因为Thinkphp5.1不支持更改动态更改配置文件而写的方法,这个是从网上找的。具体方法如下:
function setconfig($file,$pat, $rep){
/**
* 原理就是 打开config配置文件 然后使用正则查找替换 然后在保存文件.
* 传递的参数为2个数组 前面的为配置 后面的为数值. 正则的匹配为单引号 如果你的是分号 请自行修改为分号
* $pat[0] = 参数前缀; 例: default_return_type
$rep[0] = 要替换的内容; 例: json
*/
if (is_array($pat) and is_array($rep)) {
for ($i = 0; $i < count($pat); $i++) {
$pats[$i] = '/\'' . $pat[$i] . '\'(.*?),/';
$reps[$i] = "'". $pat[$i]. "'". "=>" . "'".$rep[$i] ."',";
}
$fileurl = Env::get('config_path') . $file;
$string = file_get_contents($fileurl); //加载配置文件
$string = preg_replace($pats, $reps, $string); // 正则查找然后替换
file_put_contents($fileurl, $string); // 写入配置文件
return true;
} else {
return flase;
}
}
然后重新执行获取redis对象的方法。
5、当redis连接成功后,我们需要知道它连接的是不是主服务器,所以需要
$redis->info();这个方法来判断它是否是主服务器,如果role是master,那就直接返回redis对象。
如果不是,就返回错误,重新跑这个逻辑。
博客地址:观海听潮博客