Redis面試必看之持久化、主從同步、布隆過濾器、集群等詳解

一、數(shù)據(jù)類型

redis支持以下五種數(shù)據(jù)類型:

1. String類型

二進制安全,可存儲字符串、圖片和視頻等,支持incr自增操作(set/get/mset/mget/incr...)

2. List類型

雙向鏈表,可以實現(xiàn)消息隊列功能(rpush/lpop/llen...)

3. Set類型

無序集合,通過HashTable實現(xiàn),可實現(xiàn)快速查找(去重)(sadd/srem/sismember...)

4. Sorted Set類型

有序集合,排好序的Set類型,可以用來實現(xiàn)優(yōu)先級隊列(zadd/zrem/zincrby...)

5. Hash類型

每個key都是一個HashTable,適合存儲對象,如用戶信息對象,id作key(hset/hget/hmset/hmget/hlen...)

二、事務處理

redis支持簡單的事務操作,通過multi命令進入事務操作的上下文,接下來的redis命令將依次存入隊列,識別到exec命令時,redis將按隊列順序執(zhí)行隊列中的所有命令,并將執(zhí)行結果一并打包返回,然后終結事務上下文。

三、持久化

redis是基于內存的數(shù)據(jù)庫,內存數(shù)據(jù)存在一個嚴重的弊端:突然宕機后者斷電時,內存的數(shù)據(jù)不會保存。為了解決這個問題,redis提供了2種持久化的方式,分別為內存快照(Snapshotting)和日志追加(Append-only file),下面介紹一下。

1. 內存快照(RDB)

內存快照是將內存中的數(shù)據(jù)寫入二進制文件中,默認文件名為dump.rdb。redis重啟時讀取rdb中的數(shù)據(jù)。
redis內存快照分為自動和手動2種觸發(fā)模式:

1.1 手動觸發(fā)

客戶端使用save或bgsave命令告訴redis需要做一次快照操作

  • save:阻塞redis服務器,拒絕所有redis命令,直到save完成。 PS: 盡量不要使用
  • bgsave:fork一個子進程(非線程),通過子進程去進行save操作,而主進程可以執(zhí)行命令。

需要注意以下問題:

  • 在執(zhí)行bgsave時,為避免父子進程同時執(zhí)行rdbSave而產生競爭,客戶端發(fā)送的save命令將被拒絕。
  • 在執(zhí)行bgsave時,如果發(fā)送了bgrewriteaof(aof重寫)命令,該命令將延遲到bgsave完成之后執(zhí)行,如果正在執(zhí)行bgrewriteaof命令,bgsave將被拒絕。
  • 雖然bgsave是由子進程進行rdb文件的生成,但是在fork子進程的時候依然會造成父進程的阻塞,因此使用時要格外注意。
1.2 自動觸發(fā)

因為basave命令可以不阻塞父進程保存數(shù)據(jù),所以redis可以設置服務器配置的save選項,讓服務器每隔一段時間自動執(zhí)行一次bgsave命令。
save 秒數(shù) 修改次數(shù)
可以設置多個條件實現(xiàn)不同的快照方案,滿足任何一個條件,redis都將進行一次內存快照:

save 900 1
save 300 10
save 60  1000
2. 日志追加(AOF)

aof是把增加、修改的命令通過write函數(shù)追加到日志文件的尾部(默認名appendonly.aof)。redis重啟時讀取aof文件中的所有命令并且執(zhí)行,從而把數(shù)據(jù)寫入內存中。

由于操作系統(tǒng)內核的I/O接口可能存在緩存,所以日志追加的方式可能不會立即寫入文件中,這就有可能丟失部分數(shù)據(jù)。redis可以提供了以下三種方式配置來告訴redis何時去執(zhí)行fsync函數(shù)強制系統(tǒng)將緩存寫入磁盤:

#appendfsync always  # 每次收到增加或修改命令就立刻強制寫入磁盤
appendfsync everysec # 每秒強制寫入磁盤一次
#appendfsync no      # 是否寫入磁盤完全依賴系統(tǒng)

日志追加的方式有效降低了數(shù)據(jù)丟失的風險,也帶了另一個問題,那就是持久化文件不斷膨脹。例如,執(zhí)行incr nums命令100次,文件就會保存100條incr命令,其實99條都是多余的命令,因為恢復數(shù)據(jù)只需要執(zhí)行set nums 100就可以了。

