卓仔 Redis 詳解

這是卓仔寫過的最長的文章了,幾乎把 redis 所有重要的內容都詳細的學習了。

包括 redis 快的原因、網絡 io 模型、數據結構、命令、持久化和高可用。

1

redis 是單線程的,爲什麼那麼快!

總體有 5 個原因:

  1. 採用單線程,避免了不必要的上下文切換和競爭條件,也不存在多進程或者多線程導致的切換而消耗 CPU,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有因爲可能出現死鎖而導致的性能消耗

  2. 使用多路 I/O 複用模型,非阻塞 IO

  3. 使用底層模型不同,它們之間底層實現方式以及與客戶端之間通信的應用協議不一樣,Redis 直接自己構建了 VM 機制 ,因爲一般的系統調用系統函數的話,會浪費一定的時間去移動和請求

6)redis 是用 C 語言寫的,本來就直接跟操作系統交互,命令執行快得飛起

2

線程模型

這個非常重要:

Redis 基於 Reactor 模式開發了自己的網絡事件處理器——文件事件處理器,

1)文件事件處理器

文件事件處理器使用 I/O 多路複用程序來同時監聽多個 socket,並根據 socket 目前執行的任務來爲 socket 關聯不同的事件處理器。

當被監聽的 socket 準備好執行連接應答、讀取、寫入、關閉等操作時,與操作相對應的文件事件就會產生,這時文件事件處理器就會調用 socket 之前已關聯好的事件處理器來處理這些事件。

這個文件事件處理器,是單線程的,redis 才叫做單線程的模型.

文件事件處理器的結構包含 4 個部分:多個 socket,IO 多路複用程序,文件事件分派器,事件處理器(命令請求處理器、命令回覆處理器、連接應答處理器,等等)。

多個 socket 可能併發的產生不同的操作,每個操作對應不同的文件事件,但是 IO 多路複用程序會監聽多個 socket,但是會將 socket 放入一個隊列中排隊,每次從隊列中取出一個 socket 給事件分派器,事件分派器把 socket 給對應的事件處理器。

然後一個 socket 的事件處理完之後,IO 多路複用程序纔會將隊列中的下一個 socket 給事件分派器。文件事件分派器會根據每個 socket 當前產生的事件,來選擇對應的事件處理器來處理。

2)文件事件

當 socket 變得可讀時(比如客戶端對 redis 執行 write 操作,或者 close 操作),或者有新的可以應答的 sccket 出現時(客戶端對 redis 執行 connect 操作),socket 就會產生一個 AE_READABLE 事件。

當 socket 變得可寫的時候(客戶端對 redis 執行 read 操作),socket 會產生一個 AE_WRITABLE 事件。

IO 多路複用程序可以同時監聽 AE_REABLE 和 AE_WRITABLE 兩種事件,要是一個 socket 同時產生了 AE_READABLE 和 AE_WRITABLE 兩種事件,那麼文件事件分派器優先處理 AE_REABLE 事件,然後纔是 AE_WRITABLE 事件。

3)文件事件處理器

如果是客戶端要連接 redis,那麼會爲 socket 關聯連接應答處理器

如果是客戶端要寫數據到 redis,那麼會爲 socket 關聯命令請求處理器

如果是客戶端要從 redis 讀數據,那麼會爲 socket 關聯命令回覆處理器

4)客戶端與 redis 通信的一次流程

流程圖:

處理過程可以分爲以下幾個步驟:

**4)**總結:

所以文件事件處理器有 4 個部分:

多個 socket,IO 多路複用程序,文件事件分派器,事件處理器

socket 會產生不同的事件(AE_REABLE 和 AE_WRITABLE)。

IO 多路複用程序的作用是把監聽並把請求 socket 放入隊列。

文件事件分派器的作用是從隊列取出 socket,根據不同的事件分配給不同的事件處理器處理(應答處理器、命令請求處理器、命令回覆處理器)。

再和之前的 reactor 模式進行對比學習:

先回顧下 reactor 模式:

reactor 模式有 3 個部分:reactor、acceptor 和 handler (selector 多路複用)。

reactor 的作用是先註冊一個 acceptor,然後持續遍歷 selector(多路複用程序),也就是執行 acceptor 和 handler。

acceptor 的作用就是爲每一個連接創建具體處理 IO 請求的 Handler,並註冊到 selector.

handler 的作用就是接收處理每個 socket 的讀寫請求。

對比:

所以 selector 就是多路複用程序。reactor 對應的就是文件事件分派器。

acceptor 和 Handler 分別對應的是應答處理器(acceptor) 和命令請求處理器、命令回覆處理器(Handler)。

問題:

1、爲什麼不採用多進程或多線程處理?

  1. 多線程處理可能涉及到鎖

  2. 多線程處理會涉及到線程切換而消耗 CPU

2、單線程處理的缺點?

  1. 耗時的命令會導致併發的下降,不只是讀併發,寫併發也會下降

  2. 無法發揮多核 CPU 性能,不過可以通過在單機開多個 Redis 實例來完善

3

數據結構!

redis 主要提供了 5 種數據結構:字符串 (String)、哈希 (hash)、列表 (list)、集合 (set)、有序集合 (short set)。

1)字符串 (String)

簡單動態字符串(SDS)

結構

struct sdshdr{
     //記錄buf數組中已使用字節的數量
     //等於 SDS 保存字符串的長度
     int len;
     //記錄 buf 數組中未使用字節的數量
     int free;
     //字節數組,用於保存字符串
     char buf[];
}

1、len 保存了 SDS 保存字符串的長度

2、buf[] 數組用來保存字符串的每個元素

3、free 記錄了 buf 數組中未使用的字節數量

優點:

命令:

  1. 設置值 :set key value

  2. 獲取值:get key

  3. 批量設置值:mset key value

  4. 批量獲取值:mget key

  5. 計數 :incr key
    除了有 incr 自增命令外,Redis 中還提供了其它對數字處理的命令。例如:
    decr key 自減
    incrby key increment 自增指定數字
    decrby key decrement 自減指定數字
    incrbyfloat key increment 自增浮點數

  6. 追加值:append key value
    append 命令可以向字符串尾部追加值。

  7. 字符串長度:strlen key
    注意:每個中文佔用 3 個字節。

  8. 設置並返回原值:getset key value

  9. 設置指定位置的字符:setrange key offeset value

  10. 獲取部分字符串:getrange key start end

2)字典(hash)

字典又稱爲符號表或者關聯數組、或映射(map),是一種用於保存鍵值對的抽象數據結構。字典中的每一個鍵 key 都是唯一的,通過 key 可以對值來進行查找或修改。C 語言中沒有內置這種數據結構的實現,所以字典依然是 Redis 自己構建的。

結構

typedef struct dictht{
     //哈希表數組
     dictEntry **table;
     //哈希表大小
     unsigned long size;
     //哈希表大小掩碼,用於計算索引值
     //總是等於 size-1
     unsigned long sizemask;
     //該哈希表已有節點的數量
     unsigned long used;
}dictht

哈希表是由數組 table 組成,table 中每個元素都是指向 dict.h/dictEntry 結構,dictEntry 結構定義如下:

typedef struct dictEntry{
     //鍵
     void *key;
     //值
     union{
          void *val;
          uint64_tu64;
          int64_ts64;
     }v;
     //指向下一個哈希表節點,形成鏈表
     struct dictEntry *next;
}dictEntry

這裏可以參考 java 1.7 的 hashmap 原理,之前文章學習過。

哈希衝突和擴容和收縮和 java1.7 都差不多

命令:

  1. 設置值:hset key field value

  2. 獲取值:hget key field

  3. 刪除 field :hdel key field [field ...]

  4. 計算 field 個數:hlen key

  5. 批量設置或獲取 field-value:
    hmget key field [field ...]
    hmset key field value [field value ...]

  6. 判斷 field 是否存在:hexists key field

  7. 獲取所有 field:hkeys key

  8. 獲取所有 value:hvals key

  9. 獲取所有的 field-value:hgetall key

  10. 計數
    hincrby key field increment
    hincrbyfloat key field increment

hincrby 命令和 incrby 命令的使用功能基本一樣,都是對值進行增量操作的,唯一不同的就是 incrby 命令的作用域是 key,而 hincrby 命令的作用域則是 field。

  1. 計算 value 的字符串長度:hstrlen key field

3)列表 (list)

主要 redis 的列表 底層是雙向鏈表:

結構:

鏈表定義:

typedef  struct listNode{
       //前置節點
       struct listNode *prev;
       //後置節點
       struct listNode *next;
       //節點的值
       void *value;  
}listNode

通過多個 listNode 結構就可以組成鏈表,這是一個雙向鏈表,Redis 還提供了操作鏈表的數據結構:

typedef struct list{
     //表頭節點
     listNode *head;
     //表尾節點
     listNode *tail;
     //鏈表所包含的節點數量
     unsigned long len;
     //節點值複製函數
     void (*free) (void *ptr);
     //節點值釋放函數
     void (*free) (void *ptr);
     //節點值對比函數
     int (*match) (void *ptr,void *key);
}list;

Redis 鏈表特性:

  1、雙端:鏈表具有前置節點和後置節點的引用,獲取這兩個節點時間複雜度都爲 O(1)。

  2、無環:表頭節點的 prev 指針和表尾節點的 next 指針都指向 NULL, 對鏈表的訪問都是以 NULL 結束。  

  3、帶鏈表長度計數器:通過 len 屬性獲取鏈表長度的時間複雜度爲 O(1)。

  4、多態:鏈表節點使用 void* 指針來保存節點值,可以保存各種不同類型的值。

命令

  1. 添加操作:

從右邊插入元素
rpush key value [value ...]

從左邊插入元素
lpush key value [value ...]

向某個元素前或者後插入元素
linsert key BEFORE|AFTER pivot value

linsert 命令在執行的時候首先會從當前列表中查找到 pivot 元素,其次再將這個新元素插入到 pivot 元素的前面或者後面。linsert 命令在執行成功後也是會有返回值的,返回的結果就是當前列表中元素的個數。

  1. 查找

獲取指定範圍內的元素列表
lrange key start stop

lrange 命令會獲取列表中指定索引範圍的所有元素。

通過索引獲取列表主要有兩個特點:
索引下標從左到右分別是 0 到 N-1,從右到左是 -1 到 -N。
lrange 命令中的 stop 參數在執行時會包括當前元素,並不是所有的語言都是這樣的。

獲取列表中指定索引下標的元素:lindex key index

獲取列表長度:llen key

  1. 刪除

從列表左側彈出元素 lpop key

lpop 命令執行成功後會返回當前被刪除的元素名稱。

從列表右側彈出元素 rpop key

刪除指定元素:lrem key count value

lrem 命令會將列表中等於 value 的元素刪除掉,並且會根據 count 參數來決定刪除 value 的元素個數。

按照索引範圍修剪列表:ltrim key start stop

  1. 修改

修改指定索引下標的元素:lset key index value

4)集合 (set)、

set 集合有 2 中儲存方式:

intset(整數集合):當集合中的元素都是整數,並且集合中的元素個數小於 512 個時,Redis 會選用 intset 作爲底層內部實現。

hashtable(哈希表):當上述條件不滿足時,Redis 會採用 hashtable 作爲底層實現。

當元素個數較少並且都是整數時,內部編碼爲 intset。

當元素不全是整數時,內部編碼爲 hashtable。

當元素個數超過 512 個時,內部編碼爲 hashtable。

intset 結構:

typedef struct intset{
     //編碼方式
     uint32_t encoding;
     //集合包含的元素數量
     uint32_t length;
     //保存元素的數組
     int8_t contents[];
}intset;

命令:

添加元素:sadd key member [member ...]

刪除元素:srem key member [member ...]

計算元素個數:scard key

判讀元素是否在集合中:sismember key member

隨機從 set 中返回指定個數元素:srandmember key [count]

從集合中隨機彈出元素:spop key [count]

獲取所有元素:smembers key

5)有序集合 (short set)

有序集合也是一種集合,並且這個集合還是有序的。列表也是有序的,那它和有序集合又有什麼不同呢?

有序集合的有序和列表的有序是不同的。列表中的有序指的的是插入元素的順序和查詢元素的順序相同,而有序集合中的有序指的是它會爲每個元素設置一個分數 (score),而查詢時可以通過分數計算元素的排名,然後再返回結果。

因爲有序集合也是集合類型,所以有序集合中也是不插入重複元素的,但在有序集合中分數則是可以重複,那如果在有序集合中有多個元素的分數是相同的。

底層採用跳躍表實現。

跳錶與 AVL、紅黑樹... 等相比,數據結構簡單,算法易懂,但查詢的時間複雜度與平衡二叉樹 / 紅黑樹相當

跳躍表(skiplist)是一種有序數據結構,它通過在每個節點中維持多個指向其它節點的指針,從而達到快速訪問節點的目的。具有如下性質:

  1、由很多層結構組成;

  2、每一層都是一個有序的鏈表,排列順序爲由高層到底層,都至少包含兩個鏈表節點,分別是前面的 head 節點和後面的 nil 節點;

  3、最底層的鏈表包含了所有的元素;

  4、如果一個元素出現在某一層的鏈表中,那麼在該層之下的鏈表也全都會出現(上一層的元素是當前層的元素的子集);

  5、鏈表中的每個節點都包含兩個指針,一個指向同一層的下一個鏈表節點,另一個指向下一層的同一個鏈表節點;

  

  1. 搜索:從最高層的鏈表節點開始,如果比當前節點要大和比當前層的下一個節點要小,那麼則往下找,也就是和當前層的下一層的節點的下一個節點進行比較,以此類推,一直找到最底層的最後一個節點,如果找到則返回,反之則返回空。

  2. 插入:首先確定插入的層數,有一種方法是假設拋一枚硬幣,如果是正面就累加,直到遇見反面爲止,最後記錄正面的次數作爲插入的層數。當確定插入的層數 k 後,則需要將新元素插入到從底層到 k 層。

  3. 刪除:在各個層中找到包含指定值的節點,然後將節點從鏈表中刪除即可,如果刪除以後只剩下頭尾兩個節點,則刪除這一層。

**命令
**

添加元素:zadd key [NX|XX] [CH] [INCR] score member [score member ...]

計算成員個數:zcard key

計算某個成員的分數:zscore key member

計算成員的排名
zrank key member
zrevrank key member

刪除元素
zrem key member [member ...]

返回的結果爲成功刪除元素的個數,因爲 zrem 命令是支持批量刪除的。

增加元素分數:zincrby key increment member

返回指定排名範圍的元素
zrange key start stop [WITHSCORES]
zrevrange key start stop [WITHSCORES]

返回指定分數範圍的元素
zrangebyscore key min max [WITHSCORES] [LIMIT offset count]
zrevrangebyscore key max min [WITHSCORES] [LIMIT offset count]

返回指定分數範圍元素個數:zcount key min max

刪除指定排名內的升序元素:zremrangebyrank key start stop

刪除指定分數範圍元素:zremrangebyscore key min max

4

持久化!

redis 是一個內存數據庫,數據保存在內存中,但是我們都知道內存的數據變化是很快的,也容易發生丟失。

Redis 還爲我們提供了持久化的機制,分別是 RDB(Redis DataBase) 和 AOF(Append Only File)。

1、持久化流程

要有下面五個過程:

(1)客戶端向服務端發送寫操作 (數據在客戶端的內存中)。

(2)數據庫服務端接收到寫請求的數據 (數據在服務端的內存中)。

(3)服務端調用 write 這個系統調用,將數據往磁盤上寫 (數據在系統內存的緩衝區中)。

(4)操作系統將緩衝區中的數據轉移到磁盤控制器上 (數據在磁盤緩存中)。

(5)磁盤控制器將數據寫到磁盤的物理介質中 (數據真正落到磁盤上

redis 提供了兩種持久化策略機制,也就是 RDB 和 AOF。

2、RDB

RDB 其實就是把數據以快照的形式保存在磁盤上。什麼是快照呢,你可以理解成把當前時刻的數據拍成一張照片保存下來。

RDB 持久化是指在指定的時間間隔內將內存中的數據集快照寫入磁盤。也是默認的持久化方式,這種方式是就是將內存中數據以快照的方式寫入到二進制文件中, 默認的文件名爲 dump.rdb。

優勢

(1)RDB 文件緊湊,全量備份,非常適合用於進行備份和災難恢復。

(2)生成 RDB 文件的時候,redis 主進程會 fork() 一個子進程來處理所有保存工作,主進程不需要進行任何磁盤 IO 操作。

(3)RDB 在恢復大數據集時的速度比 AOF 的恢復速度要快。

劣勢

RDB 快照是一次全量備份,存儲的是內存數據的二進制序列化形式,存儲上非常緊湊。當進行快照持久化時,會開啓一個子進程專門負責快照持久化,子進程會擁有父進程的內存數據,父進程修改內存子進程不會反應出來,所以在快照持久化期間修改的數據不會被保存,可能丟失數據。

3.AOF 機制

全量備份總是耗時的,有時候我們提供一種更加高效的方式 AOF,工作機制很簡單,redis 會將每一個收到的寫命令都通過 write 函數追加到文件中。通俗的理解就是日誌記錄。

持久化原理

他的原理看下面這張圖:

每當有一個寫命令過來時,就直接保存在我們的 AOF 文件中。

Redis 會將每一個收到的寫命令都通過 write 函數追加到文件中(默認是 appendonly.aof 文件)

當然由於 OS 會在內核中緩存 write 做的修改,所以可能不是立即寫到磁盤上。

這樣 AOF 方式的持久化也還是有可能會丟失部分修改,不過我們可以通過配置文件告訴 Redis 我們想要通過 fsync 函數強制 OS 寫入到磁盤的時機(默認是:每秒 fsync 一次),有如下三種方式:

1)appendfsync always 每次收到寫命令就立即強制寫入磁盤,效率最低,但可保證完全的持久化,不推薦使用

