redis哨兵模式下主从切换后,php实现自动切换
redis的哨兵模式,在主服务器挂掉后,会通过选举将对应的从服务器切换为主服务器,以此来达到服务的高可用性。
在业务层面如果主从做了切换可能相对应的服务器IP地址会发生改变,这样会带来程序的的正常运行。为了不影响其业务,会考虑使用VIP去实现IP的飘逸,但是在部分情况下,虚拟机并不支持VIP,这样就无法保证业务的正常运行。索引在此情况下,通过业务本身来实现连接新的主的IP。本文主要以PHP为例,相关代码如下
<?php class SRedis { /** * 哨兵地址,支持多哨兵地址 * @var array * eg: [ [ 'host' => '127.0.0.1' , 'port' => 26379 ] ] */ private $_sentinelAddr = []; private $_sentinelConn = null; private $_timeout = 10; //超时时间 private $_masterName = 'mymaster'; //主节点名称 private static $_handle = []; //存放redis连接实例 public function __construct(array $iplist, string $masterName = null) { $this->_sentinelAddr = $iplist; $masterName !== null && $this->_masterName = $masterName; $this->_getSentinelConn(); } /** * 获取redis主节点的实例 * @return bool|Redis * @throws Exception */ public function getInstansOf() { $masterInfo = $this->getMasterInfo(); if ($masterInfo) { $instansof = $this->_connection($masterInfo[0], $masterInfo[1], $this->_timeout); return $instansof; } return false; } /** * 获取主节点的ip地址 * @return array */ public function getMasterInfo() { $masterInfo = []; if ($this->_sentinelConn != null) { $masterInfo = $this->_sentinelConn->rawcommand("sentinel", 'get-master-addr-by-name', $this->_masterName); } return $masterInfo; } /** * 设置哨兵连接句柄 */ private function _getSentinelConn() { if (is_array($this->_sentinelAddr) && $this->_sentinelAddr) { $this->_sentinelConn = $this->_RConnect($this->_sentinelAddr); } } /** * 获取redis句柄(如果是多主机,保证连接的是可用的哨兵服务器) * @param array $hosts * @return null|Redis */ private function _RConnect(array $hosts) { $count = count($hosts); $redis = null; if ($count == 1) { $this->_connection($hosts[0]['host'], $hosts[0]['port'], $this->_timeout); } else { $i = 0; while ($redis == null && $i < $count) { $redis = $this->_connection($hosts[$i]['host'], $hosts[$i]['port'], $this->_timeout); $i++; } } return $redis; } /** * redis 连接句柄 * @param string $host * @param int $port * @param int $timeout * @return null|Redis */ private function _connection(string $host, int $port, int $timeout) { if (isset(self::$_handle[$host . ':' . $port])) { return self::$_handle[$host . ':' . $port]; } try { $redis = new Redis(); $redis->connect($host, $port, $timeout); self::$_handle[$host . ':' . $port] = $redis; } catch (\Exception $e) { $redis = null; } return $redis; } }
$hosts = [ [ 'host' => '127.0.0.1', 'port' => 26381 ], [ 'host' => '127.0.0.1', 'port' => 26380 ] ]; $masterName = 'mymaster'; $sredis = new SRedis($hosts, $masterName); $masterRedis = $sredis->getInstansOf(); if ($masterRedis) { print_r($masterRedis->hgetall("iplist")); } else { echo "redis 服务器连接失败"; }