redis提供了bgwriteaof,當redis收到此命令時,就使用類似于內存快照的方式將內存的數(shù)據(jù)以命令的方式保存到臨時文件中,最后替換原來的日志文件。

四、主從同步

redis支持主從同步。主從同步可以防止主機(Master)掛掉導致網站不能正常運作,只需要把從機(Slave)設置為主機即可。主從同步有諸多優(yōu)點:

  • Master可以有多個Slave。
  • 多個Slave可以連接到相同的Master,還可以連接到其他Slave形成圖形結構。
  • 不會阻塞Master。當一個或多個Slave與Master初次進行數(shù)據(jù)同步時,Master可以繼續(xù)處理客戶端請求。相反,Slave在初次進行數(shù)據(jù)同步時不能處理請求(2.2版本以后不再阻塞)。
  • 在Master服務器禁止持久化,只在Slave服務器進行數(shù)據(jù)持久化。
1. 主從同步原理

主從同步設置好以后,Slave自動與Master建立連接,發(fā)送SYNC命令。無論是初次建立連接還是重連,Master都將啟動一個后臺進程,將內存數(shù)據(jù)以快照的方式寫入文件中,同時Master主進程開始收集新的命令。Master后臺進程完成快照操作以后,將數(shù)據(jù)文件發(fā)送給Slave,Slave將文件保存到磁盤上,然后把數(shù)據(jù)加載到內存中。接著Master把緩存的命令發(fā)給Slave,后續(xù)Master收到的寫命令都通過開始建立的連接發(fā)送到Slave。當Master與Slave斷開連接,Slave自動重新建立連接。當Master同時收到多個Slave發(fā)來的同步請求,只會啟動一個進程寫數(shù)據(jù)庫鏡像,然后發(fā)給所有的Slave。

主從同步第一階段(建立連接):

    1. Slave服務器主動連接到Master服務器。
    1. Slave服務器發(fā)送SYNC命令到Master服務器請求同步。
    1. Master服務器啟動新的進程備份數(shù)據(jù)庫到rdb文件。
    1. Master服務器把rdb文件傳輸給Slave服務器。
    1. Slave服務器清空數(shù)據(jù)庫文件,把rdb文件導入數(shù)據(jù)庫中。

主從同步第二階段(持續(xù)同步):

    1. Master服務器把所有用戶的更改數(shù)據(jù)的操作,通過命令的形式轉發(fā)給所有的Slave服務器。
    1. Slave服務器執(zhí)行Master服務器發(fā)送的命令。

Redis主從復制的配置,只需要在Slave服務器的配置文件中加入以下配置項:

slaveof 192.168.1.1 6379 # 指定Master的ip和端口

五、布隆過濾器

布隆過濾器是一種比較巧妙的概率型數(shù)據(jù)結構,它可以告訴你某種東西可能存在或者一定不存在。當它告訴你某種東西存在時,這種東西可能存在;當它告訴你某種東西不存在時,那它一定不存在。

1.1 實現(xiàn)原理

布隆過濾器的數(shù)據(jù)結構就是一個很大的位數(shù)組和幾個不同的的無偏哈希函數(shù)。向布隆過濾器添加元素時,會根據(jù)多個無偏哈希函數(shù),算出一個整體的索引值,然后對位數(shù)組長度進行一個取模運算,每個無偏哈希函數(shù)都會得到一個不同的位置。再把這幾個位數(shù)組對應的位置值置1,就完成了一個bf.add命令操作。

向布隆過濾器查詢元素是否存在時,和添加元素一樣,也會哈希出幾個位置來,看對應的位置是否都為1。只要有一個位0,那么就說明這個布隆過濾器不存在這個元素;如果都為1,并不能完全說明這個元素就一定存在,有可能這些位置為1是因為其他元素的存在,這就是布隆過濾器會存在誤判的原因。

1.2 基本用法

布隆過濾器的基本用法:

  • bf.add:添加單個元素, 類似于集合的sadd。
  • bf.madd:添加多個元素。
  • bf.exists:判斷某個元素是否存在,類似于集合的sismember。
  • bf.mexusts:判斷多個元素是否存在。
1.3 進階用法

創(chuàng)建一個自定義的布隆過濾器:bf.reserve key error_rate capacity

  1. key:鍵名。
  2. error_rate:期望錯誤率,錯誤率越低,需要的空間越大。
  3. capacity:初識容量,當初實際元素個數(shù)超過這個實際容量時,錯誤率將會上升。
bf.reserve one-more-filter 0.0001 1000000

六、Redis集群

redis集群主要是redis的一個分布式實現(xiàn),主要實現(xiàn)目標是:

  • 可擴展性:能夠方便地擴展集群,可擴展到1000個節(jié)點。
  • 寫入安全:集群會盡可能保存客戶端寫入的數(shù)據(jù),但在故障轉移時可能出現(xiàn)短時的數(shù)據(jù)丟失。
  • 可用性:集群的大多數(shù)節(jié)點都是可達的,并且對于不可達的主節(jié)點都至少有一個從節(jié)點數(shù)可達的情況下,集群仍可以繼續(xù)提供服務。

redis集群采用的是p2p的運行模式,完全去中心化。把所有的key分成了16384個solt(插槽),每個redis實例負責其中一部分solt。集群中的所有信息都通過節(jié)點之間定期的數(shù)據(jù)交換而更新。

1. 集群搭建
redis集群至少需要6個節(jié)點(3主3從)才能完成,下面演示的是單臺機器上用多個端口進行模擬,生產環(huán)境中必須在多臺機器上搭建集群才能保證其可用性,以免因機器宕機而造成集群不可用。

bind 192.168.128.1                                        #綁定IP
port 9000                                                 #指定端口
dir /usr/local/etc/redis/9000                             #指定保存數(shù)據(jù)文件的路徑
cluster-enabled yes                                       #開啟集群
cluster-config-file /usr/local/etc/redis/9000/nodes.conf  #自動創(chuàng)建,保存集群運行情況
cluster-node-timeout 15000                                #指定集群中節(jié)點的超時時間
cluster-require-full-coverage no                          #指定集群如果沒有完全汗覆蓋16384個槽時集群停止服務,默認yes,一定要設置為no,否則集群可能因為某個節(jié)點宕機而停止服務。
daemonize yes                                             #指定是否以守護進程模式運行
logfile /usr/local/etc/redis/9000/redis.log               #指定保存日志的文件路徑

2. 集群管理
redis提供了一個管理集群的腳本工具:redis-trib.rb,需要提前安裝ruby和rubygems。

3. 集群建立
執(zhí)行命令啟動節(jié)點:

/usr/local/redis/bin/redis-server /usr/local/etc/redis/9000/redis.conf
/usr/local/redis/bin/redis-server /usr/local/etc/redis/9001/redis.conf
/usr/local/redis/bin/redis-server /usr/local/etc/redis/9002/redis.conf
/usr/local/redis/bin/redis-server /usr/local/etc/redis/9003/redis.conf
/usr/local/redis/bin/redis-server /usr/local/etc/redis/9004/redis.conf
/usr/local/redis/bin/redis-server /usr/local/etc/redis/9005/redis.conf

執(zhí)行完畢后可以用ps -aux | grep redis查看節(jié)點是否啟動成功,啟動成功后使用redis-trib.rb的create命令進行集群的創(chuàng)建:

./redis-trib.rb create --replicas 1 192.168.128.1:9000 192.168.128.1:9001 192.168.128.1:9002 192.168.128.1:9003 192.168.128.1:9004 192.168.128.1:9005

其中“--replicas”選項的作用是指定每個主節(jié)點需要一個從節(jié)點。看到“[OK] All 16384 solts covered”就表示集群搭建成功了。

4. 添加節(jié)點
復制兩份配置文件,然后根據(jù)對應的節(jié)點進行修改,修改完成后執(zhí)行:

/usr/local/redis/bin/redis-server /usr/local/etc/redis/9007/redis.conf
/usr/local/redis/bin/redis-server /usr/local/etc/redis/9008/redis.conf

啟動完畢后,使用redis-trib.rb的add-node命令可以把節(jié)點加入到集群中,一個作主節(jié)點,一個作從節(jié)點。

./redis-trib.rb add-node 192.168.128.1:9007 192.168.128.1:9008

上述命令以9007為主節(jié)點,9008為從節(jié)點添加到集群中,但要讓9008節(jié)點從屬于9007節(jié)點,我們必須添加9007節(jié)點的ID,在redis-cli中用cluster nodes命令可以查詢集群狀態(tài),得到類似"dd62920df907f18a290e4f6ff8d7f94832ccf993"這樣的ID,然后我們把上面的命令修改一下:

./redis-trib.rb add-node --slave --master -id dd62920df907f18a290e4f6ff8d7f94832ccf993 192.168.128.1:9007 192.168.128.1:9008

5. 數(shù)據(jù)遷移
上面的配置沒有為添加的節(jié)點分配任何的solt,所以新增的數(shù)據(jù)不會儲存在這個節(jié)點上。為了讓新增的節(jié)點分擔集群的儲存壓力,我們可以使用redis-trib.rb的reshard命令把集群的一部分solt遷移到新增的節(jié)點上:

./redis-trin.rb reshard 192.168.128.1:9000

回車之后需要我們輸入要遷移的solt個數(shù)和遷移的目標節(jié)點ID

6. 故障轉移
在redis集群中,某個主節(jié)點宕機不會導致整個集群停止服務,這是靠故障轉移來保證集群的高可用性。當某個主節(jié)點宕機,集群會從此節(jié)點的所有從節(jié)點選舉出一個節(jié)點你作為新的主節(jié)點。

六、代碼演示(PHP)

<?php
/**
 * Redis 操作,支持 Master/Slave 的負載集群
 */
class RedisCluster
{

    // 是否使用 M/S 的讀寫集群方案
    private $_isUseCluster = false;

    // Slave 句柄標記
    private $_sn = 0;

    // 服務器連接句柄
    private $_linkHandle = array(
        'master' => null, // 只支持一臺 Master

        'slave' => array(), // 可以有多臺 Slave
    );

    /**
     * 構造函數(shù)
     *
     * @param boolean $isUseCluster 是否采用 M/S 方案
     */
    public function __construct($isUseCluster = false)
    {
        $this->_isUseCluster = $isUseCluster;
    }

    /**
     * 連接服務器,注意:這里使用長連接,提高效率,但不會自動關閉
     *
     * @param array $config Redis服務器配置
     * @param boolean $isMaster 當前添加的服務器是否為 Master 服務器
     * @return boolean
     */
    public function connect($config = array('host' => '127.0.0.1', 'port' => 6379), $isMaster = true)
    {
        // default port
        if (!isset($config['port'])) {
            $config['port'] = 6379;
        }
        // 設置 Master 連接
        if ($isMaster) {
            $this->_linkHandle['master'] = new \Redis();
            $ret = $this->_linkHandle['master']->pconnect($config['host'], $config['port']);
        } else {
            // 多個 Slave 連接
            $this->_linkHandle['slave'][$this->_sn] = new Redis();
            $ret = $this->_linkHandle['slave'][$this->_sn]->pconnect($config['host'], $config['port']);
            ++$this->_sn;
        }
        return $ret;
    }

    /**
     * 關閉連接
     *
     * @param int $flag 關閉選擇 0:關閉 Master 1:關閉 Slave 2:關閉所有
     * @return boolean
     */
    public function close($flag = 2)
    { 
        switch ($flag) {
            // 關閉 Master
            case 0:
                $this->getRedis()->close();
                break;
            // 關閉 Slave
            case 1:
                for ($i = 0; $i < $this->_sn; ++$i) {
                    $this->_linkHandle['slave'][$i]->close();
                }
                break;
            // 關閉所有
            case 1:
                $this->getRedis()->close();
                for ($i = 0; $i < $this->_sn; ++$i) {
                    $this->_linkHandle['slave'][$i]->close();
                }
                break;
        }
        return true;
    }

    /**
     * 得到 Redis 原始對象可以有更多的操作
     *
     * @param boolean $isMaster 返回服務器的類型 true:返回Master false:返回Slave
     * @param boolean $slaveOne 返回的Slave選擇 true:負載均衡隨機返回一個Slave選擇 false:返回所有的Slave選擇
     * @return redis object
     */
    public function getRedis($isMaster = true, $slaveOne = true)
    {
        // 只返回 Master
        if ($isMaster) {
            return $this->_linkHandle['master'];
        } else {
            return $slaveOne ? $this->_getSlaveRedis() : $this->_linkHandle['slave'];
        }
    }

