php操作redis哨兵模式,主从切换后自动获取master

亚瑟
• 阅读 1855

本文将介绍如何使用PHP来连接redis哨兵模式。哨兵模式:大概的原理就是监听redis主库心跳包,如果心跳断开,则枚举一个从库推举成为新的主库,防止redis宕机不能使用。为了增强redis的性能,防止其挂掉,引用redis哨兵监控redis集群是个不错的选择。下面三步简单记录php连接redis哨兵。 第一步、获取哨兵模式连接redis句柄对象

/**
 * 哨兵模式连接redis
 * @return array|Redis
 */
function im_cache_redis() {
    global $_W;
    static $im_redisobj;
    $config = $_W['config']['im']['redis'];

    //哨兵节点
    $temp_data = [
        [
            'ip' => '192.168.101.85',
            'port' => 26380
        ],
        [
            'ip' => '192.168.101.85',
            'port' => 26381
        ],
        [
            'ip' => '192.168.101.85',
            'port' => 26382
        ]
    ];

    $address = redis_nodeinfo($temp_data);
    logging_run(__METHOD__ . ':redis哨兵获取主节点地址:' . json_encode($address),LOGGING_INFO);
    $im_redisobj = new Redis();
    try {
        $im_redisobj->connect($address['ip'],intval($address['port']));
        if (!empty($config['auth'])) {
            $auth = $im_redisobj->auth($config['auth']);
        }
    } catch (Exception $e) {
        logging_run(__METHOD__ . ':redis连接失败,错误信息:' . $e->getMessage(),LOGGING_ERROR);
        return error(-1,'im redis连接失败,错误信息:'.$e->getMessage());
    }
   return $im_redisobj;
}

第二步、获取redis哨兵主节点地址

/**
 * 获取redis哨兵主节点地址
 * @param array $temp_data
 * @return array
 */
function redis_nodeinfo($temp_data = []){
    $random = [];
    $ips = [];
    //哨兵节点
    //$temp_data = [['ip'=>'101.36.149.73','port'=>263719],['ip'=>'101.36.149.41','port'=>26379],['ip'=>'101.36.149.189','port'=>26379]];
    for($count=1;$count<count($temp_data);$count++){
        $random[] =$count;
    }
    shuffle($random);
    foreach($random as $key){
        $ips[$temp_data[$key]['ip']]=['port'=>$temp_data[$key]['port']];
    }
    $sentinel = new Sentinel();
    foreach($ips as $ip=>$portinfo){
        try{
            $sentinel->connect($ip, $portinfo['port'],1);
            $address = $sentinel->getMasterAddrByName('mymaster');
            if($address){
                echo '哨兵节点:' .$ip .'正常'. '<br/>';

                return $address;
            }
        }catch(Exception $e){
            echo '哨兵节点:' .$ip .'异常 异常信息:' . $e->getMessage() . '<br/>';
        }
    }
}

第三步、封装Sentinel类

<?php

class Sentinel
{
    /**
     * @var \Redis
     */
    protected $redis;

    public function __construct()
    {
        $this->redis = new Redis();
    }

    public function __destruct()
    {
        try {
            $this->redis->close();
        } catch (\Exception $e) {
        }
    }

    /**
     * @param $host
     * @param int $port
     * @return boolean
     */
    public function connect($host, $port = 26379)
    {
        if (!$this->redis->connect($host, $port)) {
            return false;
        }
        return true;
    }

    /**
     * This command simply returns PONG.
     *
     * @return string STRING: +PONG on success. Throws a RedisException object on connectivity error.
     */
    public function ping()
    {
        return $this->redis->ping();
    }

    /**
     * Show a list of monitored masters and their state.
     *
     * @return array
     */
    public function masters()
    {
        return $this->parseArrayResult($this->redis->rawCommand('SENTINEL', 'masters'));
    }

    /**
     * parse redis response data
     *
     * @param array $data
     * @return array
     */
    private function parseArrayResult(array $data)
    {
        $result = array();
        $count = count($data);
        for ($i = 0; $i < $count;) {
            $record = $data[$i];
            if (is_array($record)) {
                $result[] = $this->parseArrayResult($record);
                $i++;
            } else {
                $result[$record] = $data[$i + 1];
                $i += 2;
            }
        }

        return $result;
    }

    /**
     * Show the state and info of the specified master.
     *
     * @param string $master_name
     * @return array
     */
    public function master($master_name)
    {
        return $this->parseArrayResult($this->redis->rawCommand('SENTINEL', 'master', $master_name));
    }

    /**
     * Show a list of slaves for this master, and their state.
     *
     * @param string $master_name
     * @return array
     */
    public function slaves($master_name)
    {
        return $this->parseArrayResult($this->redis->rawCommand('SENTINEL', 'slaves', $master_name));
    }

    /**
     * Show a list of sentinel instances for this master, and their state.
     *
     * @param string $master_name
     * @return array
     */
    public function sentinels($master_name)
    {
        return $this->parseArrayResult($this->redis->rawCommand('SENTINEL', 'sentinels', $master_name));
    }

    /**
     * Return the ip and port number of the master with that name.
     * If a failover is in progress or terminated successfully
     * for this master it returns the address and port of the promoted slave.
     *
     * @param string $master_name
     * @return array
     */
    public function getMasterAddrByName($master_name)
    {
        $data = $this->redis->rawCommand('SENTINEL', 'get-master-addr-by-name', $master_name);
        return array(
            'ip' => $data[0],
            'port' => $data[1]
        );
    }

