page contents

redis哨兵模式主从切换后,php实现自动切换

为了不影响其业务,会考虑使用VIP去实现IP的飘逸,但是在部分情况下,虚拟机并不支持VIP,这样就无法保证业务的正常运行。

attachments-2020-04-zAPS6xbr5e8444c76388f.jpg


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 服务器连接失败";
}



attachments-2020-04-KviWTD0f5e8444b150060.jpg

  • 发表于 2020-04-01 15:38
  • 阅读 ( 473 )
  • 分类:PHP开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
Pack
Pack

1135 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1316 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章