【大廠面試】面試官看了讚不絕口的Redis筆記(三)分佈式篇

說明

因爲內容太多了,CSDN編輯器不允許我在一篇文章上發揮。這是頭兩篇。

介紹了Redis單機的方方面面

傳送門:【大廠面試】面試官看了讚不絕口的Redis筆記
目錄:
在這裏插入圖片描述
傳送門:【大廠面試】面試官看了讚不絕口的Redis筆記(二)
目錄:
在這裏插入圖片描述

下面我們步入分佈式領域

六、Redis複製的原理與優化

(一)Redis單機的問題存在三方面的問題

(1)機器故障

在一臺服務器上部署一個Redis節點,如果機器發生主板損壞,硬盤損壞等問題,不能在短時間修復完成,就不能處理Redis操作了,這會帶來很大的麻煩。
但是即使服務器正常運行,Redis主進程也有可能發生宕機事件,一般重啓Redis就可以。如果不考慮在Redis重啓期間的性能損失,可以考慮Redis的單機部署。如果你想解決這種問題,可以考慮Redis分佈式部署。

(2)容量瓶頸

一臺服務器有16G內存,此時分配12G內存運行Redis

如果有新需求:Redis需要佔用32G或者64G等更多的內存,此時這臺服務器就不能滿足需求了,此時可以考慮更換一臺更大內存的服務器,越大型的服務器,價格也就越高。分佈式允許多臺服務器組成一個Redis集羣來滿足這個需求。

(3)QPS瓶頸
根據Redis官方的說法,單臺Redis可以支持10萬的QPS,如果現在的業務需要100萬的QPS,此時可以考慮使用Redis分佈式,提高性能。

這樣就引出了下面的主角 – 主從複製

(二)主從複製(主從同步)

在瞭解 Redis 的主從複製之前,你需要一點分佈式的理論基礎 【分佈式】關於分佈式“一致性”的討論,這篇文章因爲轉載內容過多,設置爲轉載了,算是我整合的一篇文章。

你要是想能有更加體系化的學習分佈式,可以看這本書。放心zookeeper對於大多數開發者而言,都是需要掌握的。
在這裏插入圖片描述

1.主從複製的模型:

(1)一主一從模型

一個Redis節點爲master節點(主節點),負責對外提供服務。另一個節點爲slave節點(從節點),負責同步主節點的數據,以達到備份的效果。

當主節點發生宕機等故障時,從節點也可以對外提供服務

如下圖所示
在這裏插入圖片描述
(2)一主多從模型

一個Redis節點爲master節點(主節點),負責對外提供服務。多個節點爲slave節點(從節點),每個slave都會對主節點中的數據進行備份,以達到更加高可用的效果。

這種情況下就算master和一個slave同時發生宕機故障,其餘的slave仍然可以對外讀提供服務,並保證數據不會丟失

當master有很多讀寫,達到Redis的極限閥值,可以使用多個slave節點對Redis的讀操作進行分流,有效實現流量的分流和負載均衡,所以一主多從也可以做讀寫分離(master節點負責寫數據,同時客戶端可以從slave節點讀取數據)

在這裏插入圖片描述

主從複製作用:對數據提供了多個備份,這些備份數據可以大大提高Redis的讀性能,是Redis高可用或者分佈式的基礎

3.主從複製的配置
有兩種方式,一種是命令行,一種是配置文件。

(1)命令行
slaved命令
在這裏插入圖片描述
取消複製
在這裏插入圖片描述
(2)配置文件配置
修改Redis配置文件/etc/redis.conf

slaveof <masterip> <masterport>         # masterip爲主節點IP地址,masterport爲主節點端口
slave-read-only yes                     # 從節點只做讀操作,不做寫操作,保證主從設備數據相同

(3)兩種主從配置方式比較

  • 使用命令行配置無需重啓Redis,可以實現統一配置
  • 使用配置文件方式配置不變於管理,而且需要重啓Redis

(三)全量複製和部分複製

(一)兩個概念

1.run_id的概念

Redis每次啓動時,都有一個隨機ID來標識Redis,這個隨機ID就是上面通過info命令查看得到的run_id
查看192.168.81.101虛擬機上的run_id和偏移量

[root@localhost ~]# redis-cli info server |grep run_id
run_id:7e366f6029d3525177392e98604ceb5195980518
[root@localhost ~]# redis-cli info |grep master_repl_offset
master_repl_offset:0

查看192.168.91.100虛擬機上的run_id和偏移量

[root@lalalala ~]# redis-cli info server | grep run_id
run_id:7091f874c7c3eeadae873d3e6704e67637d8772b
[root@lalalala ~]# redis-cli info | grep master_repl_offset
master_repl_offset:4483

在上面的例子裏,192.168.81.101作爲slave去複製192.168.81.100這個master上的數據,會先獲取192.168.81.100機器上對應的run_id,並在192.168.81.101上做一個標識

當192.168.81.100機器上的Redis的run_id發生改變,意味着192.168.81.100機器上的Redis發生重啓操作或者別的重大變化,192.168.81.101就會把192.168.81.100上的數據全部同步到192.168.81.101上,這就是全量複製的概念

2.offset的概念

偏移量(offset)就是數據寫入量的字節數。

在192.168.81.100的Redis上寫入數據時,master就會記錄寫了多少數據,並記錄在偏移量中。

在192.168.81.100上的操作,會同步到192.168.81.101機器上,192.168.81.101上的Redis也會記錄偏移量。

當兩臺機器上的偏移量相同時,代表數據同步完成

偏移量是部分複製很重要的依據

查看192.168.81.100機器上Redis的偏移量

127.0.0.1:6379> info replication    # 查看複製信息
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.81.101,port=6379,state=online,offset=8602,lag=0
master_repl_offset:8602             # 此時192.168.81.100上的偏移量是8602
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:8601
127.0.0.1:6379> set k1 v1           # 向192.168.81.100寫入數據
OK
127.0.0.1:6379> set k2 v2           # 向192.168.81.100寫入數據
OK
127.0.0.1:6379> set k3 v3           # 向192.168.81.100寫入數據
OK
127.0.0.1:6379> info replication    # 查看複製信息
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.81.101,port=6379,state=online,offset=8759,lag=1
master_repl_offset:8759             # 寫入數據後192.168.81.100上的偏移量是8759
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:8758

查看192.168.81.101機器上Redis的偏移量

127.0.0.1:6379> info replication    # 查看複製信息
# Replication
role:slave
master_host:192.168.81.100
master_port:6379
master_link_status:up
master_last_io_seconds_ago:8
master_sync_in_progress:0
slave_repl_offset:8602
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0                # 此時192.168.81.101上的偏移量是8602
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379> get k3
"v3"
127.0.0.1:6379> info replication    # 查看複製信息
# Replication
role:slave
master_host:192.168.81.100
master_port:6379
master_link_status:up
master_last_io_seconds_ago:7
master_sync_in_progress:0
slave_repl_offset:8759              # 同步數據後192.168.81.101上的偏移量是8759
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

如果主從節點上的offset差距太大,說明從節點沒有從主節點同步數據,主從節點之間的連接出現問題:比如網絡,阻塞,緩衝區等

(二)全量複製

如果一個主節點上已經寫入很多數據,此時從節點不僅同步已經有的數據,同時同步slave在同步期間master上被寫入的數據(如果在同步期間master被寫入數據),以達到數據完全同步的目的,這就是Redis的全量複製的功能。

Redis的master會把當前的RDB文件同步給slave, 在此期間master中寫入的數據會被寫入複製緩衝區(repl_back_buffer)中,當RDB文件同步到slave完成,master通過偏移量的對比,把複製緩衝區(repl_back_buffer)中的數據同步給slave。

Redis使用psync命令進行數據全量複製和部分複製

psync命令有兩個參數:run_id和偏移量

psync命令的步驟:

  1. 在slave第一次向master同步數據時,不知道master的run_id和offset,使用psync ? -1命令向master發起同步請求
  2. master接受請求後,知道slave是做全量複製,master就會把run_id和offset響應給slave
  3. slave保存master發送過來的run_id和offset
  4. master響應slave後,執行BGSAVE命令把當前所有數據生成RDB文件,然後將RDB文件同步給slave
  5. Redis中的repl_back_buffer複製緩衝區可以記錄生成RDB文件之後到同步完成這個時間段時寫入的數據,然後把這些數據也同步給slave
  6. slave執行flushall命令清空slave中原有的數據,然後從RDB文件讀取所有的數據,保證slave與master中數據的同步

可以用下圖表示:
在這裏插入圖片描述
全量複製的開銷非常大

  • master執行BGSAVE命令會消耗一定時間
  • BGSAVE命令會fork子進程,對CPU,內存和硬盤都有一個消耗
  • master將RDB文件傳輸給slave的時間,傳輸過程中也會佔用一定的網絡帶寬
  • slave清除原有數據的時間,如果slave中原有數據比較多,清空原有數據也會消耗一定的時間
  • slave加載RDB文件會消耗一定時間
  • 可能的AOF文件重寫的時間:RDB文件加載完成,如果slave節點的AOF功能開啓,則會執行AOF重寫操作,保證AOF文件中保存最新的數據

除了上面提到的開銷,如果master和slave之間的網絡出現問題,則在一段時間內slave上同步的數據就會丟失。解決這個問題的最好辦法就是再做一次全量複製,同步master中所有數據。Redis 2.8版本中添加了部分複製的功能,如果發生master和slave之間的網絡出現問題時,使用部分複製儘可能的減少丟失數據的可能,而不用全部複製。

(三)部分複製

當master與slave之間的連接斷開時,master在寫入數據同時也會把寫入的數據保存到repl_back_buffer複製緩衝區中。

當master與slave之間的網絡連通後,slave會執行psync {offset} {run_id}命令,offset是slave節點上的偏移量。master接收到slave傳輸的偏移量,會與repl_back_buffer複製緩衝區中的offset做對比,如果接收到的offset小於repl_back_buffer中記錄的偏移量,master就會把兩個偏移量之間的數據發送給slave,slave同步完成,slave中的數據就與master中的數據一致。

可以用下圖表示:
在這裏插入圖片描述
(四)主從複製故障

(1) slave宕機

處理方法是 將客戶端交互的那個失效的salve 改成正常運行的salve。不過要考慮 這個正常的salve 能否承受這麼大的壓力
在這裏插入圖片描述

(2)master宕掉

Redis的master就無法提供服務了,只有slave可以提供數據讀取服務

解決方法:把其中一個slave爲成master,以提供寫入數據功能,另外一臺slave重新做爲新的master的從節點,提供讀取數據功能,這種解決方法依然需要手動完成。
在這裏插入圖片描述
在這裏插入圖片描述

主從模式沒有實現故障的自動轉移,這就引出了Redis的sentinel(哨兵)了。

(四)開發中可能遇到的問題

4 - 1讀寫分離問題

讀寫分離:master負責寫入數據,把讀取數據的流量分攤到slave節點。讀寫分離一方面可以減輕master的壓力,另一方面又擴展了讀取數據的能力
在這裏插入圖片描述
但是讀寫分離可能遇到以下問題:

(1).複製數據延遲

大多數情況下,master採用異步方式將數據同步給slave,在這個過程中會有一個時間差。當slave遇到阻塞時,接收數據會有一定延遲,在這個時間段內從slave讀取數據可能會出現數據不一致的情況。

解決方法是:可以對master和slave的offset值進行監控,當offset值相差過多時,可以把讀流量轉換到master上,但是這種方式有一定的成本

(2).讀到過期數據

Redis刪除過期數據有兩種策略

方式一:懶惰策略

當Redis操作這個數據時,纔會去看這個數據是否過期,如果數據已經過期,會返回一個-2給客戶端,表示查詢的數據已經過期

方式二:定時任務

每隔一個週期,Redis會採集一部分key,看這些key是否過期
如果過期key非常多或者採樣速度慢於key過期速度時,就會有很多過期key沒有被刪除
此時slave會同步包括過期key在內的master上的所有數據
由於slave沒有刪除數據的權限,此時基於讀寫分離的模式,客戶端會從slave中讀取一些過期的數據,也即髒數據

(3)從節點故障

上面已經介紹了。

4-2 主從配置不一致

第一種情況是:例如maxmemory不一致:丟失數據

如master節點分配的內存爲4G,而slave節點分配的內存只有2G時,此時雖然可以進行正常的主從複製,但當slave從master同步的數據大於2G時,slave不會拋出異常,不過會觸發slave節點的maxmemory-policy策略,對同步的數據進行一部分的淘汰,此時slave中的數據已經不完整了,造成丟失數據的情況。

另一種主從配置不一致的情況是:對master節點進行數據結構優化,但是沒有對slave做同樣的優化,會造成master和slave的內存不一致

4-3 規避全量複製

全量複製的開銷是非常大的,能避免就避免。主從節點的maxmemory不要設置過大,則傳輸和加載RDB文件的速度會很快,開銷相對會小一些,也可以在用戶訪問量比較低時進行全量複製

不過對於第一次爲一個master配置一個slave時,slave中沒有任何數據,進行全量複製不可避免。

4-4 節點run_id不匹配

當master重啓時,master的run_id會發生變化。slave在同步數據時發現之前保存的master的run_id與現在的run_id不匹配,會認爲當前master不安全。

解決方法:
做一次全量複製,當master發生故障時,slave轉換爲master提供數據寫入,或者使用Redis哨兵和集羣。
Redis4.0版本中提供新的方法:當master的run_id發生改變時,做故障轉移可以避免做全量複製

4-5 複製緩衝區不足

複製緩衝區的作用是把新的命令寫入到緩衝區中,複製緩衝區實際是一個隊列,默認大小爲1MB,即複製緩衝區只能保存1MB大小的數據。

如果slave與master的網絡斷開,master就會把新寫入的數據保存到複製緩衝區中

當寫入到複製緩衝區內的數據小於1MB時,就可以做部分複製,避免全量複製的問題。
如果新寫入的數據大於1MB時,就只能做全量複製了。
在配置文件中修改rel_backlog_size選項來加大複製緩衝區的大小,來減少全量複製的情況出現。

4-6 規避複製風暴
主從架構中,master節點重啓時,則master的run_id會發生變化,所有的slave節點都會進行主從複製

master生成RDB文件,然後所有slave節點都會同步RDB文件,在這個過程中對master節點的CPU,內存,硬盤有很大的開銷,這就是複製風暴。

1、單主節點複製風暴解決方法:更換複製拓樸
在這裏插入圖片描述
2、單機多部署複製風暴
一臺服務器上的所有節點都是master,如果這臺服務器系統發生重啓,則所有的slave節點都從這臺服務器進行全量複製,會對服務器造成很大的壓力

主節點分散多機器:將master分配到不同的服務器上
在這裏插入圖片描述

七、Redis sentinel

(一)主從複製高可用的問題

主從複製高可用的作用:

  1. 爲master提供備份,當master宕機時,slave有完整的備份數據
  2. 對master實現分流,實現讀寫分離

但是主從架構有一個問題:
如果master宕機,故障轉移需要手動完成或者由別的工具來完成,從slave中選擇一個slave做爲新的master

舉個例子:在一主兩從情況下,master宕機,則slave從master同步數據也斷開,此時client向master寫入數據會失敗,讀寫分離時讀取數據正常,但不能更新數據。

master出現故障之後,採用手動進行故障轉移步驟

  1. 選擇一個slave,執行slave no one命令使之成爲一個master
  2. 對其餘的slave執行slaveof new master命令,將這些slave指定爲新的master的slave
  3. client會對新的master進行寫入數據,從slave中讀取原來的數據
    在這裏插入圖片描述
    上面的操作過程需要手動完成,或者編寫腳本,由腳本來執行這個過程,但是這個過程是有問題的:
  • 怎麼判斷一個Redis節點是有問題的,怎麼通知client對新master進行寫入操作
  • 怎麼保證一個完整的事務實現過程

這裏就引出我們的主角-Redis Sentinel

(二)Redis Sentinel架構說明