    /**
     * This command will reset all the masters with matching name.
     * The pattern argument is a glob-style pattern.
     * The reset process clears any previous state in a master
     * (including a failover in progress), and removes every slave
     * and sentinel already discovered and associated with the master.
     *
     * @param string $pattern
     * @return int
     */
    public function reset($pattern)
    {
        return $this->redis->rawCommand('SENTINEL', 'reset', $pattern);
    }

    /**
     * Force a failover as if the master was not reachable,
     * and without asking for agreement to other Sentinels
     * (however a new version of the configuration will be published
     * so that the other Sentinels will update their configurations).
     *
     * @param string $master_name
     * @return boolean
     */
    public function failOver($master_name)
    {
        return $this->redis->rawCommand('SENTINEL', 'failover', $master_name) === 'OK';
    }

    /**
     * @param string $master_name
     * @return boolean
     */
    public function ckquorum($master_name)
    {
        return $this->checkQuorum($master_name);
    }

    /**
     * Check if the current Sentinel configuration is able to
     * reach the quorum needed to failover a master, and the majority
     * needed to authorize the failover. This command should be
     * used in monitoring systems to check if a Sentinel deployment is ok.
     *
     * @param string $master_name
     * @return boolean
     */
    public function checkQuorum($master_name)
    {
        return $this->redis->rawCommand('SENTINEL', 'ckquorum', $master_name);
    }

    /**
     * Force Sentinel to rewrite its configuration on disk,
     * including the current Sentinel state. Normally Sentinel rewrites
     * the configuration every time something changes in its state
     * (in the context of the subset of the state which is persisted on disk across restart).
     * However sometimes it is possible that the configuration file is lost because of
     * operation errors, disk failures, package upgrade scripts or configuration managers.
     * In those cases a way to to force Sentinel to rewrite the configuration file is handy.
     * This command works even if the previous configuration file is completely missing.
     *
     * @return boolean
     */
    public function flushConfig()
    {
        return $this->redis->rawCommand('SENTINEL', 'flushconfig');
    }

    /**
     * This command tells the Sentinel to start monitoring a new master with the specified name,
     * ip, port, and quorum. It is identical to the sentinel monitor configuration directive
     * in sentinel.conf configuration file, with the difference that you can't use an hostname in as ip,
     * but you need to provide an IPv4 or IPv6 address.
     *
     * @param $master_name
     * @param $ip
     * @param $port
     * @param $quorum
     * @return boolean
     */
    public function monitor($master_name, $ip, $port, $quorum)
    {
        return $this->redis->rawCommand('SENTINEL', 'monitor', $master_name, $ip, $port, $quorum);
    }

    /**
     * is used in order to remove the specified master: the master will no longer be monitored,
     * and will totally be removed from the internal state of the Sentinel,
     * so it will no longer listed by SENTINEL masters and so forth.
     *
     * @param $master_name
     * @return boolean
     */
    public function remove($master_name)
    {
        return $this->redis->rawCommand('SENTINEL', 'remove', $master_name);
    }

    /**
     * The SET command is very similar to the CONFIG SET command of Redis,
     * and is used in order to change configuration parameters of a specific master.
     * Multiple option / value pairs can be specified (or none at all).
     * All the configuration parameters that can be configured via sentinel.conf
     * are also configurable using the SET command.
     *
     * @param $master_name
     * @param $option
     * @param $value
     * @return boolean
     */
    public function set($master_name, $option, $value)
    {
        return $this->redis->rawCommand('SENTINEL', 'set', $master_name, $option, $value);
    }

    /**
     * get last error
     *
     * @return string
     */
    public function getLastError()
    {
        return $this->redis->getLastError();
    }

    /**
     * clear last error
     *
     * @return boolean
     */
    public function clearLastError()
    {
        return $this->redis->clearLastError();
    }

    /**
     * sentinel server info
     *
     * @return string
     */
    public function info()
    {
        return $this->redis->info();
    }

} 

本文转自 https://www.100txy.com/article/261,如有侵权,请联系删除。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Stella981 Stella981
3年前
Nginx + lua +[memcached,redis]
精品案例1、Nginxluamemcached,redis实现网站灰度发布2、分库分表/基于Leaf组件实现的全球唯一ID(非UUID)3、Redis独立数据监控,实现订单超时操作/MQ死信操作SelectPollEpollReactor模型4、分布式任务调试Quartz应用
Stella981 Stella981
3年前
Redis主从模式的常用类型
本文介绍Redis主从模式的常用类型。Redis的可靠性主要有主从模式和集群模式。对于主从模式而言,Redis有以下方案:Sentinel方案;Keepalived方案。Sentinel方案作为Redis主推的官方方案,主要的实现原理是通过引入哨兵sentinel节点,来投标决定master节点故障后,
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
3年前
Redis Sentinel 哨兵模式
RedisSentinel哨兵模式Sentinel介绍Redis的主从模式下,主节点一旦发生故障不能提供服务,需要人工干预,将从节点晋升为主节点,同时还需要修改客户端配置。对于很多应用场景这种方式无法接受。Sentinel(哨兵)架构解决了redis主从人工干预的问题。Redis
Wesley13 Wesley13
3年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Stella981 Stella981
3年前
Redis哨兵集群中哨兵挂了,主从库还能切换吗?
实际上,一旦多个实例组成了哨兵集群,即使有哨兵实例出现故障挂掉了,其他哨兵还能继续协作完成主从库切换的工作,包括判定主库是不是处于下线状态,选择新主库,以及通知从库和客户端。_1_,基于pub/sub机制的哨兵集群组成哨兵之间的相互发现哨兵实例之间可以相互发现,要归功于Redis提供的pub/sub机制,也就是