    /**
     * 寫緩存
     *
     * @param string $key 組存KEY
     * @param string $value 緩存值
     * @param int $expire 過期時間, 0:表示無過期時間
     */
    public function set($key, $value, $expire = 0)
    {
        // 永不超時
        if ($expire == 0) {
            $ret = $this->getRedis()->set($key, $value);
        } else {
            $ret = $this->getRedis()->setex($key, $expire, $value);
        }
        return $ret;
    }

    /**
     * 讀緩存
     *
     * @param string $key 緩存KEY,支持一次取多個 $key = array('key1','key2')
     * @return string || boolean  失敗返回 false, 成功返回字符串
     */
    public function get($key)
    {
        // 是否一次取多個值
        $func = is_array($key) ? 'mGet' : 'get';
        // 沒有使用M/S
        if (!$this->_isUseCluster) {
            return $this->getRedis()->{$func}($key);
        }
        // 使用了 M/S
        return $this->_getSlaveRedis()->{$func}($key);
    }

    /*
    // magic function
    public function __call($name,$arguments){
    return call_user_func($name,$arguments);
    }
     */
    /**
     * 條件形式設置緩存,如果 key 不存時就設置,存在時設置失敗
     *
     * @param string $key 緩存KEY
     * @param string $value 緩存值
     * @return boolean
     */
    public function setnx($key, $value)
    {
        return $this->getRedis()->setnx($key, $value);
    }

    /**
     * 刪除緩存
     *
     * @param string || array $key 緩存KEY,支持單個健:"key1" 或多個健:array('key1','key2')
     * @return int 刪除的健的數(shù)量
     */
    public function remove($key)
    {
        // $key => "key1" || array('key1','key2')
        return $this->getRedis()->delete($key);
    }

    /**
     * 值加加操作,類似 ++$i ,如果 key 不存在時自動設置為 0 后進行加加操作
     *
     * @param string $key 緩存KEY
     * @param int $default 操作時的默認值
     * @return int 操作后的值
     */
    public function incr($key, $default = 1)
    {
        if ($default == 1) {
            return $this->getRedis()->incr($key);
        } else {
            return $this->getRedis()->incrBy($key, $default);
        }
    }

    /**
     * 值減減操作,類似 --$i ,如果 key 不存在時自動設置為 0 后進行減減操作
     *
     * @param string $key 緩存KEY
     * @param int $default 操作時的默認值
     * @return int 操作后的值
     */
    public function decr($key, $default = 1)
    {
        if ($default == 1) {
            return $this->getRedis()->decr($key);
        } else {
            return $this->getRedis()->decrBy($key, $default);
        }
    }

    /**
     * 添空當前數(shù)據(jù)庫
     *
     * @return boolean
     */
    public function clear()
    {
        return $this->getRedis()->flushDB();
    }

    /* =================== 以下私有方法 =================== */

    /**
     * 隨機 HASH 得到 Redis Slave 服務器句柄
     *
     * @return redis object
     */
    private function _getSlaveRedis()
    {
        // 就一臺 Slave 機直接返回
        if ($this->_sn <= 1) {
            return $this->_linkHandle['slave'][0];
        }
        // 隨機 Hash 得到 Slave 的句柄
        $hash = $this->_hashId(mt_rand(), $this->_sn);
        return $this->_linkHandle['slave'][$hash];
    }

    /**
     * 根據(jù)ID得到 hash 后 0~m-1 之間的值
     *
     * @param string $id
     * @param int $m
     * @return int
     */
    private function _hashId($id, $m = 10)
    {
        //把字符串K轉換為 0~m-1 之間的一個值作為對應記錄的散列地址
        $k = md5($id);
        $l = strlen($k);
        $b = bin2hex($k);
        $h = 0;
        for ($i = 0; $i < $l; $i++) {
            //相加模式HASH
            $h += substr($b, $i * 2, 2);
        }
        $hash = ($h * 1) % $m;
        return $hash;
    }

    /**
     *    lpush
     */
    public function lpush($key, $value)
    {
        return $this->getRedis()->lpush($key, $value);
    }

    /**
     *    rpush
     */
    public function rpush($key, $value)
    {
        return $this->getRedis()->rpush($key, $value);
    }

    /**
     *    add lpop
     */
    public function lpop($key)
    {
        return $this->getRedis()->lpop($key);
    }

    /**
     *    add rpop
     */
    public function rpop($key)
    {
        return $this->getRedis()->rpop($key);
    }