Redis Sentinel的功能:對Redis節點進行監控,故障判斷,故障轉移,故障通知
在這裏插入圖片描述
對於Redis的主從架構,Redis Sentinel會運行幾個sentinel進程,sentinel進程不操作數據,而是對Redis故障進行判斷和轉移。

多個sentinel運行,即使一個sentinel進程運行異常,還有別的sentinel繼續運行,可以保證對故障節點判斷的準確性,同時保證Redis的高可用。

對於redis-cli來說,Redis cli不會再記錄Redis的IP和端口,而是從sentinel獲取Redis信息,然後進行連接Redis節點,進行數據寫入和讀取操作,多個Redis Sentinel對所有的master和slave進行監控,會實時記錄master和slave的地址信息。

在這裏插入圖片描述

Redis Sentinel故障轉移步驟:

  1. 當某個master發生故障,多個sentinel會監控到這個異常,這些sentinel會按照一定規則從多個slave中選中一個做爲新的master,並通知別的slave從新的master中同步數據
  2. 當某個slave轉換爲新的master,sentinel會記錄新的master的地址信息和slave的地址信息,通知Redis cli
  3. Redis cli接收到新的master和slave的信息,就會向新的master寫入數據,從slave中讀取數據
  4. 等到原來的master重啓之後,會變成新的master的slave,並從新的master同步數據

在這裏插入圖片描述
在上面的步驟裏,sentinel實現了Redis的故障自動發現,自動轉移和自動通知

說明:一套Redis sentinel集合可以通知master-name做爲標識同時監控多套主從架構

(三)Redis Sentinel客戶端連接解析

1.Redis Sentinel配置
(1)環境說明
例如:

192.168.81.100的6379端口爲master節點
192.168.81.100的6380端口爲slave節點
192.168.81.101的6379端口和6380端口爲slave節點

在192.168.81.101的26379,26380,26381端口開啓三個sentinel進行監控

(2)在192.168.81.100虛擬機上配置主從節點

[root@localhost ~]# cd /etc/                            # 進入/etc目錄
[root@localhost ~]# systemctl stop redis                # 關閉系統中運行的redis
[root@localhost etc]# cp redis.conf redis_6379.conf     # 複製redis配置文件,以端口區分,方便後面進行配置
[root@localhost etc]# cp redis.conf redis_6380.conf     # 複製redis配置文件,以端口區分,方便後面進行配置
[root@localhost etc]# vi redis_6379.conf                # 編輯redis-server配置文件,修改下面幾行
    bind 0.0.0.0                                        # 修改bing選項,才能從系統外連接redis
    protected-mode yes                                  # 開啓保存模式
    port 6379                                           # 指定redis運行的端口
    daemonize yes                                       # 以守護進程啓動redis
    pidfile "/var/run/redis_6379.pid"                   # 指定redis運行時pid保存路徑
    logfile "/var/log/redis/redis_6379.log"             # 指定redis運行時日誌保存路徑
    dir /var/lib/redis_6379                             # 指定redis運行時數據文件保存路徑
    
[root@localhost etc]# vi redis_6380.conf                # 修改redis-server,修改下面幾行
    bind 0.0.0.0
    port 6380                                           # 指定redis運行的端口
    daemonize yes
    pidfile "/var/run/redis_6380.pid"
    logfile "/var/log/redis/redis_6380.log"
    dir /var/lib/redis_6380
    slaveof 192.168.81.100 6379                         # 指定redis-server爲192.168.81.100:6379的slave
    
[root@localhost etc]# redis-server /etc/redis_6379.conf     # 指定配置文件運行redis-server
[root@localhost etc]# redis-server /etc/redis_6380.conf     # 指定配置文件運行redis-server
[root@localhost etc]# ps aux | grep redis-server            # 查看redis-server是否運行
root       2548  0.3  1.7 155192 17720 ?        Ssl  23:14   0:00 redis-server 0.0.0.0:6379
root       2562  1.3  1.7 155192 17596 ?        Ssl  23:15   0:00 redis-server 0.0.0.0:6380
root       2567  0.0  0.0 112648   960 pts/3    R+   23:15   0:00 grep --color=auto redis-server
[root@localhost etc]# redis-cli -p 6380 info replication    # 進入6380端口運行redis客戶端,並執行'info replication'命令
# Replication
role:slave                              # 角色爲slave
master_host:192.168.81.100              # master爲192.168.81.100
master_port:6379
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_repl_offset:1919
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

(3)在192.168.81.101虛擬機上配置從節點

[root@mysql ~]# cd /etc/                                # 操作同192.168.81.100相同
[root@mysql ~]# systemctl stop redis
[root@mysql etc]# cp redis.conf redis_6379.conf
[root@mysql etc]# cp redis.conf redis_6380.conf
[root@mysql etc]# vi redis_6379.conf
    bind 0.0.0.0
    protected-mode yes
    port 6379
    daemonize yes
    pidfile "/var/run/redis_6379.pid"
    logfile "/var/log/redis/redis_6379.log"
    dir /var/lib/redis_6379
    slaveof 192.168.81.100 6379                         # 指定redis-server爲192.168.81.100:6379的slave
    
[root@mysql etc]# vi redis_6380.conf    
    bind 0.0.0.0
    port 6380
    daemonize yes
    pidfile "/var/run/redis_6380.pid"
    logfile "/var/log/redis/redis_6380.log"
    dir /var/lib/redis_6380
    slaveof 192.168.81.100 6379                         # 指定redis-server爲192.168.81.100:6379的slave
    
[root@mysql etc]# redis-server /etc/redis_6379.conf     # 指定配置文件運行redis-server
[root@mysql etc]# redis-server /etc/redis_6380.conf     # 指定配置文件運行redis-server
[root@mysql ~]# ps aux | grep redis-server              # 查看redis-server是否運行
root       2178  0.2  0.8 155204 17728 ?        Ssl  15:10   0:02 redis-server 0.0.0.0:6379
root       2184  0.2  0.8 155204 17724 ?        Ssl  15:10   0:02 redis-server 0.0.0.0:6380
root       2411  0.0  0.0 112664   972 pts/2    R+   15:29   0:00 grep --color=auto redis-server
[root@mysql ~]# redis-cli -p 6379 info replication
# Replication
role:slave                              # 角色爲slave
master_host:192.168.81.100              # master爲192.168.81.100
master_port:6379
master_link_status:up
master_last_io_seconds_ago:6
master_sync_in_progress:0
slave_repl_offset:1961
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
[root@mysql ~]# redis-cli -p 6380 info replication   
# Replication
role:slave                              # 角色爲slave
master_host:192.168.81.100              # master爲192.168.81.100
master_port:6379
master_link_status:up
master_last_io_seconds_ago:2
master_sync_in_progress:0
slave_repl_offset:1975
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

(4)在192.168.81.101虛擬機上配置並運行sentinel

[root@mysql etc]# cp redis-sentinel.conf sentinel_26379.conf    # 複製sentinel配置文件,方便區分
[root@mysql etc]# cp redis-sentinel.conf sentinel_26380.conf    # 複製sentinel配置文件,方便區分
[root@mysql etc]# cp redis-sentinel.conf sentinel_26381.conf    # 複製sentinel配置文件,方便區分
[root@mysql etc]# vi sentinel_26379.conf                        # 修改sentinel配置文件,修改下面幾行
    daemonize yes                                               # 以守護進程方式啓動
    port 26379                                                  # 指定端口
    protected-mode no                                           # 關閉保護模式
    sentinel monitor mymaster 192.168.81.100 6379 2             # 設置sentinel監控信息
    logfile /var/log/redis/sentinel_26379.log                   # 設置日誌文件保存路徑
[root@mysql etc]# vi sentinel_26380.conf 
    daemonize yes
    port 26380  
    protected-mode no  
    sentinel monitor mymaster 192.168.81.100 6379 2
    logfile /var/log/redis/sentinel_26380.log
[root@mysql etc]# vi sentinel_26381.conf 
    protected-mode no  
    port 26381
    daemonize yes  
    sentinel monitor mymaster 192.168.81.100 6379 2
    logfile /var/log/redis/sentinel_26381.log
[root@mysql etc]# redis-sentinel /etc/sentinel_26379.conf       # 指定配置文件,啓動Redis Sentinel
[root@mysql etc]# redis-sentinel /etc/sentinel_26380.conf       # 指定配置文件,啓動Redis Sentinel  
[root@mysql etc]# redis-sentinel /etc/sentinel_26381.conf       # 指定配置文件,啓動Redis Sentinel
[root@mysql etc]# ps aux | grep sentinel                        # 查看Redis Sentinel是否運行
root       2709  0.9  0.2 142916  5464 ?        Ssl  15:49   0:00 redis-sentinel *:26379 [sentinel]
root       2713  1.1  0.2 142916  5472 ?        Ssl  15:49   0:00 redis-sentinel *:26380 [sentinel]
root       2717  2.0  0.2 142916  5476 ?        Rsl  15:49   0:00 redis-sentinel *:26381 [sentinel]
root       2721  0.0  0.0 112664   964 pts/2    R+   15:49   0:00 grep --color=auto sentinel
[root@mysql ~]# redis-cli -p 26379
127.0.0.1:26379> ping                                           # 執行ping操作
PONG
127.0.0.1:26379> info sentinel                                  # 查看所有sentinel的信息
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.81.100:6379,slaves=3,sentinels=3                   # 被監控的Redis主從架構命名爲mymaster,被監控Redis節點的master爲192.168.81.100L6379,有三個slave,同時有3個sentinel運行
127.0.0.1:26379> exit
[root@mysql ~]# grep -v '^#' /etc/sentinel_26379.conf | grep -v '^$'     #查看sentinel_26379配置文件,去除註釋和空行,Redis Sentinel向配置文件中添加了幾行內容
port 26379                                                  # sentinel運行的端口
dir "/tmp"
sentinel myid 9611958fc3e8b7c2be43385e44be88f87d725a77
sentinel monitor mymaster 192.168.81.100 6379 2             # sentinel監控的Redis節點名爲mymaster,master地址爲192.168.81.100:6379,quorem設置爲2
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
logfile "/var/log/redis/sentinel_26379.log"
daemonize yes
sentinel known-slave mymaster 192.168.81.101 6379           # sentinel探測到的slave
sentinel known-slave mymaster 192.168.81.100 6380           # sentinel探測到的slave
sentinel known-slave mymaster 192.168.81.101 6380           # sentinel探測到的slave
sentinel known-sentinel mymaster 192.168.81.101 26380 17ca0cb82becb58bd24e5a87ee3b6e8e9a49caf1                    # Redis Sentinel深測到的別的運行的sentinel
sentinel known-sentinel mymaster 127.0.0.1 26381 fb9342f3007e2abff165f5c33de1d48cf089f062                    # Redis Sentinel深測到的別的運行的sentinel
sentinel current-epoch 0
[root@mysql ~]# grep -v '^#' /etc/sentinel_26380.conf | grep -v '^$'  
port 26380
dir "/tmp"
sentinel myid 17ca0cb82becb58bd24e5a87ee3b6e8e9a49caf1
sentinel monitor mymaster 192.168.81.100 6379 2
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
logfile "/var/log/redis/sentinel_26380.log"
daemonize yes
sentinel known-slave mymaster 192.168.81.101 6379
sentinel known-slave mymaster 192.168.81.101 6380
sentinel known-slave mymaster 192.168.81.100 6380
sentinel known-sentinel mymaster 127.0.0.1 26381 fb9342f3007e2abff165f5c33de1d48cf089f062
sentinel known-sentinel mymaster 192.168.81.101 26379 9611958fc3e8b7c2be43385e44be88f87d725a77
sentinel current-epoch 0
[root@mysql ~]# grep -v '^#' /etc/sentinel_26381.conf | grep -v '^$' 
port 26381
daemonize yes
dir "/tmp"
sentinel myid fb9342f3007e2abff165f5c33de1d48cf089f062
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
logfile "/var/log/redis/sentinel_26381.log"
sentinel known-sentinel mymaster 127.0.0.1 26380 17ca0cb82becb58bd24e5a87ee3b6e8e9a49caf1
sentinel known-sentinel mymaster 192.168.81.101 26379 9611958fc3e8b7c2be43385e44be88f87d725a77
sentinel current-epoch 0

至此,3個sentinel已經正常運行了

python客戶端持續通過sentinel向Redis寫入數據,讀取數據

import random
import time
from redis.sentinel import Sentinel

sentinel = Sentinel([
    ('192.168.81.101',26379),
    ('192.168.81.101',26380),
    ('192.168.81.101',26381),
],socket_timeout=0.1)               # 傳入Redis Sentinel集合

while True:
    try:
        master = sentinel.discover_master('mymaster')
        print('current master IP:',master)          # 打印當前master的IP地址和端口
        val = random.randint(0,10000)               # 獲取10000以內隨機整數
        key = 'k%d' % val
        m = sentinel.master_for('mymaster', socket_timeout=0.5)
        m.set(key,'val%d' % val)                    # 通過sentinel向master節點寫入數據
        v = m.get(key)                              # 通過sentinel讀取數據
        print('{0} value is {1}'.format(key,v))
        time.sleep(1)
    except Exception as e:
        print("get no val:",e)

Redis Sentinel的高可用指的是服務端的高可用,對於Redis服務端的master宕機,sentinel可以對故障實現自動發現,自動轉移,自動通知。這個過程客戶端是感知不到的

Redis高可用即依賴於服務端的高可用,又依賴於客戶端的高可用

通過分析Redis Sentinel的請求響應流程,可以知道客戶端實現高可用步驟:

  1. 客戶端遍歷sentinel節點集合,獲取一個可用的sentinel節點,同時獲取masterName
  2. 在可用的sentinel節點上執行sentinel的API,獲取master的地址和端口
  3. 在sentinel內部,sentinel會按照一定頻率在master或者slave上執行info命令,獲取對應節點的信息
  4. 客戶端獲取到master的地址和端口,會執行role命令或者role replication命令,對master進行驗證
  5. 當master出現故障,sentinel按照算法從slave中選出一個做爲新的master,同時把其餘的slave做爲新的master的slave
  6. sentinel維護一個頻道,sentinel在這個頻道中發佈消息,指出新master的IP和端口
  7. 客戶端訂閱這個頻道,接收消息後就知道新master的IP和端口,向新master連接進行數據處理

在這裏插入圖片描述
python客戶端接入Redis Sentinel需要兩個參數:sentinel地址集合,masterName

需要注意的是Redis節點的配置文件中的protected-mode必須設置爲yes,否則連接會失敗

(四)Redis Sentinel實現原理

1.Redis Sentinel內部的三個定時任務

Redis Sentinel內部有三個定時任務來對redid節點進行故障判斷和轉移

  • 每10秒每個sentinel對master和slave執行info命令,以發現slave節點和確認主從關係

sentinel在master節點執行info replication命令,從命令執行結果中解析出slave節點

圖爲 第一個定時:每10秒info
在這裏插入圖片描述

  • 每2秒每個sentinel通過master節點的channel交換信息(發佈訂閱)

master節點上有一個發佈訂閱的channel頻道:__sentinel__:hello,用於所有sentinel之間進行信息交換

一個sentinel發佈消息,消息包含當前sentinel節點的信息,對其他sentinel節點的判斷以及當前sentinel對master節點和slave節點的一些判斷,其他sentinel都可以接收到這條消息。新加入sentinel節點時,sentinel節點之間可以相互感知,以達到信息交互的功能

圖爲: 第二個定時:每2秒發佈訂閱
在這裏插入圖片描述

  • 每1秒每個sentinel對其他sentinel節點和Redis節點執行ping操作

每個sentinel都可以知道其他sentinel節點,當監控的master發生故障時,方便進行判斷和新master的挑選,這個定時任務是master進行故障判定的依據

圖爲: 第三個定時:每1秒ping
在這裏插入圖片描述

2.主觀下線和客觀下線

主觀下線:每個sentinel節點對Redis節點失敗的’偏見’

在redis-sentinel配置文件中,有下面這種配置

sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel down-after-milliseconds <master-name> <timeout>

一個sentinel集合可以同時監控多個master,slave的節點,sentinel對多個master,slave節點進行區分的標識就是master-name,ip和port是master節點的IP地址和端口,quorum是master客觀下線之後sentinel進行判斷的節點數

sentinel對master進行主觀下線判斷的時間,單位爲毫秒,每個sentinel每秒對master和slave執行ping操作,當sentinel對master或slave在timeout定義的毫秒時間內沒有回覆,則sentinel會認爲這個節點已經被主觀下線了。

在前面的例子中對sentinel的配置是

sentinel monitor mymaster 192.168.81.100 6379 2
sentinel down-after-milliseconds mymaster 30000

解釋:

  • sentinel集合監控名爲mymaster的master,slave節點
  • 被監控的master節點的IP地址是192.168.81.100,端口爲6379,
  • sentinel會在__sentinel__:hello頻道中交流對master節點的看法,如果sentinel節點都對master節點ping失敗’達成共識’,sentinel個數超過quorum的個數,sentinel集合則會認爲master節點客觀下線
  • 當兩個sentinel對master節點執行ping操作,在30000毫秒(30秒)時間內沒有得到回覆,則認爲節點已經被主觀下線
  • quorum建議設置爲:(sentinel節點數 / 2) + 1,可以根據應用場景進行設定

3.sentinel領導者選舉

只需要一個sentinel節點就可以完成故障轉移,通過sentinel is-master-down-by-addr命令來完成sentinel交換對master節點的失敗判定和新master的選舉

完成sentinel領導者選舉步驟:

  1. 每個做主觀下線的sentinel節點向其他sentinel節點發送命令,要求將自己設置爲領導者
  2. 收到命令的sentinel節點如果沒有同意同意其他sentinel節點發送的命令,那麼將同意該請求,否則拒絕
  3. 如果該sentinel節點發現自己的票數已經超過sentinel集合半數且超過quorum,將成爲領導者
  4. 如果此過程中有多個sentinel節點成爲領導者,那麼將等待一段時間重新進行選舉

4.故障轉移(由sentinel領導者節點完成)

故障轉移步驟:

  1. 從slave節點中選出一個合適的節點作爲新的master節點
  2. 對選出的slave節點執行slaveof no one命令,使成爲新的master節點
  3. 向剩餘的slave節點發送命令,讓slave節點成爲新master節點的slave節點,然後從新master節點同步數據。數據同步規則和parallel-syncs參數有關,比如一個一主三從架構中,master故障,sentinel領導者從3個slave中選出一個作爲新的master節點,剩餘的兩個slave節點會成爲新master節點的slave,從新master節點同步同步數據,master節點只需要生成一次RDB文件。如果parallel-syncs參數設置爲1,則剩餘兩個slave節點會按順序從新master節點拷貝數據,一個slave切點拷貝完成,另外一個slave纔會從新master節點拷貝數據;如果parallel-syncs參數設置爲2,則兩個slave節點會同時從master節點進行數據拷貝,這無疑會加入新master的開銷。
  4. sentinel領導者會把原來的master節點設置爲slave節點,並保持對其’關注’,當原來的master節點恢復後,sentinel會使其去複製新master節點的數據

5 slave節點的選擇

slave節點選擇規則

  1. 選擇slave-priority(slave節點優先級)最高的slave節點,如果存在則返回,不存在則繼續
  2. 選擇複製偏移量(offset)最大的slave節點,offset最大說明對master的數據複製的最完整,如果存在則返回,不存在則繼續
  3. 選擇run_id最小的slave節點,run_id最小說明slave節點啓動最早

6.Redis Sentine小總結:

  • Redis Sentinel是Redis的高可用實現方案:故障發現,故障自動轉移,配置中心,客戶端通知
  • Redis Sentinel是Redis 2.8版本開始才正式生產可用,之前版本不可用於生產
  • 儘可以在不同物理機上部署Redis Sentinel所有節點,但是最好一個局域網內
  • Redis Sentinel中sentinel節點個數應該大於等於3,且最好爲奇數,可以保證判斷的公平
  • Redis Sentinel中的數據節點與普通數據節點沒有區別
  • 客戶端初始化時連接的是Sentinel節點集合,不是具體的Redis節點,但是Sentinel只是配置中心不是代理
  • Redis Sentinel通過三個定時任務實現了Sentinel節點對於master,slave,其餘sentinel節點的監控
  • Redis Sentinel在對節點做失敗判定時分爲主觀下線和客觀下線
  • 看懂Redis Sentinel故障轉移日誌對於Redis Sentinel以及問題排查非常有幫助
  • Redis Sentinel實現讀寫分離高可用可以依賴Redis Sentinel節點的消息通知,獲取Redis數據節點的狀態變化

八、Redis Cluster

RedisCluster 是 Redis 的親⼉⼦,它是 Redis 作者⾃⼰提供的Redis 集羣化⽅案。

(一)Redis原生命令搭建集羣

搭建Redis Cluster主要步驟

  1. 配置開啓節點
  2. meet
  3. 指派槽
  4. 主從關係分配

環境說明
兩臺虛擬機,IP地址分別爲:192.168.81.100和192.168.81.101
兩臺虛擬機操作系統均爲:CentOS 7.5 64位
兩臺虛擬機系統說明:

  • 使用yum方式安裝Redis
  • 關閉firewalld防火牆

使用兩臺虛擬機的7000,7001,7002端口搭建三主三從的Redis Cluster

  • 其中192.168.81.100主機三個端口啓動的Redis Server爲主節點
  • 192.168.81.101主機三個端口啓動的Redis Server爲從節點

搭建Redis Cluster具體步驟
(1)在192.168.81.100虛擬機上操作

[root@host1 etc]# cd /opt
[root@host1 opt]# mkdir config
[root@host1 opt]# cd config
[root@host1 config]# vi redis_7000.conf             # 創建7000端口運行需要的配置文件,文件內容如下
    port 7000
    daemonize yes
    dir '/var/lib/redis'
    logfile '/var/log/redis/redis_7000.log'
    dbfilename 'redis_7000.data'
    cluster-enabled yes
    cluster-config-file nodes-7000.conf
    cluster-require-full-coverage no
[root@host1 config]# sed 's/7000/7001/g' redis_7000.conf > redis_7001.conf  # 把redis_7000.conf文件中的7000替換成7001,並生成redis_7001.conf文件
[root@host1 config]# sed 's/7000/7002/g' redis_7000.conf > redis_7002.conf  # 把redis_7000.conf文件中的7000替換成7002,並生成redis_7002.conf文件
[root@host1 config]# redis-server /opt/config/redis_7000.conf               # 指定配置文件,啓動redis server節點
[root@host1 config]# redis-server /opt/config/redis_7001.conf               # 指定配置文件,啓動redis server節點            
[root@host1 config]# redis-server /opt/config/redis_7002.conf               # 指定配置文件,啓動redis server節點
[root@host1 config]# ps aux | grep redis-server                             # 查看redis-server進程運行情況                        
root       2444  0.1  0.5 142904  5328 ?        Ssl  19:38   0:00 redis-server *:7000 [cluster]
root       2475  0.0  0.5 142904  5328 ?        Ssl  19:39   0:00 redis-server *:7001 [cluster]
root       2479  0.2  0.5 142904  5328 ?        Ssl  19:39   0:00 redis-server *:7002 [cluster]
root       2483  0.0  0.0 112648   964 pts/0    R+   19:39   0:00 grep --color=auto redis-server

(2)在192.168.81.101虛擬機上進行第一步的操作,生成三個配置文件,並啓動Redis server

[root@mysql config]# redis-server /opt/config/redis_7000.conf               # 指定配置文件,啓動redis server節點
[root@mysql config]# redis-server /opt/config/redis_7001.conf               # 指定配置文件,啓動redis server節點           
[root@mysql config]# redis-server /opt/config/redis_7002.conf               # 指定配置文件,啓動redis server節點
[root@mysql config]# ps aux  | grep redis-server                            # 查看redis-server的進程運行情況                        
root       1704  0.1  0.2 142916  5344 ?        Ssl  19:41   0:00 redis-server *:7000 [cluster]
root       1736  0.0  0.2 142916  5344 ?        Ssl  19:41   0:00 redis-server *:7001 [cluster]
root       1740  0.0  0.2 142916  5340 ?        Ssl  19:42   0:00 redis-server *:7002 [cluster]

(3)在192.168.81.100虛擬機上查看cluster節點的信息

[root@host1 config]# redis-cli -p 7000
127.0.0.1:7000> set hello world             # 向當前節點執行寫入命令,失敗
(error) CLUSTERDOWN Hash slot not served
127.0.0.1:7000> cluster nodes               # 查看集羣節點信息,只有當前節點的信息,且顯示爲主節點
d20aa403c5d7d9507adcc4ef6132c14f3c9486ed :7000 myself,master - 0 0 0 connected
127.0.0.1:7000> cluster info                # 查看cluster的信息
cluster_state:fail                          # 集羣爲失敗狀態
cluster_slots_assigned:0
cluster_slots_ok:0                          # 當前集羣中有0個slot(槽)
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:1                       # 當前集羣中節點個數爲1
cluster_size:0
cluster_current_epoch:0
cluster_my_epoch:0
cluster_stats_messages_sent:0
cluster_stats_messages_received:0
127.0.0.1:7000> exit
[root@host1 config]# cd /var/lib/redis/
[root@host1 redis]# ls              
dump.rdb  nodes-7000.conf  nodes-7001.conf  nodes-7002.conf
[root@host1 redis]# cat nodes-7000.conf    # 查看7000端口上運行的redis-server的run_id與執行cluster nodes命令得到的run_id相同
d20aa403c5d7d9507adcc4ef6132c14f3c9486ed :0 myself,master - 0 0 0 connected
vars currentEpoch 0 lastVoteEpoch 0

(4)在192.168.81.100上執行meet操作

[root@host1 redis]# redis-cli -p 7000 cluster meet 127.0.0.1 7001       # 通過7000端口的redis server向7001端口的redis server發送meet操作
OK
[root@host1 redis]# redis-cli -p 7000 cluster nodes                     # 通過7000端口運行的redis server查看cluster的節點信息,已經添加7001端口運行的redis server,且都爲master節點
d20aa403c5d7d9507adcc4ef6132c14f3c9486ed 127.0.0.1:7000 myself,master - 0 0 0 connected
45d79e730593df3216a4236a19c21ff601949449 127.0.0.1:7001 master - 0 1539719395866 1 connected
[root@host1 redis]# redis-cli -p 7001 cluster nodes                     # 通過7001端口運行的redis server查看cluster的節點信息,也可以看到7000端口運行的redis server
d20aa403c5d7d9507adcc4ef6132c14f3c9486ed 127.0.0.1:7000 master - 0 1539719408423 0 connected
45d79e730593df3216a4236a19c21ff601949449 127.0.0.1:7001 myself,master - 0 0 1 connected
[root@host1 redis]# redis-cli -p 7002 cluster nodes                     # 通過7002端口的redis server查看cluster的節點信息,7000端口和7001端口運行的redis server都不在其中,因爲7002端口運行的redis server沒有meet
e5ea887c98e79ef2b2205d6cc1d7ac5cfe936d9a :7002 myself,master - 0 0 0 connected
[root@host1 redis]# redis-cli -p 7000 cluster meet 127.0.0.1 7002       # 向7002端口運行的redis server發送meet操作
OK
[root@host1 redis]# redis-cli -p 7001 cluster nodes                     # 7002端口運行的redis server已經添加到集羣中了            
e5ea887c98e79ef2b2205d6cc1d7ac5cfe936d9a 127.0.0.1:7002 master - 0 1539719438785 0 connected
d20aa403c5d7d9507adcc4ef6132c14f3c9486ed 127.0.0.1:7000 master - 0 1539719439689 2 connected
45d79e730593df3216a4236a19c21ff601949449 127.0.0.1:7001 myself,master - 0 0 1 connected
[root@host1 redis]# redis-cli -p 7002 cluster nodes              
45d79e730593df3216a4236a19c21ff601949449 127.0.0.1:7001 master - 0 1539719442308 1 connected
d20aa403c5d7d9507adcc4ef6132c14f3c9486ed 127.0.0.1:7000 master - 0 1539719441301 2 connected
e5ea887c98e79ef2b2205d6cc1d7ac5cfe936d9a 127.0.0.1:7002 myself,master - 0 0 0 connected
[root@host1 redis]# redis-cli -p 7000 cluster meet 192.168.81.101 7002  # 向192.168.81.101:7002端口運行的redis server執行meet操作              
OK
[root@host1 redis]# redis-cli -p 7000 cluster meet 192.168.81.101 7000  # 向192.168.81.101:7000端口運行的redis server執行meet操作
OK
[root@host1 redis]# redis-cli -p 7000 cluster meet 192.168.81.101 7001  # 向192.168.81.101:7001端口運行的redis server執行meet操作
OK
[root@host1 redis]# redis-cli -p 7000 cluster nodes
c96589b19b8ff5d9d286d470b8efff9a540726d8 192.168.81.101:7000 master - 0 1539719546060 5 connected
53911425f4479ce4f054b8b714f4700715f0dc64 192.168.81.101:7002 master - 0 1539719548113 3 connected
bb88f0996503bac3b222b9cc4ec25139ad34ed3a 192.168.81.101:7001 master - 0 1539719547106 4 connected
45d79e730593df3216a4236a19c21ff601949449 127.0.0.1:7001 master - 0 1539719544042 1 connected
d20aa403c5d7d9507adcc4ef6132c14f3c9486ed 127.0.0.1:7000 myself,master - 0 0 2 connected
e5ea887c98e79ef2b2205d6cc1d7ac5cfe936d9a 127.0.0.1:7002 master - 0 1539719545050 0 connected
[root@host1 redis]# redis-cli -p 7002 cluster nodes                     # 查看集羣中的節點信息,發現6個node都已經添加到當前集羣中了
45d79e730593df3216a4236a19c21ff601949449 127.0.0.1:7001 master - 0 1539719554166 1 connected
d20aa403c5d7d9507adcc4ef6132c14f3c9486ed 127.0.0.1:7000 master - 0 1539719554668 2 connected
bb88f0996503bac3b222b9cc4ec25139ad34ed3a 192.168.81.101:7001 master - 0 1539719555174 4 connected
53911425f4479ce4f054b8b714f4700715f0dc64 192.168.81.101:7002 master - 0 1539719556180 3 connected
e5ea887c98e79ef2b2205d6cc1d7ac5cfe936d9a 127.0.0.1:7002 myself,master - 0 0 0 connected
c96589b19b8ff5d9d286d470b8efff9a540726d8 192.168.81.101:7000 master - 0 1539719557188 5 connected
[root@host1 redis]# redis-cli -p 7002 cluster info         # 查看集羣相關的信息
cluster_state:fail                  # 集羣狀態爲失敗
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6               # 集羣中有6個已知節點
cluster_size:0
cluster_current_epoch:5
cluster_my_epoch:0
cluster_stats_messages_sent:507
cluster_stats_messages_received:507

(5)在192.168.81.101虛擬機上查看cluster的信息