2)apendfsync everysec 每秒鐘強制寫入磁盤一次,在性能和持久化方面做了很好的折中,推薦使用這個

3)appendfsync no 完全依賴 OS,性能最好,持久化沒保證

AOF 默認的是文件的無限追加,這樣的話持久化文件會變得越來越大。

例如我們調用 incr test 命令 100 次,文件中必須保存全部的 100 條命令,其實有 99 條都是多餘的。因爲要恢復數據庫的狀態其實文件中保存一條 set test 100 就夠了。

爲了壓縮 AOF 的持久化文件。Redis 提供了 bgrewriteaof 命令。收到此命令 Redis 將使用與快照類似的方式將內存中的數據以命令的方式保存到臨時文件中,最後替換原來的文件。

優點:

(1)AOF 可以更好的保護數據不丟失,可以設置不同的 fsync 策略,比如無 fsync ,每秒鐘一次 fsync ,或者每次執行寫入命令時 fsync 。

AOF 的默認策略爲每秒鐘 fsync 一次,在這種配置下,Redis 仍然可以保持良好的性能,並且就算髮生故障停機,也最多隻會丟失一秒鐘的數據。

fsync 會在後臺線程執行,所以主線程可以繼續努力地處理命令請求。

(2)AOF 文件是一個只進行追加操作的日誌文件(append only log), 因此對 aof 文件的寫入不需要進行 seek。有點像 kafka 的順序讀寫,和內存速度差不多。

(3)AOF 日誌文件即使過大的時候,出現後臺重寫操作,也不會影響客戶端的讀寫。

(4)AOF 日誌文件的命令通過非常可讀的方式進行記錄,這個特性非常適合做災難性的誤刪除的緊急恢復。比如某人不小心用 flushall 命令清空了所有數據,只要這個時候後臺 rewrite 還沒有發生,那麼就可以立即拷貝 AOF 文件,將最後一條 flushall 命令給刪了,然後再將該 AOF 文件放回去,就可以通過恢復機制,自動恢復所有數據

缺點

(1)對於同一份數據來說,AOF 日誌文件通常比 RDB 數據快照文件更大

(2)AOF 開啓後,支持的寫 QPS 會比 RDB 支持的寫 QPS 低,因爲 AOF 一般會配置成每秒 fsync 一次日誌文件,當然,每秒一次 fsync,性能也還是很高的

4. 對比:

5

高可用!

redis 高可用有 2 種方式: 

哨兵模式和集羣模式:

哨兵模式:

哨兵的作用就是監控 Redis 系統的運行狀況。它的功能包括以下兩個。

監控主數據庫和從數據庫是否正常運行。

主數據庫出現故障時自動將從數據庫轉換爲主數據庫。

sentinel 發現 master 掛了後,就會從 slave 中重新選舉一個 master。

哨兵模式強調高可用

Sentinel 系統用於管理多個 Redis 服務器(instance), 該系統執行以下三個任務:

監控(Monitoring):Sentinel 會不斷地檢查你的主服務器和從服務器是否運作正常。

提醒(Notification):當被監控的某個 Redis 服務器出現問題時, Sentinel 可以通過 API 向管理員或者其他應用程序發送通知。

自動故障遷移(Automatic failover):當一個主服務器不能正常工作時, Sentinel 會開始一次自動故障遷移操作, 它會將失效主服務器的其中一個從服務器升級爲新的主服務器, 並讓失效主服務器的其他從服務器改爲複製新的主服務器;當客戶端試圖連接失效的主服務器時, 集羣也會向客戶端返回新主服務器的地址, 使得集羣可以使用新主服務器代替失效服務器。