    /**
     * lrange
     */
    public function lrange($key, $start, $end)
    {
        return $this->getRedis()->lrange($key, $start, $end);
    }

    /**
     * rrange
     */
    public function rrange($key, $start, $end)
    {
        return $this->getRedis()->rrange($key, $start, $end);
    }

    /**
     *    set hash opeation
     */
    public function hset($name, $key, $value)
    {
        if (is_array($value)) {
            return $this->getRedis()->hset($name, $key, serialize($value));
        }
        return $this->getRedis()->hset($name, $key, $value);
    }
    /**
     *    get hash opeation
     */
    public function hget($name, $key = null, $serialize = true)
    {
        if ($key) {
            $row = $this->getRedis()->hget($name, $key);
            if ($row && $serialize) {
                unserialize($row);
            }
            return $row;
        }
        return $this->getRedis()->hgetAll($name);
    }

    /**
     * delete hash opeation
     */
    public function hdel($name, $key = null)
    {
        if ($key) {
            return $this->getRedis()->hdel($name, $key);
        }
        return $this->getRedis()->hdel($name);
    }

    /**
     * Transaction start
     */
    public function multi()
    {
        return $this->getRedis()->multi();
    }

    /**
     * Transaction send
     */
    public function exec()
    {
        return $this->getRedis()->exec();
    }

    /** 集合操作 **/
    
    /*
    * 將一個元素加入集合,已經存在集合中的元素則忽略。
    * 若集合不存在則先創(chuàng)建,若key不是集合類型則返回false,若元素已存在返回0,插入成功返回1。
    */
    public function sAdd($key, $value)
    {
        return $this->getRedis()->sAdd($key, $value);
    }

    /*
    * 返回集合中所有成員。
    */
    public function sMembers($key)
    {
        return $this->getRedis()->sMembers($key);
    }

    /*
    * 判斷集合里是否存在指定元素,是返回true,否則返回false。
    */
    public function sismember($key, $value)
    {
        return $this->getRedis()->sismember($key, $value);
    }

    /*
    * 返回集合中元素的數(shù)量
    */
    public function scard($key)
    {
        return $this->getRedis()->scard($key);
    }

    /*
    * 隨機刪除并返回集合里的一個元素。
    */
    public function sPop($key)
    {
        return $this->getRedis()->sPop($key);
    }

    /*
    * 隨機返回(n)個集合內的元素,由第二個參數(shù)決定返回多少個
    * 如果 n 大于集合內元素的個數(shù)則返回整個集合
    * 如果 n 是負數(shù)時隨機返回 n 的絕對值,數(shù)組內的元素會重復出現(xiàn)
    */
    public function sRandMember($key, $n)
    {
        return $this->getRedis()->sRandMember($key, $n);
    }

    /*
    * 刪除集合中指定的一個元素,元素不存在返回0。刪除成功返回1,否則返回0。
    */
    public function srem($key, $value)
    {
        return $this->getRedis()->srem($key, $value);
    }

    /*
    * 模糊搜索相對的元素,
    * 參數(shù):key,迭代器變量,匹配值,每次返回元素數(shù)量(默認為10個)
    */
    public function sscan($key, $it, $n = 10)
    {
        // return $this->getRedis()->sscan($key, $it, 's*', $n);
    }
}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 目錄: 1 Redis初識 1.1 Redis介紹 1.2 Redis功能特性介紹 1.3 Redis...
    莎莎1990閱讀 815評論 0 2
  • 和Mysql主從復制的原因一樣,Redis雖然讀取寫入的速度都特別快,但是也會產生讀壓力特別大的情況。為了分擔讀壓...
    彳亍口巴閱讀 504評論 0 6
  • 一、Redis高可用概述 在介紹Redis高可用之前,先說明一下在Redis的語境中高可用的含義。 我們知道,在w...
    空語閱讀 1,681評論 0 2
  • 前言 在上一篇文章中,介紹了Redis內存模型,從這篇文章開始,將依次介紹Redis高可用相關的知識——持久化、復...
    Java架構閱讀 2,503評論 3 21
  • 一、Redis高可用概述 在介紹Redis高可用之前,先說明一下在Redis的語境中高可用的含義。 我們知道,在w...
    胸毛飄逸閱讀 316評論 0 2

友情鏈接更多精彩內容