[root@mysql config]# redis-cli -p 7000 cluster nodes        # 查看cluster的節點信息,6個節點的信息都顯示出來,且都爲master
53911425f4479ce4f054b8b714f4700715f0dc64 192.168.81.101:7002 master - 0 1539690828453 3 connected
45d79e730593df3216a4236a19c21ff601949449 192.168.81.100:7001 master - 0 1539690825432 1 connected
d20aa403c5d7d9507adcc4ef6132c14f3c9486ed 192.168.81.100:7000 master - 0 1539690826437 2 connected
e5ea887c98e79ef2b2205d6cc1d7ac5cfe936d9a 192.168.81.100:7002 master - 0 1539690827448 0 connected
bb88f0996503bac3b222b9cc4ec25139ad34ed3a 192.168.81.101:7001 master - 0 1539690827950 4 connected
c96589b19b8ff5d9d286d470b8efff9a540726d8 192.168.81.101:7000 myself,master - 0 0 5 connected
[root@mysql config]# redis-cli -p 7001 cluster nodes        # 查看cluster的節點信息,6個節點的信息都顯示出來,且都爲master
53911425f4479ce4f054b8b714f4700715f0dc64 127.0.0.1:7002 master - 0 1539690840955 3 connected
c96589b19b8ff5d9d286d470b8efff9a540726d8 192.168.81.101:7000 master - 0 1539690842968 5 connected
bb88f0996503bac3b222b9cc4ec25139ad34ed3a 192.168.81.101:7001 myself,master - 0 0 4 connected
e5ea887c98e79ef2b2205d6cc1d7ac5cfe936d9a 192.168.81.100:7002 master - 0 1539690844979 0 connected
d20aa403c5d7d9507adcc4ef6132c14f3c9486ed 192.168.81.100:7000 master - 0 1539690841960 2 connected
45d79e730593df3216a4236a19c21ff601949449 192.168.81.100:7001 master - 0 1539690843977 1 connected
[root@mysql config]# redis-cli -p 7002 cluster nodes        # 查看cluster的節點信息,6個節點的信息都顯示出來,且都爲master
bb88f0996503bac3b222b9cc4ec25139ad34ed3a 127.0.0.1:7001 master - 0 1539690847798 4 connected
53911425f4479ce4f054b8b714f4700715f0dc64 192.168.81.101:7002 myself,master - 0 0 3 connected
d20aa403c5d7d9507adcc4ef6132c14f3c9486ed 192.168.81.100:7000 master - 0 1539690846795 2 connected
e5ea887c98e79ef2b2205d6cc1d7ac5cfe936d9a 192.168.81.100:7002 master - 0 1539690843775 0 connected
c96589b19b8ff5d9d286d470b8efff9a540726d8 192.168.81.101:7000 master - 0 1539690844780 5 connected
45d79e730593df3216a4236a19c21ff601949449 192.168.81.100:7001 master - 0 1539690845786 1 connected
[root@mysql config]# redis-cli -p 7002 cluster info         # 查看cluster的信息
cluster_state:fail              # 集羣狀態爲失敗狀態
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6           # 集羣中添加了6個節點
cluster_size:0                  # 集羣中
cluster_current_epoch:5
cluster_my_epoch:3
cluster_stats_messages_sent:413
cluster_stats_messages_received:413

(6)在192.168.81.100虛擬機上編寫腳本,完成分配slot

[root@host1 ~]# cd /opt/config/
[root@host1 config]# vi add_slots.sh                    # 編寫add_slots.sh腳本

    #!/bin/bash

    start=$1
    end=$2
    port=$3

    for slot in `seq ${start} ${end}`
    do
        echo "slot:${slot}"
        redis-cli -p ${port} cluster addslots ${slot}
    done                                                                                                                
[root@host1 config]# sh add_slots.sh 0 5461 7000        # 運行add_slots.sh腳本,把0到5461號槽分配給192.168.81.100:7000的redis server節點
slot:0
OK
slot:1
OK
slot:2
OK
slot:3
OK
slot:4
OK
slot:5
OK
...中間省略
slot:5459
OK
slot:5460
OK
slot:5461
OK
[root@host1 config]# redis-cli -p 7000 cluster info        # 查看cluster集羣的信息
cluster_state:ok                    # 集羣狀態爲OK狀態
cluster_slots_assigned:5462         # 集羣中已經有5462個數據槽
cluster_slots_ok:5462               # 5462個槽的狀態爲0K狀態
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6               # 集羣添加了6個節點   
cluster_size:1                      # 集羣的大小爲1個
cluster_current_epoch:5
cluster_my_epoch:2
cluster_stats_messages_sent:2237
cluster_stats_messages_received:2237
[root@host1 config]# redis-cli -p 7000 cluster nodes        # 查看集羣中節點的信息
c96589b19b8ff5d9d286d470b8efff9a540726d8 192.168.81.101:7000 master - 0 1539720483326 5 connected
53911425f4479ce4f054b8b714f4700715f0dc64 192.168.81.101:7002 master - 0 1539720484336 3 connected
bb88f0996503bac3b222b9cc4ec25139ad34ed3a 192.168.81.101:7001 master - 0 1539720485346 4 connected
45d79e730593df3216a4236a19c21ff601949449 127.0.0.1:7001 master - 0 1539720482314 1 connected
d20aa403c5d7d9507adcc4ef6132c14f3c9486ed 127.0.0.1:7000 myself,master - 0 0 2 connected 0-5461                # 192.168.81.100:7000端口運行的redis server已經分配的槽爲0到5461號槽,其他節點還沒有分配槽
e5ea887c98e79ef2b2205d6cc1d7ac5cfe936d9a 127.0.0.1:7002 master - 0 1539720486351 0 connected
[root@host1 config]# redis-cli -p 7002 cluster nodes 
45d79e730593df3216a4236a19c21ff601949449 127.0.0.1:7001 master - 0 1539720507768 1 connected
d20aa403c5d7d9507adcc4ef6132c14f3c9486ed 127.0.0.1:7000 master - 0 1539720509782 2 connected 0-5461
bb88f0996503bac3b222b9cc4ec25139ad34ed3a 192.168.81.101:7001 master - 0 1539720510789 4 connected
53911425f4479ce4f054b8b714f4700715f0dc64 192.168.81.101:7002 master - 0 1539720508776 3 connected
e5ea887c98e79ef2b2205d6cc1d7ac5cfe936d9a 127.0.0.1:7002 myself,master - 0 0 0 connected
c96589b19b8ff5d9d286d470b8efff9a540726d8 192.168.81.101:7000 master - 0 1539720511799 5 connected
[root@host1 config]# sh add_slots.sh 5462 10922 7001    # 運行add_slots.sh腳本,把5462號到10922號槽分配給7001端口運行的redis server
[root@host1 config]# sh add_slots.sh 10923 16383 7002   # 運行add_slots.sh腳本,把10923號到16383號槽分配給7002端口運行的redis server          
[root@host1 config]# redis-cli -p 7000 cluster nodes    # 查看集羣的節點信息
c96589b19b8ff5d9d286d470b8efff9a540726d8 192.168.81.101:7000 master - 0 1539720810075 5 connected
53911425f4479ce4f054b8b714f4700715f0dc64 192.168.81.101:7002 master - 0 1539720807558 3 connected
bb88f0996503bac3b222b9cc4ec25139ad34ed3a 192.168.81.101:7001 master - 0 1539720804033 4 connected
45d79e730593df3216a4236a19c21ff601949449 127.0.0.1:7001 master - 0 1539720809067 1 connected 5462-10922        # 7001端口運行的redis server的槽編號爲5462號到10922號槽
d20aa403c5d7d9507adcc4ef6132c14f3c9486ed 127.0.0.1:7000 myself,master - 0 0 2 connected 0-5461                            # 7000端口運行的redis server的槽編號爲0號到5461號槽
e5ea887c98e79ef2b2205d6cc1d7ac5cfe936d9a 127.0.0.1:7002 master - 0 1539720808061 0 connected 10923-16383       # 7002端口運行的redis server的槽編號爲10922號到16383號槽
[root@host1 config]# redis-cli -p 7000 cluster info     # 查看集羣的信息
cluster_state:ok                    # 集羣狀態爲ok狀態
cluster_slots_assigned:16384        # 集羣已經被分配16384個槽
cluster_slots_ok:16384              # 集羣中狀態爲ok的槽有16384個
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6               # 集羣有6個節點
cluster_size:3                      # 集羣大小爲3個
cluster_current_epoch:5
cluster_my_epoch:2
cluster_stats_messages_sent:2950
cluster_stats_messages_received:2950
[root@host1 config]# redis-cli -p 7001 cluster info 
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:5
cluster_my_epoch:1
cluster_stats_messages_sent:3158
cluster_stats_messages_received:3158
[root@host1 config]# redis-cli -p 7002 cluster info 
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:5
cluster_my_epoch:0
cluster_stats_messages_sent:2828
cluster_stats_messages_received:2828
[root@host1 config]# redis-cli -p 7000
127.0.0.1:7000> set hello world     # 成功向集羣中寫入數據
OK
127.0.0.1:7000> config get cluster* # 獲取集羣的配置信息
1) "cluster-node-timeout"
2) "15000"
3) "cluster-migration-barrier"
4) "1"
5) "cluster-slave-validity-factor"
6) "10"
7) "cluster-require-full-coverage"
8) "no"
127.0.0.1:7000> exit

(7)在192.168.81.101虛擬機上操作

[root@mysql config]# redis-cli -p 7002 cluster nodes        # 查看集羣的節點信息,都是master
bb88f0996503bac3b222b9cc4ec25139ad34ed3a 127.0.0.1:7001 master - 0 1539693824725 4 connected
53911425f4479ce4f054b8b714f4700715f0dc64 192.168.81.101:7002 myself,master - 0 0 3 connected
d20aa403c5d7d9507adcc4ef6132c14f3c9486ed 192.168.81.100:7000 master - 0 1539693826743 2 connected 0-5461
e5ea887c98e79ef2b2205d6cc1d7ac5cfe936d9a 192.168.81.100:7002 master - 0 1539693829260 0 connected 10923-16383
c96589b19b8ff5d9d286d470b8efff9a540726d8 192.168.81.101:7000 master - 0 1539693830266 5 connected
45d79e730593df3216a4236a19c21ff601949449 192.168.81.100:7001 master - 0 1539693828252 1 connected 5462-10922
[root@mysql config]# redis-cli -p 7000 cluster replicate d20aa403c5d7d9507adcc4ef6132c14f3c9486ed        # 使192.168.81.101:7000端口運行的redis server做爲192.168.81.100:7000端口運行的redis server的master
OK
[root@mysql config]# redis-cli -p 7001 cluster replicate 45d79e730593df3216a4236a19c21ff601949449
OK
[root@mysql config]# redis-cli -p 7002 cluster replicate e5ea887c98e79ef2b2205d6cc1d7ac5cfe936d9a 
OK
[root@mysql config]# redis-cli -p 7002 cluster nodes        # 查看集羣的節點信息
bb88f0996503bac3b222b9cc4ec25139ad34ed3a 127.0.0.1:7001 slave 45d79e730593df3216a4236a19c21ff601949449 0 1539693962338 4 connected
53911425f4479ce4f054b8b714f4700715f0dc64 192.168.81.101:7002 myself,slave e5ea887c98e79ef2b2205d6cc1d7ac5cfe936d9a 0 0 3 connected
d20aa403c5d7d9507adcc4ef6132c14f3c9486ed 192.168.81.100:7000 master - 0 1539693958297 2 connected 0-5461
e5ea887c98e79ef2b2205d6cc1d7ac5cfe936d9a 192.168.81.100:7002 master - 0 1539693960324 0 connected 10923-16383
c96589b19b8ff5d9d286d470b8efff9a540726d8 192.168.81.101:7000 slave d20aa403c5d7d9507adcc4ef6132c14f3c9486ed 0 1539693961329 5 connected
45d79e730593df3216a4236a19c21ff601949449 192.168.81.100:7001 master - 0 1539693963347 1 connected 5462-10922
[root@mysql config]# redis-cli -p 7002 cluster slots        # 查看集羣的槽與節點的關係
1) 1) (integer) 0
   2) (integer) 5461
   3) 1) "192.168.81.100"
      2) (integer) 7000
      3) "d20aa403c5d7d9507adcc4ef6132c14f3c9486ed"
   4) 1) "192.168.81.101"
      2) (integer) 7000
      3) "c96589b19b8ff5d9d286d470b8efff9a540726d8"
2) 1) (integer) 10923
   2) (integer) 16383
   3) 1) "192.168.81.100"
      2) (integer) 7002
      3) "e5ea887c98e79ef2b2205d6cc1d7ac5cfe936d9a"
   4) 1) "192.168.81.101"
      2) (integer) 7002
      3) "53911425f4479ce4f054b8b714f4700715f0dc64"
3) 1) (integer) 5462
   2) (integer) 10922
   3) 1) "192.168.81.100"
      2) (integer) 7001
      3) "45d79e730593df3216a4236a19c21ff601949449"
   4) 1) "127.0.0.1"
      2) (integer) 7001
      3) "bb88f0996503bac3b222b9cc4ec25139ad34ed3a"

(8)向集羣中寫入數據

[root@host1 config]# redis-cli -c -p 7000
127.0.0.1:7000> set hello world
OK
127.0.0.1:7000> exit

基本的環境已經搭建完畢

下面看一下集羣擴容
(1)在192.168.81.100虛擬機上生成配置文件,並啓動redis server

[root@host1 config]# ls
add_slots.sh  redis_7000.conf  redis_7001.conf  redis_7002.conf
[root@host1 config]# sed 's/7000/7003/g' redis_7000.conf > redis_7003.conf  # 生成配置文件
[root@host1 config]# redis-server /opt/config/redis_7003.conf               # 啓動redis-server
[root@host1 config]# ps aux | grep redis-server
root       2553  0.2  0.7 142904  7552 ?        Ssl  12:23   0:12 redis-server 0.0.0.0:7000 [cluster]
root       2557  0.2  0.7 142904  7548 ?        Ssl  12:23   0:13 redis-server 0.0.0.0:7001 [cluster]
root       2561  0.2  0.7 142904  7556 ?        Ssl  12:23   0:13 redis-server 0.0.0.0:7002 [cluster]
root       2596  0.1  0.5 142904  5336 ?        Ssl  13:53   0:00 redis-server 0.0.0.0:7003 [cluster]
root       2600  0.0  0.0 112648   964 pts/0    R+   13:53   0:00 grep --color=auto redis-server

(2)在192.168.81.101虛擬機上生成配置文件,並啓動redis-server

[root@mysql config]# ls
dump.rdb  redis_7000.conf  redis_7001.conf  redis_7002.conf
[root@mysql config]# sed 's/7000/7003/g' redis_7000.conf > redis_7003.conf      # 生成配置文件
[root@mysql config]# ls
dump.rdb  redis_7000.conf  redis_7001.conf  redis_7002.conf  redis_7003.conf
[root@mysql config]# redis-server /opt/config/redis_7003.conf   # 指定配置文件,啓動redis-server
[root@mysql config]# ps aux | grep redis-server
root       1948  0.2  0.3 142916  7560 ?        Ssl  12:21   0:13 redis-server 0.0.0.0:7002 [cluster]
root       1952  0.2  0.3 142916  7560 ?        Ssl  12:21   0:12 redis-server 0.0.0.0:7001 [cluster]
root       1964  0.2  0.3 142916  7356 ?        Ssl  12:21   0:12 redis-server 0.0.0.0:7000 [cluster]
root       7348  0.0  0.2 142916  5352 ?        Ssl  13:53   0:00 redis-server 0.0.0.0:7003 [cluster]
root       7352  0.0  0.0 112664   972 pts/0    R+   13:53   0:00 grep --color=auto redis-server

(3)在192.168.81.101虛擬機上執行meet操作,對集羣擴容

