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

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM