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 服務器連接失敗"; }