[root@mysql config]# redis-cli -p 7000 cluster meet 127.0.0.1 7003          # 對新添加的redis-server執行meet操作
OK
[root@mysql config]# redis-cli -p 7000 cluster meet 192.168.81.100 7003
OK
[root@mysql config]# redis-cli -p 7000 cluster nodes            # 查看集羣的節點信息
6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:7002 slave cb8c114d44d289687798508232d31e0a065fdab5 0 1539755696566 4 connected
ac153a3c1fb10d9d502b153c32dec65c85b2f97c 192.168.81.100:7002 slave fceba6001b95e2169ddd6622436b213324fe8f77 0 1539755699589 6 connected
71f5695dc1f4322c8ea9066d1b3cd8bb0ab7a329 192.168.81.100:7001 slave cf74b2d9570665b74525802462c74cf2e072ef99 0 1539755694553 5 connected
27266dcfd098dfe2a42361d6ab59edf8fb9f5413 192.168.81.100:7003 master - 0 1539755697570 7 connected       # 已經添加到集羣中了
cb8c114d44d289687798508232d31e0a065fdab5 192.168.81.100:7000 master - 0 1539755694553 4 connected 5461-10922
fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:7001 master - 0 1539755698572 2 connected 10923-16383
cf74b2d9570665b74525802462c74cf2e072ef99 192.168.81.101:7000 myself,master - 0 0 1 connected 0-5460
2ff22acb1e006b9881abc80238e15b4e3fcefbef 127.0.0.1:7003 master - 0 1539755695560 0 connected       # 已經添加到集羣中了
[root@mysql config]# redis-cli -p 7000 cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:8
cluster_size:3
cluster_current_epoch:7
cluster_my_epoch:1
cluster_stats_messages_sent:11829
cluster_stats_messages_received:11829
[root@mysql config]# redis-cli -p 7003 cluster replicate 27266dcfd098dfe2a42361d6ab59edf8fb9f5413        # 綁定主從關係
OK
[root@mysql config]# redis-cli -p 7003 cluster nodes 
27266dcfd098dfe2a42361d6ab59edf8fb9f5413 192.168.81.100:7003 master - 0 1539756040013 7 connected
2ff22acb1e006b9881abc80238e15b4e3fcefbef 192.168.81.101:7003 myself,slave 27266dcfd098dfe2a42361d6ab59edf8fb9f5413 0 0 0 connected
cb8c114d44d289687798508232d31e0a065fdab5 192.168.81.100:7000 master - 0 1539756035980 4 connected 5461-10922
ac153a3c1fb10d9d502b153c32dec65c85b2f97c 192.168.81.100:7002 slave fceba6001b95e2169ddd6622436b213324fe8f77 0 1539756037488 2 connected
cf74b2d9570665b74525802462c74cf2e072ef99 127.0.0.1:7000 master - 0 1539756040516 1 connected 0-5460
6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:7002 slave cb8c114d44d289687798508232d31e0a065fdab5 0 1539756038998 4 connected
fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:7001 master - 0 1539756041017 2 connected 10923-16383
71f5695dc1f4322c8ea9066d1b3cd8bb0ab7a329 192.168.81.100:7001 slave cf74b2d9570665b74525802462c74cf2e072ef99 1539756042024 1539756037992 1 connected

Redis原生命令搭建集羣

優點

  • 可以深入理解Redis Cluster架構

缺點

  • 容易出差錯,生產環境中不建議使用

(二)使用redis-trib.rb工具搭建集羣

環境說明:
兩臺虛擬機,IP地址分別爲:192.168.81.100和192.168.81.101
虛擬機系統爲:CentOS 7.5
Redis爲yum安裝,版本爲3.2
系統環境:關閉firewalld
Redis Cluster集羣節點包括:192.168.81.101機器的9000.9001,9002端口運行的redis-server以及192.168.81.100機器的9000.9001,9002端口運行的redis-server

步驟:
(1)Ruby環境準備
官網下載Ruby源碼包,解壓,編譯,安裝,進行軟鏈接

(2)Ruby環境安裝redis模塊

[root@mysql ruby_package]# ruby -v              # ruby安裝完成,查看版本
ruby 2.3.7p456 (2018-03-28 revision 63024) [x86_64-linux]
[root@mysql ruby_package]# gem install redis    # 安裝ruby操作redis模塊
Successfully installed redis-4.0.2
Parsing documentation for redis-4.0.2
Done installing documentation for redis after 0 seconds
1 gem installed
[root@mysql ruby_package]# gem list -- check    # 查看ruby環境已經安裝的模塊

*** LOCAL GEMS ***

bigdecimal (1.2.8)
did_you_mean (1.0.0)
io-console (0.4.5)
json (1.8.3.1)
minitest (5.8.5)
net-telnet (0.1.1)
power_assert (0.2.6)
psych (2.1.0.1)
rake (10.4.2)
rdoc (4.2.1)
redis (4.0.2, 3.3.0)
test-unit (3.1.5)

(3)獲取redis-trib.rb工具

[root@mysql ruby_package]# rz       # 從Redis官網下載Redis安裝包,並上傳到虛擬機中
rz waiting to receive.
Starting zmodem transfer.  Press Ctrl+C to cancel.
Transferring redis-3.2.12.tar.gz...
  100%    1515 KB    1515 KB/sec    00:00:01       0 Errors  

[root@mysql ruby_package]# ls
redis-3.2.12.tar.gz  ruby-2.3.7  ruby-2.3.7.tar.gz  rubygems-2.7.7.zip
[root@mysql ruby_package]# tar xf redis-3.2.12.tar.gz       # 對Redis安裝包進行解壓
[root@mysql ruby_package]# ls
[root@mysql ruby_package]# cd redis-3.2.12/src      # 進入Redis目錄的src目錄下
[root@mysql src]# ls
adlist.c     asciilogo.h  crc64.h       help.h         Makefile.dep     quicklist.h        release.c      setproctitle.c  t_hash.c      zipmap.c
adlist.h     bio.c        db.c          hyperloglog.c  memtest.c        rand.c             replication.c  sha1.c          t_list.c      zipmap.h
ae.c         bio.h        debug.c       intset.c       mkreleasehdr.sh  rand.h             rio.c          sha1.h          t_set.c       zmalloc.c
ae_epoll.c   bitops.c     debugmacro.h  intset.h       multi.c          rdb.c              rio.h          slowlog.c       t_string.c    zmalloc.h
ae_evport.c  blocked.c    dict.c        latency.c      networking.c     rdb.h              scripting.c    slowlog.h       t_zset.c
ae.h         cluster.c    dict.h        latency.h      notify.c         redisassert.h      sdsalloc.h     solarisfixes.h  util.c
ae_kqueue.c  cluster.h    endianconv.c  lzf_c.c        object.c         redis-benchmark.c  sds.c          sort.c          util.h
ae_select.c  config.c     endianconv.h  lzf_d.c        pqsort.c         redis-check-aof.c  sds.h          sparkline.c     valgrind.sup
anet.c       config.h     fmacros.h     lzf.h          pqsort.h         redis-check-rdb.c  sentinel.c     sparkline.h     version.h
anet.h       crc16.c      geo.c         lzfP.h         pubsub.c         redis-cli.c        server.c       syncio.c        ziplist.c
aof.c        crc64.c      geo.h         Makefile       quicklist.c      redis-trib.rb      server.h       testhelp.h      ziplist.h
[root@mysql src]# cp redis-trib.rb /usr/bin     # 把redis-trib.rb拷貝到/usr/bin目錄下
[root@mysql src]# redis-trib.rb                 # 查看redis-trib.rb的幫助文檔
Usage: redis-trib <command> <options> <arguments ...>

  create          mysql:port1 ... hostN:portN
                  --replicas <arg>
  check           host:port
  info            host:port
  fix             host:port
                  --timeout <arg>
  reshard         host:port
                  --from <arg>
                  --to <arg>
                  --slots <arg>
                  --yes
                  --timeout <arg>
                  --pipeline <arg>
  rebalance       host:port
                  --weight <arg>
                  --auto-weights
                  --use-empty-masters
                  --timeout <arg>
                  --simulate
                  --pipeline <arg>
                  --threshold <arg>
  add-node        new_host:new_port existing_host:existing_port
                  --slave
                  --master-id <arg>
  del-node        host:port node_id
  set-timeout     host:port milliseconds
  call            host:port command arg arg .. arg
  import          host:port
                  --from <arg>
                  --copy
                  --replace
  help            (show this help)

For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.

(4)在192.168.81.101虛擬機上創建配置文件,並非常用啓動Redis server

[root@mysql ~]# ps aux | grep redis-server
root       1684  0.0  0.0 112664   972 pts/0    R+   11:44   0:00 grep --color=auto redis-server
[root@mysql ~]# cd /opt/config/
[root@mysql config]# ls
redis_7000.conf  redis_7001.conf  redis_7002.conf
[root@mysql config]# sed 's/7000/9000/g' redis_7000.conf > redis_9000.conf      # 創建redis_9000.conf配置文件
[root@mysql config]# sed 's/7000/9001/g' redis_7000.conf > redis_9001.conf      # 創建redis_9001.conf配置文件
[root@mysql config]# sed 's/7000/9002/g' redis_7000.conf > redis_9002.conf      # 創建redis_9002.conf配置文件
[root@mysql config]# redis-server /opt/config/redis_9000.conf       # 指定配置文件,啓動redis-server
[root@mysql config]# redis-server /opt/config/redis_9001.conf       # 指定配置文件,啓動redis-server
[root@mysql config]# redis-server /opt/config/redis_9002.conf       # 指定配置文件,啓動redis-server
[root@mysql config]# ps aux | grep redis-server         # 查看已經啓動的redis-server
root       1948  0.2  0.3 142916  7572 ?        Ssl  12:21   0:02 redis-server 0.0.0.0:9002 [cluster]
root       1952  0.2  0.3 142916  7560 ?        Ssl  12:21   0:02 redis-server 0.0.0.0:9001 [cluster]
root       1964  0.2  0.3 142916  7356 ?        Ssl  12:21   0:02 redis-server 0.0.0.0:9000 [cluster]
root       6640  0.0  0.0 112664   972 pts/1    R+   12:42   0:00 grep --color=auto redis-server
[root@mysql config]# cat redis_9000.conf        # redis_9000.conf配置文件內容
port 9000
bind 0.0.0.0
daemonize yes
dir '/var/lib/redis'
logfile '/var/log/redis/redis_9000.log'
dbfilename 'redis_9000.data'
cluster-enabled yes
cluster-config-file nodes-9000.conf
cluster-require-full-coverage no
[root@mysql config]# redis-cli -p 9000 cluster nodes        # 查看集羣中節點的信息,都只顯示自身節點
5eba129e4f4a4be2ffe630fe9fac19ba30f5b419 :9000 myself,master - 0 0 0 connected
[root@mysql config]# redis-cli -p 9001 cluster nodes        # 查看集羣中節點的信息,都只顯示自身節點
32d2d969c41f4af646b1052f10d69fd29510f3e4 :9001 myself,master - 0 0 0 connected
[root@mysql config]# redis-cli -p 9002 cluster nodes        # 查看集羣中節點的信息,都只顯示自身節點
6c43b4ddfeaeb3030af397e7469bb0d0b7673979 :9002 myself,master - 0 0 0 connected

使用同樣的步驟,在192.168.81.100虛擬機上生成配置文件:redis_9000.conf,redis_9001.conf,redis_9002.conf

(5)在192.168.81.101虛擬機上使用redis-trib.rb工具構建集羣

[root@mysql config]# redis-trib.rb create --replicas 1 127.0.0.1:9000 127.0.0.1:9001 127.0.0.1:9002 192.168.81.100:9000 192.168.81.100:9001 192.168.81.100:9002         # 構建集羣,replicas後的參數爲集羣的節點
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:            # 指定master
127.0.0.1:9000
192.168.81.100:9000
127.0.0.1:9001
Adding replica 192.168.81.100:9001 to 127.0.0.1:9000        # 爲master添加slave
Adding replica 127.0.0.1:9002 to 192.168.81.100:9000
Adding replica 192.168.81.100:9002 to 127.0.0.1:9001
M: cf74b2d9570665b74525802462c74cf2e072ef99 127.0.0.1:9000
   slots:0-5460 (5461 slots) master
M: fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:9001
   slots:10923-16383 (5461 slots) master
S: 6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:9002
   replicates cb8c114d44d289687798508232d31e0a065fdab5
M: cb8c114d44d289687798508232d31e0a065fdab5 192.168.81.100:9000
   slots:5461-10922 (5462 slots) master
S: 71f5695dc1f4322c8ea9066d1b3cd8bb0ab7a329 192.168.81.100:9001
   replicates cf74b2d9570665b74525802462c74cf2e072ef99
S: ac153a3c1fb10d9d502b153c32dec65c85b2f97c 192.168.81.100:9002
   replicates fceba6001b95e2169ddd6622436b213324fe8f77
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join..........
>>> Performing Cluster Check (using node 127.0.0.1:9000)
M: cf74b2d9570665b74525802462c74cf2e072ef99 127.0.0.1:9000
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
M: cb8c114d44d289687798508232d31e0a065fdab5 192.168.81.100:9000
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
S: 6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:9002
   slots: (0 slots) slave
   replicates cb8c114d44d289687798508232d31e0a065fdab5
M: fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:9001
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: ac153a3c1fb10d9d502b153c32dec65c85b2f97c 192.168.81.100:9002
   slots: (0 slots) slave
   replicates fceba6001b95e2169ddd6622436b213324fe8f77
S: 71f5695dc1f4322c8ea9066d1b3cd8bb0ab7a329 192.168.81.100:9001
   slots: (0 slots) slave
   replicates cf74b2d9570665b74525802462c74cf2e072ef99
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

需要注意的是:如果上面的操作中,一直阻塞在’Waiting for the cluster to join’,則是因爲meet操作阻塞,可以手動進行meet操作

具體步驟爲:在當前虛擬機上另開啓一個命令提示符,進行meet操作

[root@mysql ~]# redis-cli -p 9000 cluster meet 127.0.0.1 9001       # 192.168.81.101:9000端口運行的redis-server向192.168.81.101:9001端口運行的redis-server發送meet請求
OK
[root@mysql ~]# redis-cli -p 9000 cluster meet 127.0.0.1 9002       # 192.168.81.101:9000端口運行的redis-server向192.168.81.101:9001端口運行的redis-server發送meet請求
OK
[root@mysql ~]# redis-cli -p 9000 cluster meet 192.168.81.100 9002  # 192.168.81.101:9000端口運行的redis-server向192.168.81.100:9002端口運行的redis-server發送meet請求
OK
[root@mysql ~]# redis-cli -p 9000 cluster meet 192.168.81.100 9001  # 192.168.81.101:9000端口運行的redis-server向192.168.81.100:9001端口運行的redis-server發送meet請求
OK
[root@mysql ~]# redis-cli -p 9000 cluster meet 192.168.81.100 9000  # 192.168.81.101:9000端口運行的redis-server向192.168.81.100:9000端口運行的redis-server發送meet請求
OK
[root@mysql ~]# redis-cli -p 9000 cluster info      # 查看集羣的信息
cluster_state:ok                        # 狀態爲ok
cluster_slots_assigned:16384            # 標記的slot共有16384個
cluster_slots_ok:16384                  # 已分配的slot有16384個
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6                   # 當前集羣共有6個節點
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_sent:1890
cluster_stats_messages_received:1890
[root@mysql ~]# redis-cli -p 9000 cluster nodes         # 查看當前集羣節點信息
cb8c114d44d289687798508232d31e0a065fdab5 192.168.81.100:9000 master - 0 1539751180759 4 connected 5461-10922
6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:9002 slave cb8c114d44d289687798508232d31e0a065fdab5 0 1539751183277 4 connected
fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:9001 master - 0 1539751181266 2 connected 10923-16383
ac153a3c1fb10d9d502b153c32dec65c85b2f97c 192.168.81.100:9002 slave fceba6001b95e2169ddd6622436b213324fe8f77 0 1539751182272 6 connected
71f5695dc1f4322c8ea9066d1b3cd8bb0ab7a329 192.168.81.100:9001 slave cf74b2d9570665b74525802462c74cf2e072ef99 0 1539751180255 5 connected
cf74b2d9570665b74525802462c74cf2e072ef99 127.0.0.1:9000 myself,master - 0 0 1 connected 0-5460      

基本環境搭建完成。


下面看看Redis Cluster擴容集羣
(1)在192.168.81.100虛擬機上準備新節點