客戶端中不會記錄 redis 的地址(某個 IP),而是記錄 sentinel 的地址,這樣我們可以直接從 sentinel 獲取的 redis 地址,因爲 sentinel 會對所有的 master、slave 進行監控,它是知道到底誰纔是真正的 master 的,例如我們故障轉移,這時候對於 sentinel 來說,master 是變了的,然後通知客戶端。而客戶端根本不用關心到底誰纔是真正的 master,只關心 sentinel 告知的 master。

集羣模式

即使使用哨兵,redis 每個實例也是全量存儲,每個 redis 存儲的內容都是完整的數據,浪費內存且有木桶效應。爲了最大化利用內存,可以採用集羣,就是分佈式存儲。即每臺 redis 存儲不同的內容,共有 16384 個 slot。每個 redis 分得一些 slot,hash_slot = crc16(key) mod 16384 找到對應 slot,鍵是可用鍵,如果有 {} 則取 {} 內的作爲可用鍵,否則整個鍵是可用鍵

Redis 中的集羣分爲主節點和從節點。其中主節點用於處理槽;而從節點用於複製某個主節點,並在被複制的主節點下線時,代替下線的主節點繼續處理命令請求。

集羣至少需要 3 主 3 從,且每個實例使用不同的配置文件,主從不用配置,集羣會自己選。

cluster 是爲了解決單機 Redis 容量有限的問題,將數據按一定的規則分配到多臺機器。

集羣模式提高併發量。

6

緩存問題!

緩存穿透、緩存雪崩、緩存擊穿

1)緩存穿透是指查詢一個一定不存在的數據。由於緩存命不中時會去查詢數據庫,查不到數據則不寫入緩存,這將導致這個不存在的數據每次請求都要到數據庫去查詢,造成緩存穿透。

解決方案:

 是將空對象也緩存起來,並給它設置一個很短的過期時間,最長不超過 5 分鐘

採用布隆過濾器,將所有可能存在的數據哈希到一個足夠大的 bitmap 中,一個一定不存在的數據會被這個 bitmap 攔截掉,從而避免了對底層存儲系統的查詢壓力

2)如果緩存集中在一段時間內失效,發生大量的緩存穿透,所有的查詢都落在數據庫上,就會造成緩存雪崩。

解決方案:

儘量讓失效的時間點不分佈在同一個時間點

3)緩存擊穿,是指一個 key 非常熱點,在不停的扛着大併發,當這個 key 在失效的瞬間,持續的大併發就穿破緩存,直接請求數據庫,就像在一個屏障上鑿開了一個洞。

解決方案:

可以設置 key 永不過期

7

總結!

學習組件不僅僅要學習它的用法和原理,還要分析它的優點,學習它的設計理念。

所以總結一下,爲什麼 redis 的性能如此優秀?

首先從分別從網絡 io 和存儲方式 2 個方面。

網絡 io 中,redis 自己實現了 reactor 模型(epoll),可以說是目前性能最好的網絡 io 模型了。

存儲採用 內存(肯定快)+ 高效的數據結構(比如說跳躍表)

說到內存存儲肯定要涉及到持久化,持久化 redis 採用 快照方式(全量存儲)RDB 或 存儲命令 AOF 的方式。

但是單線程方式雖然可以避免鎖和線程切換的問題。 但併發缺無法保證,

還有就是可靠性也無法保證,(如果掛了怎麼快速恢復和數據過大時需要分散數據)

所以還需要採用集羣的方式(幾乎所有的組件都有集羣方式), 

redis 有兩種集羣方式,哨兵模式和集羣模式,

哨兵模式只是監控主從節點,主節點掛掉立即切換從節點。 但每個節點還要存儲所有數據,所以無法保證併發性和數據分散。

集羣模式就可以把數據分散到不同的節點,同時保證了併發性和數據分散。

在和 mysql 對比一下:

redis 很難做到事物, 目前採用 lua 腳本方式(卓仔不太會)。

集羣方面 redis 的

哨兵模式像 mysql 的主從備份方式,

集羣模式有點像 mysql 的水平拆分(分表)。

參考文章:

https://www.jianshu.com/p/1f380ce18254

https://www.jianshu.com/p/b13968924503

http://www.freeoa.net/osuport/db/redis-data-structure_3278.html

https://www.cnblogs.com/ysocean/p/9080942.html

https://baijiahao.baidu.com/s?id=1654694618189745916&wfr=spider&for=pc

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/vhanAu9XboV98-c5aTLcaA