自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Redis高可用性之Failover過渡方案

運維 系統(tǒng)運維 Redis
從Redis官方路線圖來看,大概會在Redis3.0左右正式支持Cluster。不過即便是樂觀的估計,至少也得等幾個月的時間,為了讓我的應(yīng)用在這段時間內(nèi)能保持高可用性,我以主從服務(wù)器為基礎(chǔ)實現(xiàn)了一個Failover過渡方案。

從Redis官方路線圖來看,大概會在Redis3.0左右正式支持Cluster。不過即便是樂觀的估計,至少也得等幾個月的時間,為了讓我的應(yīng)用在這段時間內(nèi)能保持高可用性,我以主從服務(wù)器為基礎(chǔ)實現(xiàn)了一個Failover過渡方案。

 

從理論上解釋,一旦主服務(wù)器下線,可以在從服務(wù)器里挑選出新的主服務(wù)器,同時重新設(shè)置主從關(guān)系,并且當(dāng)下線服務(wù)器重新上線后能自動加入到主從關(guān)系中去,內(nèi)容如下:

<?php

class RedisFailover
{
    public $config = array();
    public $map    = array();

    const CONFIG_FILE = 'config.php';
    const MAP_FILE    = 'map.php';

    public function __construct()
    {
        $config = include self::CONFIG_FILE;

        foreach ((array)$config as $name => $nodes) {
            foreach ($nodes as $node) {
                $node = new RedisNode($node['host'], $node['port']);

                if ($node->isValid()) {
                    $this->config[$name][] = $node;
                }
            }

            if (empty($this->config[$name])) {
                throw new Exception('Invalid config.');
            }

            $this->map[$name] = $this->config[$name][0];
        }

        if (file_exists(self::MAP_FILE)) {
            $map = include self::MAP_FILE;

            foreach ((array)$map as $name => $node) {
                $node = new RedisNode($node['host'], $node['port']);

                $this->map[$name] = $node;
            }
        }
    }

    public function run()
    {
        $set_nodes_master = function($nodes, $master) {
            foreach ($nodes as $node) {
                $node->setMaster($master->host, $master->port);
            }
        };

        foreach ($this->config as $name => $nodes) {
            $is_master_valid = false;

            foreach ($nodes as $node) {
                if ($node == $this->map[$name]) {
                    $is_master_valid = true;

                    break;
                }
            }

            if ($is_master_valid) {
                $set_nodes_master($nodes, $this->map[$name]);

                continue;
            }

            foreach ($nodes as $node) {
                $master = $node->getMaster();

                if (empty($master)) {
                    continue;
                }

                if ($master['master_host'] != $this->map[$name]->host) {
                    continue;
                }

                if ($master['master_port'] != $this->map[$name]->port) {
                    continue;
                }

                if ($master['master_sync_in_progress']) {
                    continue;
                }

                $node->clearMaster();

                $set_nodes_master($nodes, $node);

                $this->map[$name] = $node;

                break;
            }
        }

        $map = array();

        foreach ($this->map as $name => $node) {
            $map[$name] = array(
                'host' => $node->host, 'port' => $node->port
            );
        }

        $content = '<?php return ' . var_export($map, true) . '; ?>';

        file_put_contents(self::MAP_FILE, $content);
    }
}

class RedisNode
{
    public $host;
    public $port;

    const CLI = '/usr/local/bin/redis-cli';

    public function __construct($host, $port)
    {
        $this->host = $host;
        $this->port = $port;
    }

    public function setMaster($host, $port)
    {
        if ($this->host != $host || $this->port != $port) {
            return $this->execute("SLAVEOF {$host} {$port}") == 'OK';
        }

        return false;
    }

    public function getMaster()
    {
        $result = array();

        $this->execute('INFO', $rows);

        foreach ($rows as $row) {
            if (preg_match('/^master_/', $row)) {
                list($key, $value) = explode(':', $row);

                $result[$key] = $value;
            }
        }

        return $result;
    }

    public function clearMaster()
    {
        return $this->execute('SLAVEOF NO ONE') == 'OK';
    }

    public function isValid()
    {
        return $this->execute('PING') == 'PONG';
    }