[root@host1 config]# ls
add_slots.sh  redis_9000.conf  redis_9001.conf  redis_9002.conf
[root@host1 config]# sed 's/9000/9003/g' redis_9000.conf > redis_9003.conf  # 生成配置文件
[root@host1 config]# redis-server /opt/config/redis_9003.conf               # 指定配置文件啓動redis-server
[root@host1 config]# ps aux | grep redis-server                             # 查看redis-server的進程
root       2553  0.2  0.7 142904  7552 ?        Ssl  12:23   0:12 redis-server 0.0.0.0:9000 [cluster]
root       2557  0.2  0.7 142904  7548 ?        Ssl  12:23   0:13 redis-server 0.0.0.0:9001 [cluster]
root       2561  0.2  0.7 142904  7556 ?        Ssl  12:23   0:13 redis-server 0.0.0.0:9002 [cluster]
root       2596  0.1  0.5 142904  5336 ?        Ssl  13:53   0:00 redis-server 0.0.0.0:9003 [cluster]
root       2600  0.0  0.0 112648   964 pts/0    R+   13:53   0:00 grep --color=auto redis-server

(2)在192.168.81.101虛擬機上生成配置文件,手動擴容集羣

[root@mysql config]# redis-cli -p 9000 cluster meet 127.0.0.1 9003          # 對新添加節點執行meet操作
OK
[root@mysql config]# redis-cli -p 9000 cluster meet 192.168.81.100 9003     # 對新添加節點執行meet操作
OK
[root@mysql config]# redis-cli -p 9000 cluster nodes            # 查看集羣節點信息
6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:9002 slave cb8c114d44d289687798508232d31e0a065fdab5 0 1539755696566 4 connected
ac153a3c1fb10d9d502b153c32dec65c85b2f97c 192.168.81.100:9002 slave fceba6001b95e2169ddd6622436b213324fe8f77 0 1539755699589 6 connected
71f5695dc1f4322c8ea9066d1b3cd8bb0ab7a329 192.168.81.100:9001 slave cf74b2d9570665b74525802462c74cf2e072ef99 0 1539755694553 5 connected
27266dcfd098dfe2a42361d6ab59edf8fb9f5413 192.168.81.100:9003 master - 0 1539755697570 7 connected
cb8c114d44d289687798508232d31e0a065fdab5 192.168.81.100:9000 master - 0 1539755694553 4 connected 5461-10922
fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:9001 master - 0 1539755698572 2 connected 10923-16383
cf74b2d9570665b74525802462c74cf2e072ef99 192.168.81.101:9000 myself,master - 0 0 1 connected 0-5460
2ff22acb1e006b9881abc80238e15b4e3fcefbef 127.0.0.1:9003 master - 0 1539755695560 0 connected
[root@mysql config]# redis-cli -p 9000 cluster info         # 查看集羣信息
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:8
cluster_size:3
cluster_current_epoch:7
cluster_my_epoch:1
cluster_stats_messages_sent:11829
cluster_stats_messages_received:11829
[root@mysql config]# redis-cli -p 9003 cluster replicate 27266dcfd098dfe2a42361d6ab59edf8fb9f5413            # 新添加節點設置主從關係 
OK
[root@mysql config]# redis-cli -p 9003 cluster nodes    # 查看集羣中節點信息
27266dcfd098dfe2a42361d6ab59edf8fb9f5413 192.168.81.100:9003 master - 0 1539756040013 7 connected
2ff22acb1e006b9881abc80238e15b4e3fcefbef 192.168.81.101:9003 myself,slave 27266dcfd098dfe2a42361d6ab59edf8fb9f5413 0 0 0 connected
cb8c114d44d289687798508232d31e0a065fdab5 192.168.81.100:9000 master - 0 1539756035980 4 connected 5461-10922
ac153a3c1fb10d9d502b153c32dec65c85b2f97c 192.168.81.100:9002 slave fceba6001b95e2169ddd6622436b213324fe8f77 0 1539756037488 2 connected
cf74b2d9570665b74525802462c74cf2e072ef99 127.0.0.1:9000 master - 0 1539756040516 1 connected 0-5460
6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:9002 slave cb8c114d44d289687798508232d31e0a065fdab5 0 1539756038998 4 connected
fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:9001 master - 0 1539756041017 2 connected 10923-16383
71f5695dc1f4322c8ea9066d1b3cd8bb0ab7a329 192.168.81.100:9001 slave cf74b2d9570665b74525802462c74cf2e072ef99 1539756042024 1539756037992 1 connected

(3)在192.168.81.101虛擬機上生成配置文件,使用redis-trib.rb工具擴容集羣
說明:
向集羣中添加192.168.81.100:9003和192.168.81.101:9003節點
建議使用redis-trib.rb工具,避免新節點已經加入了其他集羣,造成故障

[root@mysql config]# ls
dump.rdb  redis_9000.conf  redis_9001.conf  redis_9002.conf
[root@mysql config]# sed 's/9000/9003/g' redis_9000.conf > redis_9003.conf      # 生成配置文件
[root@mysql config]# ls
dump.rdb  redis_9000.conf  redis_9001.conf  redis_9002.conf  redis_9003.conf
[root@mysql config]# redis-server /opt/config/redis_9003.conf       # 指定配置文件運行redis-server
[root@mysql config]# ps aux | grep redis-server                     # 查看redis-server的進程信息
root       1948  0.2  0.3 142916  7560 ?        Ssl  12:21   0:13 redis-server 0.0.0.0:9002 [cluster]
root       1952  0.2  0.3 142916  7560 ?        Ssl  12:21   0:12 redis-server 0.0.0.0:9001 [cluster]
root       1964  0.2  0.3 142916  7356 ?        Ssl  12:21   0:12 redis-server 0.0.0.0:9000 [cluster]
root       7348  0.0  0.2 142916  5352 ?        Ssl  13:53   0:00 redis-server 0.0.0.0:9003 [cluster]
root       7352  0.0  0.0 112664   972 pts/0    R+   13:53   0:00 grep --color=auto redis-server
[root@mysql config]# redis-trib.rb add-node 127.0.0.1:9003 192.168.81.100:9003     # 向集羣添加節點
[root@mysql config]# redis-cli -p 9000 cluster nodes        # 查看集羣的節點信息
2ff22acb1e006b9881abc80238e15b4e3fcefbef 127.0.0.1:9003 slave 27266dcfd098dfe2a42361d6ab59edf8fb9f5413 0 1539826328082 7 connected
6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:9002 master - 0 1539826326067 9 connected 5461-10922
fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:9001 master - 0 1539826330601 2 connected 10923-16383
ac153a3c1fb10d9d502b153c32dec65c85b2f97c 192.168.81.100:9002 slave fceba6001b95e2169ddd6622436b213324fe8f77 0 1539826331108 6 connected
cb8c114d44d289687798508232d31e0a065fdab5 192.168.81.100:9000 slave 6f369311b0ca4c503f337c4bb23424eed3eeb188 0 1539826332115 9 connected
27266dcfd098dfe2a42361d6ab59edf8fb9f5413 192.168.81.100:9003 master - 0 1539826329091 7 connected
cf74b2d9570665b74525802462c74cf2e072ef99 192.168.81.101:9000 myself,master - 0 0 1 connected 0-5460
71f5695dc1f4322c8ea9066d1b3cd8bb0ab7a329 192.168.81.100:9001 slave cf74b2d9570665b74525802462c74cf2e072ef99 0 1539826330098 5 connected
[root@mysql config]# redis-trib.rb reshard 127.0.0.1:9000       # 遷移槽
>>> Performing Cluster Check (using node 127.0.0.1:9000)
M: cf74b2d9570665b74525802462c74cf2e072ef99 127.0.0.1:9000
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
S: 2ff22acb1e006b9881abc80238e15b4e3fcefbef 127.0.0.1:9003
   slots: (0 slots) slave
   replicates 27266dcfd098dfe2a42361d6ab59edf8fb9f5413
M: 6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:9002
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
M: fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:9001
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: ac153a3c1fb10d9d502b153c32dec65c85b2f97c 192.168.81.100:9002
   slots: (0 slots) slave
   replicates fceba6001b95e2169ddd6622436b213324fe8f77
S: cb8c114d44d289687798508232d31e0a065fdab5 192.168.81.100:9000
   slots: (0 slots) slave
   replicates 6f369311b0ca4c503f337c4bb23424eed3eeb188
M: 27266dcfd098dfe2a42361d6ab59edf8fb9f5413 192.168.81.100:9003
   slots: (0 slots) master
   1 additional replica(s)
S: 71f5695dc1f4322c8ea9066d1b3cd8bb0ab7a329 192.168.81.100:9001
   slots: (0 slots) slave
   replicates cf74b2d9570665b74525802462c74cf2e072ef99
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
How many slots do you want to move (from 1 to 16384)? 4096
What is the receiving node ID? 27266dcfd098dfe2a42361d6ab59edf8fb9f5413
Please enter all the source node IDs.
  Type 'all' to use all the nodes as source nodes for the hash slots.
  Type 'done' once you entered all the source nodes IDs.
Source node #1:all

Ready to move 4096 slots.
  Source nodes:
    M: cf74b2d9570665b74525802462c74cf2e072ef99 127.0.0.1:9000
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
    M: 6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:9002
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
    M: fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:9001
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
  Destination node:
    M: 27266dcfd098dfe2a42361d6ab59edf8fb9f5413 192.168.81.100:9003
   slots: (0 slots) master
   1 additional replica(s)
  Resharding plan:
    Moving slot 5461 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5462 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5463 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5464 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5465 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5466 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5467 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5468 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5469 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5470 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5471 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5472 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5473 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5474 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5475 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5476 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5477 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5478 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5479 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5480 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5481 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5482 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5483 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5484 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5485 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5486 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5487 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5488 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5489 from 6f369311b0ca4c503f337c4bb23424eed3eeb188
    Moving slot 5490 from 6f369311b0ca4c503f337c4bb23424eed3eeb188

Moving slot 12283 from 127.0.0.1:9001 to 192.168.81.100:9003: 
Moving slot 12284 from 127.0.0.1:9001 to 192.168.81.100:9003: 
Moving slot 12285 from 127.0.0.1:9001 to 192.168.81.100:9003: 
Moving slot 12286 from 127.0.0.1:9001 to 192.168.81.100:9003: 
Moving slot 12287 from 127.0.0.1:9001 to 192.168.81.100:9003: 
[root@mysql config]# redis-cli -p 9000 cluster slots            # 查看集羣中槽的信息
1) 1) (integer) 6827
   2) (integer) 10922
   3) 1) "127.0.0.1"
      2) (integer) 9002
      3) "6f369311b0ca4c503f337c4bb23424eed3eeb188"
   4) 1) "192.168.81.100"
      2) (integer) 9000
      3) "cb8c114d44d289687798508232d31e0a065fdab5"
2) 1) (integer) 12288
   2) (integer) 16383
   3) 1) "127.0.0.1"
      2) (integer) 9001
      3) "fceba6001b95e2169ddd6622436b213324fe8f77"
   4) 1) "192.168.81.100"
      2) (integer) 9002
      3) "ac153a3c1fb10d9d502b153c32dec65c85b2f97c"
3) 1) (integer) 0
   2) (integer) 1364
   3) 1) "192.168.81.100"
      2) (integer) 9003
      3) "27266dcfd098dfe2a42361d6ab59edf8fb9f5413"
   4) 1) "127.0.0.1"
      2) (integer) 9003
      3) "2ff22acb1e006b9881abc80238e15b4e3fcefbef"
4) 1) (integer) 5461
   2) (integer) 6826
   3) 1) "192.168.81.100"
      2) (integer) 9003
      3) "27266dcfd098dfe2a42361d6ab59edf8fb9f5413"
   4) 1) "127.0.0.1"
      2) (integer) 9003
      3) "2ff22acb1e006b9881abc80238e15b4e3fcefbef"
5) 1) (integer) 10923
   2) (integer) 12287
   3) 1) "192.168.81.100"
      2) (integer) 9003
      3) "27266dcfd098dfe2a42361d6ab59edf8fb9f5413"
   4) 1) "127.0.0.1"
      2) (integer) 9003
      3) "2ff22acb1e006b9881abc80238e15b4e3fcefbef"
6) 1) (integer) 1365
   2) (integer) 5460
   3) 1) "192.168.81.101"
      2) (integer) 9000
      3) "cf74b2d9570665b74525802462c74cf2e072ef99"
   4) 1) "192.168.81.100"
      2) (integer) 9001
      3) "71f5695dc1f4322c8ea9066d1b3cd8bb0ab7a329"
[root@mysql config]# redis-cli -p 9000 cluster nodes            # 查看集羣中節點的信息
2ff22acb1e006b9881abc80238e15b4e3fcefbef 127.0.0.1:9003 slave 27266dcfd098dfe2a42361d6ab59edf8fb9f5413 0 1539826689921 12 connected
6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:9002 master - 0 1539826692961 9 connected 6827-10922
fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:9001 master - 0 1539826693970 2 connected 12288-16383
ac153a3c1fb10d9d502b153c32dec65c85b2f97c 192.168.81.100:9002 slave fceba6001b95e2169ddd6622436b213324fe8f77 0 1539826688916 6 connected
cb8c114d44d289687798508232d31e0a065fdab5 192.168.81.100:9000 slave 6f369311b0ca4c503f337c4bb23424eed3eeb188 0 1539826693475 9 connected
27266dcfd098dfe2a42361d6ab59edf8fb9f5413 192.168.81.100:9003 master - 0 1539826690944 12 connected 0-1364 5461-6826 10923-12287
cf74b2d9570665b74525802462c74cf2e072ef99 192.168.81.101:9000 myself,master - 0 0 1 connected 1365-5460
71f5695dc1f4322c8ea9066d1b3cd8bb0ab7a329 192.168.81.100:9001 slave cf74b2d9570665b74525802462c74cf2e072ef99 0 1539826691953 5 connected
[root@mysql config]# redis-cli -p 9000 cluster nodes | grep master      # 只查看master的節點信息
6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:9002 master - 0 1539826726695 9 connected 6827-10922
fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:9001 master - 0 1539826728205 2 connected 12288-16383
27266dcfd098dfe2a42361d6ab59edf8fb9f5413 192.168.81.100:9003 master - 0 1539826726192 12 connected 0-1364 5461-6826 10923-12287
cf74b2d9570665b74525802462c74cf2e072ef99 192.168.81.101:9000 myself,master - 0 0 1 connected 1365-5460      

下面再看看.Redis Cluster集羣收縮
說明:把192.168.81.101:9000這個master及對應slave節點從集羣中移除

[root@mysql ~]# redis-cli -p 9000 cluster nodes         # 查看集羣中的節點信息
2ff22acb1e006b9881abc80238e15b4e3fcefbef 127.0.0.1:9003 slave 27266dcfd098dfe2a42361d6ab59edf8fb9f5413 0 1539827599055 12 connected
6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:9002 master - 0 1539827597043 9 connected 6827-10922
fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:9001 master - 0 1539827598049 2 connected 12288-16383
ac153a3c1fb10d9d502b153c32dec65c85b2f97c 192.168.81.100:9002 slave fceba6001b95e2169ddd6622436b213324fe8f77 0 1539827601066 6 connected
cb8c114d44d289687798508232d31e0a065fdab5 192.168.81.100:9000 slave 6f369311b0ca4c503f337c4bb23424eed3eeb188 0 1539827596039 9 connected
27266dcfd098dfe2a42361d6ab59edf8fb9f5413 192.168.81.100:9003 master - 0 1539827600062 12 connected 0-1364 5461-6826 10923-12287
cf74b2d9570665b74525802462c74cf2e072ef99 192.168.81.101:9000 myself,master - 0 0 1 connected 1365-5460         # 要移除的節點的槽編號爲:1365到5460
71f5695dc1f4322c8ea9066d1b3cd8bb0ab7a329 192.168.81.100:9001 slave cf74b2d9570665b74525802462c74cf2e072ef99 0 1539827595029 5 connected
[root@mysql ~]# redis-trib.rb reshard --from cf74b2d9570665b74525802462c74cf2e072ef99 --to 27266dcfd098dfe2a42361d6ab59edf8fb9f5413 --slots 1366 127.0.0.1:9001    # 遷移槽,從192.168.81.101:9000遷移到集羣中別的節點上
>>> Performing Cluster Check (using node 127.0.0.1:9001)
M: fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:9001
   slots:12288-16383 (4096 slots) master
   1 additional replica(s)
S: 71f5695dc1f4322c8ea9066d1b3cd8bb0ab7a329 192.168.81.100:9001
   slots: (0 slots) slave
   replicates cf74b2d9570665b74525802462c74cf2e072ef99
M: 6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:9002
   slots:6827-10922 (4096 slots) master
   1 additional replica(s)
M: 27266dcfd098dfe2a42361d6ab59edf8fb9f5413 192.168.81.100:9003
   slots:0-1364,5461-6826,10923-12287 (4096 slots) master
   1 additional replica(s)
M: cf74b2d9570665b74525802462c74cf2e072ef99 127.0.0.1:9000
   slots:1365-5460 (4096 slots) master
   1 additional replica(s)
S: ac153a3c1fb10d9d502b153c32dec65c85b2f97c 192.168.81.100:9002
   slots: (0 slots) slave
   replicates fceba6001b95e2169ddd6622436b213324fe8f77
S: 2ff22acb1e006b9881abc80238e15b4e3fcefbef 127.0.0.1:9003
   slots: (0 slots) slave
   replicates 27266dcfd098dfe2a42361d6ab59edf8fb9f5413
S: cb8c114d44d289687798508232d31e0a065fdab5 192.168.81.100:9000
   slots: (0 slots) slave
   replicates 6f369311b0ca4c503f337c4bb23424eed3eeb188
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

Ready to move 1366 slots.       # 此次可以遷移1366個槽
  Source nodes:
    M: cf74b2d9570665b74525802462c74cf2e072ef99 127.0.0.1:9000
   slots:1365-5460 (4096 slots) master
   1 additional replica(s)
  Destination node:
    M: 27266dcfd098dfe2a42361d6ab59edf8fb9f5413 192.168.81.100:9003
   slots:0-1364,5461-6826,10923-12287 (4096 slots) master
   1 additional replica(s)
  Resharding plan:
    Moving slot 1365 from cf74b2d9570665b74525802462c74cf2e072ef99
    Moving slot 1366 from cf74b2d9570665b74525802462c74cf2e072ef99
    ...
    Moving slot 2729 from cf74b2d9570665b74525802462c74cf2e072ef99
    Moving slot 2730 from cf74b2d9570665b74525802462c74cf2e072ef99
Do you want to proceed with the proposed reshard plan (yes/no)? yes
Moving slot 1365 from 127.0.0.1:9000 to 192.168.81.100:9003: 
Moving slot 1366 from 127.0.0.1:9000 to 192.168.81.100:9003: 
...
Moving slot 2728 from 127.0.0.1:9000 to 192.168.81.100:9003: 
Moving slot 2729 from 127.0.0.1:9000 to 192.168.81.100:9003: 
Moving slot 2730 from 127.0.0.1:9000 to 192.168.81.100:9003:
[root@mysql ~]# redis-cli -p 9001 cluster nodes             # 查看集羣節點信息
71f5695dc1f4322c8ea9066d1b3cd8bb0ab7a329 192.168.81.100:9001 slave cf74b2d9570665b74525802462c74cf2e072ef99 0 1539827870363 5 connected
6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:9002 master - 0 1539827868350 9 connected 6827-10922
27266dcfd098dfe2a42361d6ab59edf8fb9f5413 192.168.81.100:9003 master - 0 1539827872375 12 connected 0-2730 5461-6826 10923-12287
fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:9001 myself,master - 0 0 2 connected 12288-16383
cf74b2d9570665b74525802462c74cf2e072ef99 127.0.0.1:9000 master - 0 1539827873385 1 connected 2731-5460         # 還有2731到5460號槽還沒有遷移完
ac153a3c1fb10d9d502b153c32dec65c85b2f97c 192.168.81.100:9002 slave fceba6001b95e2169ddd6622436b213324fe8f77 0 1539827867345 6 connected
2ff22acb1e006b9881abc80238e15b4e3fcefbef 127.0.0.1:9003 slave 27266dcfd098dfe2a42361d6ab59edf8fb9f5413 0 1539827869356 12 connected
cb8c114d44d289687798508232d31e0a065fdab5 192.168.81.100:9000 slave 6f369311b0ca4c503f337c4bb23424eed3eeb188 0 1539827871370 9 connected
[root@mysql ~]# redis-trib.rb reshard --from cf74b2d9570665b74525802462c74cf2e072ef99 --to 6f369311b0ca4c503f337c4bb23424eed3eeb188 --slots 2730 127.0.0.1:9002     # 遷移槽,把192.168.81.101:9000剩餘的槽遷移到別的節點                     
>>> Performing Cluster Check (using node 127.0.0.1:9002)
M: 6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:9002
   slots:6827-10922 (4096 slots) master
   1 additional replica(s)
S: cb8c114d44d289687798508232d31e0a065fdab5 192.168.81.100:9000
   slots: (0 slots) slave
   replicates 6f369311b0ca4c503f337c4bb23424eed3eeb188
S: ac153a3c1fb10d9d502b153c32dec65c85b2f97c 192.168.81.100:9002
   slots: (0 slots) slave
   replicates fceba6001b95e2169ddd6622436b213324fe8f77
S: 2ff22acb1e006b9881abc80238e15b4e3fcefbef 127.0.0.1:9003
   slots: (0 slots) slave
   replicates 27266dcfd098dfe2a42361d6ab59edf8fb9f5413
S: 71f5695dc1f4322c8ea9066d1b3cd8bb0ab7a329 192.168.81.100:9001
   slots: (0 slots) slave
   replicates cf74b2d9570665b74525802462c74cf2e072ef99
M: cf74b2d9570665b74525802462c74cf2e072ef99 127.0.0.1:9000
   slots:2731-5460 (2730 slots) master
   1 additional replica(s)
M: fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:9001
   slots:12288-16383 (4096 slots) master
   1 additional replica(s)