    public function execute($command, &$output = null)
    {
        return exec(
            self::CLI . " -h {$this->host} -p {$this->port} {$command}", $output
        );
    }
}

?>

其中提到了兩個文件,先說一下config.php:

<?php

return array(
    'redis_foo' => array(
        array('host' => '192.168.0.1', 'port' => '6379'),
        array('host' => '192.168.0.2', 'port' => '6379'),
        array('host' => '192.168.0.3', 'port' => '6379'),
    ),
);

?>

說明:每個別名對應(yīng)一組服務(wù)器,在這組服務(wù)器中,有一個是主服務(wù)器,其余都是從服務(wù)器,主從關(guān)系不要在配置文件里硬編碼,而應(yīng)該通過SLAVEOF命令動態(tài)設(shè)定。

再說一下map.php文件,內(nèi)容如下:

<?php

return array (
    'redis_foo' => array (
        'host' => '192.168.0.1', 'port' => '6379'
    ),
);

?>

說明:別名對應(yīng)的是當(dāng)前有效的服務(wù)器。需要注意的是這個文件是自動生成的!程序在使用Redis的時候,都配置成別名的形式,具體的host,port通過此文件映射獲得。

明白了以上代碼之后,運行就很簡單了:

<?php

$failover = new RedisFailover();
$failover->run();

?>

說明:實際部署時,最嚴格的方式是以守護進程的方式來執(zhí)行,不過如果要求不是很苛刻的話,CRON就夠了。測試時可以手動殺掉主服務(wù)器進程,再通過INFO查看效果。

再補充一些命令行用法的相關(guān)說明,本文都是使用redis-cli來發(fā)送命令的,通常這也是最佳選擇,不過如果因為某些原因不能使用redis-cli的話,也可以使用nc(netcat)命令按照Redis協(xié)議實現(xiàn)一個簡單的客戶端工具,比如說PING命令可以這樣實現(xiàn):

shell> (echo -en "PING\r\n"; sleep 1) | nc localhost 6379

說明:之所以需要sleep一下是因為Redis的請求響應(yīng)機制是Pipelining方式的。

既然說到這里了,就再嘮十塊錢兒的,通常,我們可以使用telnet命令和服務(wù)交互,但是telnet有一點非常不爽的是命令行不支持上下鍵歷史,還好可以借助rlwrap來達成這個目的,視操作系統(tǒng),可以很容易的用APT或YUM來安裝,運行也很簡單:

shell> rlwrap telnet localhost 6379

說明:通過使用rlwrap,不僅支持上下鍵歷史,而且連Ctrl+r搜索也一并支持了,強!

在Redis Cluster釋出前,希望這個腳本能幫到你,其實其他的服務(wù)也可以使用類似的方案,比如MySQL,不過復(fù)雜性會加大很多,好在已經(jīng)有類似MHA之類的方案了。

【編輯推薦】

  1. 緩存大量小文件?Redis是首選!
  2. Redis能干啥?細看11種Web應(yīng)用場景
  3. 主流NoSQL數(shù)據(jù)庫之Redis全面評測

 

責(zé)任編輯:Yeva 來源: huoding.com
相關(guān)推薦

2024-02-27 09:48:25

Redis集群數(shù)據(jù)庫

2012-09-04 13:43:31

SQL Server

2013-08-28 10:30:39

vSphere

2018-05-25 09:31:00

數(shù)據(jù)存儲高可用

2009-07-09 10:25:16

2010-12-31 14:36:15

ExchangeSer

2012-07-04 11:21:07

OpenStack

2011-08-25 15:42:49

2024-12-11 08:35:55

2024-08-13 15:42:19

2010-07-28 10:22:44

DB2 9.5

2013-12-04 09:52:50

hadoop

2009-02-26 16:59:36

VMware虛擬化虛擬機

2018-06-21 08:23:35

云存儲高可用應(yīng)用

2012-02-22 10:13:43

虛擬化桌面虛擬化VMware View

2010-06-03 15:23:48

2009-09-03 13:44:27

RHEL服務(wù)器RHEL成功應(yīng)用

2009-07-07 23:14:00

高可用性SQL Server

2010-09-14 08:55:55

SQL Server

2010-07-06 17:42:46

SQL Server
點贊
收藏

51CTO技術(shù)棧公眾號