M: 27266dcfd098dfe2a42361d6ab59edf8fb9f5413 192.168.81.100:9003
   slots:0-2730,5461-6826,10923-12287 (5462 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

Ready to move 2730 slots.
  Source nodes:
    M: cf74b2d9570665b74525802462c74cf2e072ef99 127.0.0.1:9000
   slots:2731-5460 (2730 slots) master
   1 additional replica(s)
  Destination node:
    M: 6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:9002
   slots:6827-10922 (4096 slots) master
   1 additional replica(s)
  Resharding plan:
    Moving slot 2731 from cf74b2d9570665b74525802462c74cf2e072ef99
    Moving slot 2732 from cf74b2d9570665b74525802462c74cf2e072ef99
    ...
    Moving slot 5459 from cf74b2d9570665b74525802462c74cf2e072ef99
    Moving slot 5460 from cf74b2d9570665b74525802462c74cf2e072ef99
Do you want to proceed with the proposed reshard plan (yes/no)? yes
Moving slot 2731 from 127.0.0.1:9000 to 127.0.0.1:9002: 
Moving slot 2732 from 127.0.0.1:9000 to 127.0.0.1:9002: 
...
Moving slot 5459 from 127.0.0.1:9000 to 127.0.0.1:9002: 
Moving slot 5460 from 127.0.0.1:9000 to 127.0.0.1:9002: 
[root@mysql ~]# redis-cli -p 9001 cluster nodes     # 查看集羣中節點的信息
71f5695dc1f4322c8ea9066d1b3cd8bb0ab7a329 192.168.81.100:9001 slave 6f369311b0ca4c503f337c4bb23424eed3eeb188 0 1539828016103 13 connected
6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:9002 master - 0 1539828017610 13 connected 2731-5460 6827-10922
27266dcfd098dfe2a42361d6ab59edf8fb9f5413 192.168.81.100:9003 master - 0 1539828016605 12 connected 0-2730 5461-6826 10923-12287
fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:9001 myself,master - 0 0 2 connected 12288-16383
cf74b2d9570665b74525802462c74cf2e072ef99 127.0.0.1:9000 master - 0 1539828013588 1 connected       # 192.168.81.101:9000上已經沒有槽了
ac153a3c1fb10d9d502b153c32dec65c85b2f97c 192.168.81.100:9002 slave fceba6001b95e2169ddd6622436b213324fe8f77 0 1539828015601 6 connected
2ff22acb1e006b9881abc80238e15b4e3fcefbef 127.0.0.1:9003 slave 27266dcfd098dfe2a42361d6ab59edf8fb9f5413 0 1539828014593 12 connected
cb8c114d44d289687798508232d31e0a065fdab5 192.168.81.100:9000 slave 6f369311b0ca4c503f337c4bb23424eed3eeb188 0 1539828012582 13 connected
[root@mysql ~]# redis-cli -p 9001 cluster nodes |grep master
6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:9002 master - 0 1539828068951 13 connected 2731-5460 6827-10922
27266dcfd098dfe2a42361d6ab59edf8fb9f5413 192.168.81.100:9003 master - 0 1539828071970 12 connected 0-2730 5461-6826 10923-12287
fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:9001 myself,master - 0 0 2 connected 12288-16383
cf74b2d9570665b74525802462c74cf2e072ef99 127.0.0.1:9000 master - 0 1539828073980 1 connected
[root@mysql ~]# redis-trib.rb del-node 127.0.0.1:9001 cb8c114d44d289687798508232d31e0a065fdab5        # 先移除192.168.81.101:9000的slave節點
>>> Removing node cb8c114d44d289687798508232d31e0a065fdab5 from cluster 127.0.0.1:9001
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
[root@mysql ~]# redis-trib.rb del-node 127.0.0.1:9001 cf74b2d9570665b74525802462c74cf2e072ef99        # 移除192.168.81.101:9000節點
>>> Removing node cf74b2d9570665b74525802462c74cf2e072ef99 from cluster 127.0.0.1:9001
>>> Sending CLUSTER FORGET messages to the cluster...
>>> SHUTDOWN the node.
[root@mysql ~]# redis-cli -p 9000       # 連接192.168.81.101:9000客戶端,顯示連接失敗
Could not connect to Redis at 127.0.0.1:9000: Connection refused
Could not connect to Redis at 127.0.0.1:9000: Connection refused
not connected> exit
[root@mysql ~]# redis-trib.rb del-node 127.0.0.1:9001 cf74b2d9570665b74525802462c74cf2e072ef99        # 移除192.168.81.101:9000節點,顯示移除失敗,因爲集羣中已經沒有這個節點了 
>>> Removing node cf74b2d9570665b74525802462c74cf2e072ef99 from cluster 127.0.0.1:9001
[ERR] No such node ID cf74b2d9570665b74525802462c74cf2e072ef99
[root@mysql ~]# redis-cli -p 9002 cluster nodes     # 查看集羣中的節點信息
6f369311b0ca4c503f337c4bb23424eed3eeb188 127.0.0.1:9002 myself,master - 0 0 13 connected 2731-5460 6827-10922
ac153a3c1fb10d9d502b153c32dec65c85b2f97c 192.168.81.100:9002 slave fceba6001b95e2169ddd6622436b213324fe8f77 0 1539828535088 6 connected
2ff22acb1e006b9881abc80238e15b4e3fcefbef 127.0.0.1:9003 slave 27266dcfd098dfe2a42361d6ab59edf8fb9f5413 0 1539828539118 12 connected
71f5695dc1f4322c8ea9066d1b3cd8bb0ab7a329 192.168.81.100:9001 slave 6f369311b0ca4c503f337c4bb23424eed3eeb188 0 1539828536098 13 connected
fceba6001b95e2169ddd6622436b213324fe8f77 127.0.0.1:9001 master - 0 1539828537106 2 connected 12288-16383
27266dcfd098dfe2a42361d6ab59edf8fb9f5413 192.168.81.100:9003 master - 0 1539828538114 12 connected 0-2730 5461-6826 10923-12287

使用官方工具安裝集羣的優點

  • 簡單高效,準確
  • 生產環境可以使用

(三)Redis Cluster特性

在探討Redis Cluster特性之前,我們要明白爲什麼要實現Redis Cluster?

  1. 主從複製不能實現高可用
  2. 隨着公司發展,用戶數量增多,併發越來越多,業務需要更高的QPS,而主從複製中單機的QPS可能無法滿足業務需求
  3. 數據量的考慮,現有服務器內存不能滿足業務數據的需要時,單純向服務器添加內存不能達到要求,此時需要考慮分佈式需求,把數據分佈到不同服務器上
  4. 網絡流量需求:業務的流量已經超過服務器的網卡的上限值,可以考慮使用分佈式來進行分流
  5. 離線計算,需要中間環節緩衝等別的需求

1.數據分佈

做數據分佈的意義:
全量數據,單機Redis節點無法滿足要求,按照分區規則把數據分到若干個子集當中

在這裏插入圖片描述

(1)常用數據分佈方式之順序分佈
比如:1到100個數字,要保存在3個節點上,按照順序分區,把數據平均分配三個節點上
1號到33號數據保存到節點1上,34號到66號數據保存到節點2上,67號到100號數據保存到節點3上
在這裏插入圖片描述
順序分區常用在關係型數據庫的設計

(2)常用數據分佈方式之哈希分佈
例如1到100個數字,對每個數字進行哈希運算,然後對每個數的哈希結果除以節點數進行取餘,餘數爲1則保存在第1個節點上,餘數爲2則保存在第2個節點上,餘數爲0則保存在第3個節點,這樣可以保證數據被打散,同時保證數據分佈的比較均勻
在這裏插入圖片描述
哈希分佈方式分爲三個分區方式:

2 - 1 節點取餘分區
比如有100個數據,對每個數據進行hash運算之後,與節點數進行取餘運算,根據餘數不同保存在不同的節點上

節點取餘:hash(key)% nodes
在這裏插入圖片描述
節點取餘方式是非常簡單的一種分區方式

節點取餘分區方式有一個問題:即當增加或減少節點時,原來節點中的80%的數據會進行遷移操作,對所有數據重新進行分佈

節點取餘分區方式建議使用多倍擴容的方式,例如以前用3個節點保存數據,擴容爲比以前多一倍的節點即6個節點來保存數據,這樣只需要適移50%的數據。數據遷移之後,第一次無法從緩存中讀取數據,必須先從數據庫中讀取數據,然後回寫到緩存中,然後才能從緩存中讀取遷移之後的數據

在這裏插入圖片描述

節點取餘方式優點:

客戶端分片
配置簡單:對數據進行哈希,然後取餘

節點取餘方式缺點:

數據節點伸縮時,導致數據遷移
遷移數量和添加節點數據有關,建議翻倍擴容

2-2 一致性哈希分區

一致性哈希原理:
將所有的數據當做一個token環,token環中的數據範圍是0到2的32次方。然後爲每一個數據節點分配一個token範圍值,這個節點就負責保存這個範圍內的數據。
在這裏插入圖片描述
對每一個key進行hash運算,被哈希後的結果在哪個token的範圍內,則按順時針去找最近的節點,這個key將會被保存在這個節點上。

在這裏插入圖片描述
擴容
在這裏插入圖片描述
在上面的圖中,有4個key被hash之後的值在在n1節點和n2節點之間,按照順時針規則,這4個key都會被保存在n2節點上,
如果在n1節點和n2節點之間添加n5節點,當下次有key被hash之後的值在n1節點和n5節點之間,這些key就會被保存在n5節點上面了。
在上面的例子裏,添加n5節點之後,數據遷移會在n1節點和n2節點之間進行,n3節點和n4節點不受影響,數據遷移範圍被縮小很多

同理,如果有1000個節點,此時添加一個節點,受影響的節點範圍最多隻有千分之2

一致性哈希一般用在節點比較多的時候

一致性哈希分區優點:

採用客戶端分片方式:哈希 + 順時針(優化取餘)
節點伸縮時,隻影響鄰近節點,但是還是有數據遷移

一致性哈希分區缺點:

翻倍伸縮,保證最小遷移數據和負載均衡

2-3 虛擬槽分區
虛擬槽分區是Redis Cluster採用的分區方式

預設虛擬槽,每個槽就相當於一個數字,有一定範圍。每個槽映射一個數據子集,一般比節點數大

Redis Cluster中預設虛擬槽的範圍爲0到16383
在這裏插入圖片描述
步驟:

  1. 把16384槽按照節點數量進行平均分配,由節點進行管理
  2. 對每個key按照CRC16規則進行hash運算
  3. 把hash結果對16383進行取餘
  4. 把餘數發送給Redis節點
  5. 節點接收到數據,驗證是否在自己管理的槽編號的範圍
    如果在自己管理的槽編號範圍內,則把數據保存到數據槽中,然後返回執行結果
    如果在自己管理的槽編號範圍外,則會把數據發送給正確的節點,由正確的節點來把數據保存在對應的槽中

需要注意的是:Redis Cluster的節點之間會共享消息,每個節點都會知道是哪個節點負責哪個範圍內的數據槽

虛擬槽分佈方式中,由於每個節點管理一部分數據槽,數據保存到數據槽中。當節點擴容或者縮容時,對數據槽進行重新分配遷移即可,數據不會丟失。
虛擬槽分區特點:

使用服務端管理節點,槽,數據:例如Redis Cluster
可以對數據打散,又可以保證數據分佈均勻

順序分佈與哈希分佈的對比

在這裏插入圖片描述

(四)Redis Cluster基本架構

(1)節點
Redis Cluster是分佈式架構:即Redis Cluster中有多個節點,每個節點都負責進行數據讀寫操作
每個節點之間會進行通信。

(2)meet操作
節點之間會相互通信
meet操作是節點之間完成相互通信的基礎,meet操作有一定的頻率和規則

在這裏插入圖片描述
所有的節點共享消息
在這裏插入圖片描述

(3)指派槽
把16384個槽平均分配給節點進行管理,每個節點只能對自己負責的槽進行讀寫操作

由於每個節點之間都彼此通信,每個節點都知道另外節點負責管理的槽範圍
在這裏插入圖片描述
客戶端訪問任意節點時,對數據key按照CRC16規則進行hash運算,然後對運算結果對16383進行取作,如果餘數在當前訪問的節點管理的槽範圍內,則直接返回對應的數據
如果不在當前節點負責管理的槽範圍內,則會告訴客戶端去哪個節點獲取數據,由客戶端去正確的節點獲取數據

1.keyhash=hash(key)
2. slot=keyhash%16383
在這裏插入圖片描述
(4)複製
保證高可用,每個主節點都有一個從節點,當主節點故障,Cluster會按照規則實現主備的高可用性

對於節點來說,有一個配置項:cluster-enabled,即是否以集羣模式啓動

(5) 客戶端路由

5-1moved重定向

  1. 每個節點通過通信都會共享Redis Cluster中槽和集羣中對應節點的關係
  2. 客戶端向Redis Cluster的任意節點發送命令,接收命令的節點會根據CRC16規則進行hash運算與16383取餘,計算自己的槽和對應節點
  3. 如果保存數據的槽被分配給當前節點,則去槽中執行命令,並把命令執行結果返回給客戶端
  4. 如果保存數據的槽不在當前節點的管理範圍內,則向客戶端返回moved重定向異常
  5. 客戶端接收到節點返回的結果,如果是moved異常,則從moved異常中獲取目標節點的信息
  6. 客戶端向目標節點發送命令,獲取命令執行結果

在這裏插入圖片描述

需要注意的是:客戶端不會自動找到目標節點執行命令

槽命中:直接返回

在這裏插入圖片描述

[root@mysql ~]# redis-cli -p 9002 cluster keyslot hello
(integer) 866

槽不命中:moved異常

[root@mysql ~]# redis-cli -p 9002 cluster keyslot php
(integer) 9244

在這裏插入圖片描述

[root@mysql ~]# redis-cli -c -p 9002
127.0.0.1:9002> cluster keyslot hello
(integer) 866
127.0.0.1:9002> set hello world
-> Redirected to slot [866] located at 192.168.81.100:9003
OK
192.168.81.100:9003> cluster keyslot python
(integer) 7252
192.168.81.100:9003> set python best
-> Redirected to slot [7252] located at 192.168.81.101:9002
OK
192.168.81.101:9002> get python
"best"
192.168.81.101:9002> get hello
-> Redirected to slot [866] located at 192.168.81.100:9003
"world"
192.168.81.100:9003> exit
[root@mysql ~]# redis-cli -p 9002
127.0.0.1:9002> cluster keyslot python
(integer) 7252
127.0.0.1:9002> set python best
OK
127.0.0.1:9002> set hello world
(error) MOVED 866 192.168.81.100:9003
127.0.0.1:9002> exit
[root@mysql ~]# 

5-2 ask重定向
在這裏插入圖片描述
在對集羣進行擴容和縮容時,需要對槽及槽中數據進行遷移

當客戶端向某個節點發送命令,節點向客戶端返回moved異常,告訴客戶端數據對應的槽的節點信息

如果此時正在進行集羣擴展或者縮空操作,當客戶端向正確的節點發送命令時,槽及槽中數據已經被遷移到別的節點了,就會返回ask,這就是ask重定向機制
在這裏插入圖片描述
步驟:

  1. 客戶端向目標節點發送命令,目標節點中的槽已經遷移支別的節點上了,此時目標節點會返回ask轉向給客戶端
  2. 客戶端向新的節點發送Asking命令給新的節點,然後再次向新節點發送命令
  3. 新節點執行命令,把命令執行結果返回給客戶端

moved異常與ask異常的相同點和不同點

  • 兩者都是客戶端重定向
  • moved異常:槽已經確定遷移,即槽已經不在當前節點
  • ask異常:槽還在遷移中

5-3 smart智能客戶端
使用智能客戶端的首要目標:追求性能

從集羣中選一個可運行節點,使用Cluster slots初始化槽和節點映射

將Cluster slots的結果映射在本地,爲每個節點創建JedisPool,相當於爲每個redis節點都設置一個JedisPool,然後就可以進行數據讀寫操作

讀寫數據時的注意事項:

每個JedisPool中緩存了slot和節點node的關係
key和slot的關係:對key進行CRC16規則進行hash後與16383取餘得到的結果就是槽
JedisCluster啓動時,已經知道key,slot和node之間的關係,可以找到目標節點
JedisCluster對目標節點發送命令,目標節點直接響應給JedisCluster
如果JedisCluster與目標節點連接出錯,則JedisCluster會知道連接的節點是一個錯誤的節點
此時JedisCluster會隨機節點發送命令,隨機節點返回moved異常給JedisCluster
JedisCluster會重新初始化slot與node節點的緩存關係,然後向新的目標節點發送命令,目標命令執行命令並向JedisCluster響應
如果命令發送次數超過5次,則拋出異常"Too many cluster redirection!"

在這裏插入圖片描述
6. 多節點命令實現
Redis Cluster不支持使用scan命令掃描所有節點
多節點命令就是在在所有節點上都執行一條命令
批量操作優化

6-1 串行mget
定義for循環,遍歷所有的key,分別去所有的Redis節點中獲取值並進行彙總,簡單,但是效率不高,需要n次網絡時間
在這裏插入圖片描述
6-2串行IO
對串行mget進行優化,在客戶端本地做內聚,對每個key進行CRC16hash,然後與16383取餘,就可以知道哪個key對應的是哪個槽

本地已經緩存了槽與節點的對應關係,然後對key按節點進行分組,成立子集,然後使用pipeline把命令發送到對應的node,需要nodes次網絡時間,大大減少了網絡時間開銷
在這裏插入圖片描述
6-3 並行IO
並行IO是對串行IO的一個優化,把key分組之後,根據節點數量啓動對應的線程數,根據多線程模式並行向node節點請求數據,只需要1次網絡時間
在這裏插入圖片描述
6-4 hash_tag
將key進行hash_tag的包裝,然後把tag用大括號括起來,保證所有的key只向一個node請求數據,這樣執行類似mget命令只需要去一個節點獲取數據即可,效率更高
在這裏插入圖片描述
6-5 四種優化方案優缺點分析
在這裏插入圖片描述
7 故障發現

Redis Cluster通過ping/pong消息實現故障發現:不需要sentinel

ping/pong不僅能傳遞節點與槽的對應消息,也能傳遞其他狀態,比如:節點主從狀態,節點故障等

故障發現就是通過這種模式來實現,分爲主觀下線和客觀下線

7-1 主觀下線
某個節點認爲另一個節點不可用,‘偏見’,只代表一個節點對另一個節點的判斷,不代表所有節點的認知

主觀下線流程:

  1. 節點1定期發送ping消息給節點2
  2. 如果發送成功,代表節點2正常運行,節點2會響應PONG消息給節點1,節點1更新與節點2的最後通信時間
  3. 如果發送失敗,則節點1與節點2之間的通信異常判斷連接,在下一個定時任務週期時,仍然會與節點2發送ping消息
  4. 如果節點1發現與節點2最後通信時間超過node-timeout,則把節點2標識爲pfail狀態

在這裏插入圖片描述
7-2 客觀下線
在這裏插入圖片描述
當半數以上持有槽的主節點都標記某節點主觀下線時,可以保證判斷的公平性

集羣模式下,只有主節點(master)纔有讀寫權限和集羣槽的維護權限,從節點(slave)只有複製的權限

客觀下線流程:

  1. 某個節點接收到其他節點發送的ping消息,如果接收到的ping消息中包含了其他fail節點,這個節點會將主觀下線的消息內容添加到自身的故障列表中,故障列表中包含了當前節點接收到的每一個節點對其他節點的狀態信息
  2. 當前節點把主觀下線的消息內容添加到自身的故障列表之後,會嘗試對故障節點進行客觀下線操作
    故障列表的週期爲:集羣的node-timeout * 2,保證以前的故障消息不會對週期內的故障消息造成影響,保證客觀下線的公平性和有效性
    在這裏插入圖片描述

8.故障恢復

8-1 資格檢查

對從節點的資格進行檢查,只有難過檢查的從節點纔可以開始進行故障恢復

每個從節點檢查與故障主節點的斷線時間

超過cluster-node-timeout * cluster-slave-validity-factor數字,則取消資格

cluster-node-timeout默認爲15秒,cluster-slave-validity-factor默認值爲10
如果這兩個參數都使用默認值,則每個節點都檢查與故障主節點的斷線時間,如果超過150秒,則這個節點就沒有成爲替換主節點的可能性

8-2準備選舉時間

使偏移量最大的從節點具備優先級成爲主節點的條件
在這裏插入圖片描述
8-3 選舉投票
對選舉出來的多個從節點進行投票,選出新的主節點
在這裏插入圖片描述

8-4 替換主節點
當前從節點取消複製變成離節點(slaveof no one)
執行cluster del slot撤銷故障主節點負責的槽,並執行cluster add slot把這些槽分配給自己
向集羣廣播自己的pong消息,表明已經替換了故障從節點

8-5 故障轉移演練
對某一個主節點執行kill -9 {pid}來模擬宕機的情況

9.Redis Cluster的缺點
當節點數量很多時,性能不會很高

解決方式:使用智能客戶端。智能客戶端知道由哪個節點負責管理哪個槽,而且當節點與槽的映射關係發生改變時,客戶端也會知道這個改變,這是一種非常高效的方式

(五)開發中常見的問題

(1)集羣完整性
cluster-require-full-coverage默認爲yes,即是否集羣中的所有節點都是在線狀態且16384個槽都處於服務狀態時,集羣纔會提供服務

集羣中16384個槽全部處於服務狀態,保證集羣完整性

當某個節點故障或者正在故障轉移時獲取數據會提示:(error)CLUSTERDOWN The cluster is down

建議把cluster-require-full-coverage設置爲no

(2)帶寬消耗
Redis Cluster節點之間會定期交換Gossip消息,以及做一些心跳檢測

官方建議Redis Cluster節點數量不要超過1000個,當集羣中節點數量過多時,會產生不容忽視的帶寬消耗

消息發送頻率:節點發現與其他節點最後通信時間超過cluster-node-timeout /2時,會直接發送PING消息

消息數據量:slots槽數組(2kb空間)和整個集羣1/10的狀態數據(10個節點狀態數據約爲1kb)

節點部署的機器規模:集羣分佈的機器越多且每臺機器劃分的節點數越均勻,則集羣內整體的可用帶寬越高

帶寬優化:

  • 避免使用’大’集羣:避免多業務使用一個集羣,大業務可以多集羣
  • cluster-node-timeout:帶寬和故障轉移速度的均衡
  • 儘量均勻分配到多機器上:保證高可用和帶寬

(3)Pub/Sub廣播
在任意一個cluster節點執行publish,則發佈的消息會在集羣中傳播,集羣中的其他節點都會訂閱到消息,這樣節點的帶寬的開銷會很大

publish在集羣每個節點廣播,加重帶寬

解決辦法:需要使用Pub/Sub時,爲了保證高可用,可以單獨開啓一套Redis Sentinel

(4)集羣傾斜

對於分佈式數據庫來說,存在傾斜問題是比較常見的

集羣傾斜也就是各個節點使用的內存不一致

4-1 數據傾斜原因
1.節點和槽分配不均,如果使用redis-trib.rb工具構建集羣,則出現這種情況的機會不多

redis-trib.rb info ip:port查看節點,槽,鍵值分佈
redis-trib.rb rebalance ip:port進行均衡(謹慎使用)

2.不同槽對應鍵值數量差異比較大

CRC16算法正常情況下比較均勻
可能存在hash_tag
cluster countkeysinslot {slot}獲取槽對應鍵值個數

3.包含bigkey:例如大字符串,幾百萬的元素的hash,set等

在從節點:redis-cli --bigkeys
優化:優化數據結構

4.內存相關配置不一致
hash-max-ziplist-value:滿足一定條件情況下,hash可以使用ziplist
set-max-intset-entries:滿足一定條件情況下,set可以使用intset
在一個集羣內有若干個節點,當其中一些節點配置上面兩項優化,另外一部分節點沒有配置上面兩項優化
當集羣中保存hash或者set時,就會造成節點數據不均勻
優化:定期檢查配置一致性

5.請求傾斜:熱點key
重要的key或者bigkey
Redis Cluster某個節點有一個非常重要的key,就會存在熱點問題

4-2 集羣傾斜優化:
避免bigkey
熱鍵不要用hash_tag
當一致性不高時,可以用本地緩存+ MQ(消息隊列)

(5)集羣讀寫分離

只讀連接:集羣模式下,從節點不接受任何讀寫請求

當向從節點執行讀請求時,重定向到負責槽的主節點

readonly命令可以讀:連接級別命令,當連接斷開之後,需要再次執行readonly命令

讀寫分離:同樣的問題:複製延遲,讀取過期數據,從節點故障
修改客戶端:cluster slaves {nodeId}

(6)數據遷移

官方遷移工具:redis-trib.rb和import

  • 只能從單機遷移到集羣
  • 不支持在線遷移:source需要停寫
  • 不支持斷點續傳
  • 單線程遷移:影響深度

在線遷移:

唯品會:redis-migrate-tool
豌豆莢:redis-port

(7) 集羣VS單機

集羣的限制:

key批量操作支持有限:例如mget,mset必須在一個slot
key事務和Lua支持有限:操作的key必須在一個節點
key是數據分區的最小粒度:不支持bigkey分區
不支持多個數據庫:集羣模式下只有一個db0
複製只支持一層:不支持樹形複製結構
Redis Cluster滿足容量和性能的擴展性,很多業務'不需要'
大多數時客戶端性能會'降低'
命令無法跨節點使用:mget,keys,scan,flush,sinter等
Lua和事務無法跨節點使用
客戶端維護更復雜:SDK和應用本身消耗(例如更多的連接池)

很多場景Redis Sentinel已經夠用了


還剩一些拓展的內容,準備放在第四篇。

對了,兄dei,如果你覺得這篇文章可以的話,給俺點個贊再走,管不管?這樣可以讓更多的人看到這篇文章,對我來說也是一種激勵。

如果你有什麼問題的話,歡迎留言或者CSDN APP直接與我交流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章