天天看點

高性能網站架構利器--redis必殺技

目錄

1、redis簡介

2、redis主從複制實作

3、sentinel叢集管理工具實作redis的高可用性

4、redis cluster

    4.1、redis cluster環境搭建  

    4.2、redis cluster增加節點

    4.3、redis cluster删除節點

    4.4、redis cluster主從手動切換

5、總結

    Redis是一個開源的使用ANSI C語言編寫、支援網絡、可基于記憶體亦可持久化的日志型、Key-Value資料庫,并提供多種語言的API。從2010年3月15日起,Redis的開發工作由VMware主持。從2013年5月開始,Redis的開發由Pivotal贊助。---來自百度百科

    從redis官網上的介紹上看,redis是一個開放源代碼,遵循BSD許可的記憶體資料結構存儲,可用作資料庫緩存和消息代理。它支援的資料結構不像memcached那麼單一,redis支援豐富的資料結構,如: strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs and geospatial indexes with radius queries。redis支援複制,Lua腳本、基于LRU的記憶體回收機制,并支援事務,而且還支援不同級别上的資料持久性,并支援高可用叢集和自動分區功能。

    redis用戶端支援許多語言的連接配接,如下圖:

高性能網站架構利器--redis必殺技

圖檔來自:http://redis.io/clients

    目前redis穩定的版本為3.0.4,此版本修複了上一版本中的一些bug,并增加了一些新的特性,如果你想了解更多關于這方面的内容請移步https://raw.githubusercontent.com/antirez/redis/3.0/00-RELEASENOTES。

    redis的單節點運作這裡将不再單獨示範,這些内容在接下來的示範中也可發現,本節主要講解redis的主從複制的實作。redis的主從複制是非常簡易用的配置,在這種環境下,主節點允許從節點精确的擁有一份資料的副本,這也是軟體主從架構的重要的一個特性吧,如果這個特性都沒有,那何談主從。接下來看看redis主從架構的一些特性:

a、主從複制是異步進行的,從redis 2.8開始,從節點将定期的告知主節點從節點複制程序的複制量;

b、一主可以拖多從;

c、從節點可以作為其他從節點的主節點,這一點是不是與mysql很像;

d、從節點在進行複制操作時,主節點這端是非阻塞的,在進行複制的過程中主節點可以可以斷續處理查詢,覺得這些說得都比較啰嗦;

e、在複制過程中,從節點也是非阻塞的,如果在主節點的一個資料已被改變,而從節點還沒有被複制更新,那redis可以選擇是以老版本中的資料來響應還是傳回一個錯誤給用戶端,這是可以在redis的配置檔案中指定的;

f、在主從複制架構中,為了均衡redis的性能的資料的持久性,可以把主節點配置為不持久化資料,這樣少了許多把資料寫入磁盤的開銷,而在從節點上啟用資料的持久性,這些我都是可以在配置檔案中指定。

    總結起來,redis的主從架構與mysql的些類似,在最後一點中關于資料的持久性問題上,在實際環境中是不建議關閉主節點的資料持久化功能,因為當主節點出現故障而自動重新開機後,存放在記憶體中的資料被釋放,如果沒有資料持久化,主節點就沒有任何資料,那從節點也會把自己清空。

至于主從架構的實作原理作為運維人員不必再細究了。

    配置一個節點成為主節點的從節點是非常簡單的,隻需要在從節點的配置檔案是增加“slaveof 主節點IP 端口”,預設時從節點是隻讀的,是由“slave-read-only yes”來控制。

    再來考慮一個問題,是任何一個節點都可以成為主節點的從嗎?當然不是,redis也有認證機制來解決這個問題,預設時是沒有啟用此功能,若想啟用此功能,在redis.conf配置檔案中啟用“requirepass 密碼”參數,在将成為從節點的redis上可以用redis-cli用戶端工具連接配接到redis中執行“config set masterauth 密碼”來成為主節點的從,當然這樣的配置隻是臨時生效,若想永久生效還是去修改配置檔案吧。

    言歸正傳,下邊開始搭建redis主從複制環境,先交待一下實驗的基礎環境:

OS IP hostname 角色
Debian 8 x64 192.168.207.128 master
192.168.207.130 slave01

主節點配置:

root@master:~/tools# pwd
/root/tools
root@master:~/tools# cat /etc/issue
Debian GNU/Linux 8 \n \l
root@master:~/tools# uname -r
3.16.0-4-amd64
root@master:~/tools# hostname
master
root@master:~/tools# pwd
/root/tools
root@master:~/tools# ls
redis-3.0.4.tar.gz
root@master:~/tools# tar xf redis-3.0.4.tar.gz -C /usr/local/
root@master:~/tools# cd /usr/local/redis-3.0.4/
root@master:/usr/local/redis-3.0.4# ls
00-RELEASENOTES  CONTRIBUTING  depsMakefile   README      runtest runtest-sentinel  src utils
BUGS COPYING       INSTALLMANIFESTO  redis.conf  runtest-clustersentinel.conf  tests
#可以參考一下README檔案,有具體的安裝方法
root@master:/usr/local/redis-3.0.4# ls src/redis     #列出src目錄下以redis開頭的檔案,現在是沒有redis的啟動程式和用戶端連接配接工具的
redisassert.h       redis.c             redis-check-dump.c  redis.h            
redis-benchmark.c   redis-check-aof.c   redis-cli.c         redis-trib.rb  
root@master:/usr/local/redis-3.0.4#  make   #直接編譯即可
最後輸出:
Hint: It's a good idea to run 'make test' ;)
make[1]: Leaving directory '/usr/local/redis-3.0.4/src'
表示安裝成功,上邊建議運作make test進行檢測
root@master:/usr/local/redis-3.0.4# make test
cd src && make test
make[1]: Entering directory '/usr/local/redis-3.0.4/src'
You need tcl 8.5 or newer in order to run the Redis test
Makefile:211: recipe for target 'test' failed
make[1]: *** [test] Error 1
make[1]: Leaving directory '/usr/local/redis-3.0.4/src'
Makefile:6: recipe for target 'test' failed
make: *** [test] Error 2
#上邊報錯了,是需要tcl依賴包,如果你真想運作make test那請自行安裝tcl包後再執行檢測指令,我這裡略過做make test的操作。
root@master:/usr/local/redis-3.0.4# ls src/redis   #和make之前相比多了一些檔案
redisassert.h       redis.c             redis-check-dump    redis-cli.c         redis-sentinel      
redis-benchmark     redis-check-aof     redis-check-dump.c  redis-cli.o         redis-server        
redis-benchmark.c   redis-check-aof.c   redis-check-dump.o  redis.h             redis-trib.rb      
redis-benchmark.o   redis-check-aof.o   redis-cli           redis.o      

這樣redis就編譯安裝成功了,先來運作一下看redis是否能正确啟動,指令如下:

root@master:/usr/local/redis-3.0.4# src/redis-server redis.conf
                _._                                                  
           _.-``__ ''-._                                            
      _.-``    `.  `_.  ''-._           Redis 3.0.4 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                  
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 5078
  `-._    `-._  `-./  _.-'    _.-'                                  
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                  
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                  
      `-._    `-.__.-'    _.-'                                      
          `-._        _.-'                                          
              `-.__.-'                                              
5078:M 30 Sep 11:59:04.708 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
5078:M 30 Sep 11:59:04.708 # Server started, Redis version 3.0.4
5078:M 30 Sep 11:59:04.708 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
5078:M 30 Sep 11:59:04.709 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
5078:M 30 Sep 11:59:04.709 * The server is now ready to accept connections on port 6379      

這樣redis運作了,但它預設是在前台運作的,從上邊的啟動的輸出資訊中可以看到三個“WARNING”資訊,請不要忽略這些資訊,你不理睬它,那在生産環境下,你就給自己或者其他同僚挖了一個坑。

先來看第一個WARNING資訊“The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128”大概是說somaxconn的值128設定過小,從“ /proc/sys/net/core/somaxconn”這個路徑也可大概知道這個值的設定是關于網絡連接配接中某個最大值的限定設定,此值表示網絡連接配接的隊列大小,在配置檔案redis.conf中的“tcp-backlog 511”就配置在高并發環境下的最大隊列大小,此值受限于系統的somaxconn與tcp_max_syn_backlog這兩個值,是以應該把這兩個核心參數值調大,具體解決方法如下:

root@master:~# vim /etc/sysctl.conf    #在最後增加以下内容
#最大隊列長度,應付突發的大并發連接配接請求
net.core.somaxconn = 65535
#半連接配接隊列長度,此值受限于記憶體大小
net.ipv4.tcp_max_syn_backlog = 20480
root@master:~# sysctl -p   #使修改生效
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 20480      

做了以上修改後,再重新啟動redis進行測試,發現第一個WARNING敬告資訊已無,接下處理第二個WARNING資訊“WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect”根據提示可知預設時overcommit_memory是被設定為0的,在主機配置較少記憶體時,redis運作可能出現故障,根據提示就可修複,在 /etc/sysctl.conf檔案最後加上“vm.overcommit_memory = 1”後重新啟動redis即可,操作如下:

root@master:~# vim /etc/sysctl.conf 
#最大隊列長度,應付突發的大并發連接配接請求
net.core.somaxconn = 65535
#半連接配接隊列長度,此值受限于記憶體大小
net.ipv4.tcp_max_syn_backlog = 20480
#記憶體配置設定政策
vm.overcommit_memory = 1      

說明:overcommit_memory的值有三個,0、1、2。

0, 表示核心将檢查是否有足夠的可用記憶體供應用程序使用;如果有足夠的可用記憶體,記憶體申請允許;否則,記憶體申請失敗,并把錯誤傳回給應用程序。 

1, 表示核心允許配置設定所有的實體記憶體,而不管目前的記憶體狀态如何,這裡表示的所有記憶體是受限于overcommit_ratio值的,值是一個百分比,在Debian8上/proc/sys/vm/overcommit_ratio的預設值是50,那把overcommit_memory配置為1時,那系統可配置設定的記憶體為“實體記憶體+實體記憶體*50%”

2, 表示核心允許配置設定超過所有實體記憶體和交換空間總和的記憶體

root@master:~# sysctl -p   #使其生效
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 20480
vm.overcommit_memory = 1      

再把redis程序殺掉,重新啟動測試,發現關于overcommit_memory的告警已無。最後再來處理關于“ Transparent Huge Pages (THP)”的告警,這是一個關于透明記憶體巨頁的話題,簡單來說記憶體可管理的最小機關是page,一個page通常是4kb,那1M記憶體就會有256個page,CPU通過内置的記憶體管理單元管理page表記錄。Huge Pages就是表示page的大小已超過4kb了,一般是2M到1G,它的出現主要是為了管理超大記憶體,個人了解上TB的記憶體。而THP就是管理Huge Pages的一個抽象層次,根據一些資料顯示,THP會導緻記憶體鎖影響性能,是以一般建議關閉此功能。

    “/sys/kernel/mm/transparent_hugepage/enabled”有三個值,如下:

root@master:/usr/local/redis-3.0.4# cat /sys/kernel/mm/transparent_hugepage/enabled
always [madvise] never
####
# always 盡量使用透明記憶體,掃描記憶體,有512個 4k頁面可以整合,就整合成一個2M的頁面
# never 關閉,不使用透明記憶體
# madvise 避免改變記憶體占用      

關于THP的内容就介紹到這裡,現在根據警告資訊去修改,再重新啟動redis測試一下告警是否消除,操作如下:

root@master:/usr/local/redis-3.0.4# echo never > /sys/kernel/mm/transparent_hugepage/enabled
root@master:/usr/local/redis-3.0.4#vim /etc/rc.local   
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
echo "echo never > /sys/kernel/mm/transparent_hugepage/enabled"   #加入開機啟動,寫在exit 0之前
exit 0
root@master:/usr/local/redis-3.0.4# cat /sys/kernel/mm/transparent_hugepage/enabled
always madvise [never]      

再停止redis,重新啟動redis:

root@master:/usr/local/redis-3.0.4# src/redis-server redis.conf
                _._                                                  
           _.-``__ ''-._                                            
      _.-``    `.  `_.  ''-._           Redis 3.0.4 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                  
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 5666
  `-._    `-._  `-./  _.-'    _.-'                                  
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                  
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                  
      `-._    `-.__.-'    _.-'                                      
          `-._        _.-'                                          
              `-.__.-'                                              
5666:M 30 Sep 16:53:06.570 # Server started, Redis version 3.0.4
5666:M 30 Sep 16:53:06.570 * DB loaded from disk: 0.000 seconds
5666:M 30 Sep 16:53:06.570 * The server is now ready to accept connections on port 6379
#現在redis已無任何警告資訊      

到現在redis啟動後還是在前台運作,我們再開一個視窗用redis用戶端工具連接配接後做一個簡單的測試,如下:

root@master:/usr/local/redis-3.0.4/src# pwd
/usr/local/redis-3.0.4/src
root@master:/usr/local/redis-3.0.4/src# ./redis-cli -p 6379
127.0.0.1:6379> get foo
(nil)
127.0.0.1:6379> set foo bar
OK
127.0.0.1:6379> get foo
"bar"      

到這裡redis單節點就可以正常工作了,接下來真正部署一個主從架構的redis叢集,主從節點都按上邊的的方法編譯安裝即可,隻是在配置檔案上略有差別而已,為了便于調試在配置檔案中我先配置了“daemonize yes”(讓redis啟動後在背景運作)和“logfile "/var/log/redis.log"”(列印日志)。

先啟動主節點:

root@master:/usr/local/redis-3.0.4# src/redis-server redis.conf
root@master:/usr/local/redis-3.0.4# ss -tnl | grep 6379
LISTEN     0      511                       *:6379                     *:*    
LISTEN     0      511                      :::6379                    :::*      

然後配置從節點的redis.conf,確定啟用“slaveof 192.168.207.128 6379",接着就啟動從節點,再去觀察主節點的日志檔案會發現有類似如下資訊輸出:

root@master:/usr/local/redis-3.0.4# tailf /var/log/redis.log
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                  
      `-._    `-.__.-'    _.-'                                      
          `-._        _.-'                                          
              `-.__.-'                                              
869:M 01 Oct 10:47:12.566 # Server started, Redis version 3.0.4
869:M 01 Oct 10:47:12.567 * DB loaded from disk: 0.000 seconds
869:M 01 Oct 10:47:12.567 * The server is now ready to accept connections on port 6379
869:M 01 Oct 10:47:44.213 * Slave 192.168.207.130:6379 asks for synchronization     #發現有從節點來連接配接
869:M 01 Oct 10:47:44.214 * Full resync requested by slave 192.168.207.130:6379
869:M 01 Oct 10:47:44.215 * Starting BGSAVE for SYNC with target: disk
869:M 01 Oct 10:47:44.215 * Background saving started by pid 880   #因從節點是第一次來連接配接,是以主節點會啟動一個背景儲存程序去儲存資料
880:C 01 Oct 10:47:44.229 * DB saved on disk   #資料已儲存到disk
880:C 01 Oct 10:47:44.230 * RDB: 0 MB of memory used by copy-on-write
869:M 01 Oct 10:47:44.284 * Background saving terminated with success
869:M 01 Oct 10:47:44.284 * Synchronization with slave 192.168.207.130:6379 succeeded   #資料已同步      

在主節點的日志輸出中有類似下邊的輸出資訊(都很容易了解,就不再一一解釋):

1172:S 01 Oct 10:47:43.285 # Server started, Redis version 3.0.4
1172:S 01 Oct 10:47:43.295 * DB loaded from disk: 0.010 seconds
1172:S 01 Oct 10:47:43.295 * The server is now ready to accept connections on port 6379
1172:S 01 Oct 10:47:44.284 * Connecting to MASTER 192.168.207.128:6379
1172:S 01 Oct 10:47:44.285 * MASTER <-> SLAVE sync started
1172:S 01 Oct 10:47:44.285 * Non blocking connect for SYNC fired the event.
1172:S 01 Oct 10:47:44.285 * Master replied to PING, replication can continue...
1172:S 01 Oct 10:47:44.286 * Partial resynchronization not possible (no cached master)
1172:S 01 Oct 10:47:44.288 * Full resync from master: 127f65ef8fa67fd0fd33093ee44a88fe06bd4e6a:1
1172:S 01 Oct 10:47:44.357 * MASTER <-> SLAVE sync: receiving 29 bytes from master
1172:S 01 Oct 10:47:44.358 * MASTER <-> SLAVE sync: Flushing old data
1172:S 01 Oct 10:47:44.358 * MASTER <-> SLAVE sync: Loading DB in memory      

接下來就測試主從是否真的能工作,在主節點上用用戶端工具連接配接到redis,做以下操作:

root@master:/usr/local/redis-3.0.4/src# ./redis-cli -p 6379
127.0.0.1:6379> set key01 value01
OK
127.0.0.1:6379> get key01
"value01"      

再到從節點上看是否能擷取到”key01“的值:

root@slave01:/usr/local/redis-3.0.4/src# ./redis-cli -p 6379
127.0.0.1:6379> get key01
"value01"
127.0.0.1:6379> set key02 value02
(error) READONLY You can't write against a read only slave.      

測試證明我們搭建的主從redis是能正常工作的,而在從節點上嘗試進行寫入操作時也是不被允許的,這是不是與mysql的機制類似,我想隻要是主從複制的機制,從節點都應該不能被寫入吧。

    主從複制搭建是非常簡單的事情,它如mysql主從複制一樣當主節點挂掉後,在短時間無法恢複時我們可以手工切換到從節點,能在盡可短的時間内恢複業務。但主從複制始終在出現故障時會有一段時間redis不能上線,那是否有更好方法能讓各個redis節點在監測到主節點挂掉後能不用人工 幹預就能把一個從節點自動提升為主節點?sentinel就是這樣一個工具。

  sentinel管理工具有如下功能:

a、監視:sentinel會定期的監控主從redis的執行個體程序是否在正常工作;

b、通知:sentinel可能通過API向管理者發送出現問題的redis執行個體;

c、自動故障轉移:sentinel監控到主節點不能正常工作後,可以在多個從節點中選舉出一個節點成為新的主節點,而其他的從節點就會以新的主節點作為自己的主,這一切都不需要人為幹預;

d、Configuration provider(我譯為:配置可服務能力):表示在sentinel管理的redis叢集的環境下用戶端是與sentinel執行個體進行連接配接,當主節點發生故障後會重新在從節點中選舉出一個節點作為主,那sentinel有能力向用戶端告知新的master位址。

    sentinel是一個分步式系統,它被設計成多個sentinel程序協合工作,我了解就是在運作有一個redis程序的環境下也運作着一個與之相關的sentinel程序,這樣設計有什麼優點呢?

a、主節點的不可用是由多個sentinel協同認定的(我猜想從多個人中選舉出一個作為新主時也是多個sentinel協同完成的),這樣可避免誤判主節點的不可用的發生;

b、即使不是所有的sentinel執行個體都在正常工作也不會影響業務,這樣就避免了單點故障。

現在我們就來搭建一個sentinel的高可用環境。在搭建前我需要說明的一些資訊:第一、redis的節點數大于等于3;第二、因實驗環境中隻有兩debian的虛拟機,是以我這裡的3個節點都是搭建在兩個主機上,隻是在192.168.207.130主機上運作了2個redis執行個體;第三、這次我以一個普通使用者來搭建,這更與實際生産環境相似。規劃如下:

主機 redis及sentinel所在目錄 redis執行個體監聽端口 sentinel執行個體監聽端口
主節點 /home/redis/redis6379 6379 26379
從節點 /home/redis/redis6380 6380 26380
/home/redis/redis6381 6381 26381

現在我們就按上表的規劃把redis搭建好。還記得最開始編譯安裝redis的過程吧,redis編譯後我們所需要的檔案就是生成在了源碼目錄下的src目錄中,而配置檔案就在源碼所在目錄,對于想把redis運作起來我們隻需要這些檔案即可了,如果你已不記得是哪些檔案了,那就回到源碼目錄運作”make PREFIX=/tmp/redis install“就可以把編譯後的可執行檔案都copy到/tmp/redis目錄下,是以這次我隻把這些檔案拷貝到上表規劃的相應目錄中。在進行下邊操作前記得把開始啟動的redis程序殺掉。

主機192.168.207.128上的操作:

redis@master:~$ whoami
redis
redis@master:~$ pwd
/home/redis
redis@master:~$ mkdir redis6379
redis@master:~$ cd redis6379/
redis@master:~/redis6379$ cp -r /tmp/redis/bin ./
redis@master:~/redis6379$ cp /usr/local/redis-3.0.4/redis.conf /usr/local/redis-3.0.4/sentinel.conf ./
redis@master:~/redis6379$ ls
bin  redis.conf  sentinel.conf
redis@master:~/redis6379$ mkdir log   #這裡我建立一個單獨的日志目錄來存放redis的日志,當然配置檔案也應當做相應的修改,略
redis@master:~/redis6379$ ls bin/
redis-benchmark  redis-check-aof  redis-check-dump  redis-cli  redis-sentinel  redis-server
redis@master:~/redis6379$ bin/redis-server redis.conf   #啟動redis      

看見上邊的” sentinel.conf “這個配置檔案了吧,這個檔案就是sentinel執行個體運作時需要加載的配置檔案,下邊簡單介紹一下它的常用配置:

sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1      

第一行表示監視名為mymaster的主伺服器,ip是127.0.0.1,端口是6379,而那個”2“表示的是法定票數,簡單來說就是把這個主伺服器判定為失效是需要2個sentinel程序同意,如果沒有2個sentinel程序,那故障将不會轉移,在高可用分步式環境中這個值一般設定為超過半數的節點;

第二行中的down-after-milliseconds表示sentinel判斷一個主節點不可用時的逾時時間,機關為毫秒;

第三行的failover-timeout表示故障轉移的逾時時間,這個在配置文檔中有注釋資訊,但個人E文不好,沒有看得太懂;

第四行的parallel-syncs表示當選舉出新的master後,最多允許多少個從連接配接到新的master進行資料複制,當從重新連接配接新的master進行資料同步時,以前的資料将會被清空,此時從伺服器不将具有被查詢的能力,是以建議保持預設值。

此配置檔案中沒有slave的相關配置,隻需要指定主節點就可以了,當你把sentile都啟動後,sentile會自己配置各個從節點到這個配置檔案中,也就是說sentinel有一定自我維護此配置檔案的能力。說了這麼多,下邊就讓我們動手實驗一下:

192.168.207.128節點上的sentinel配置如下:

redis@master:~/redis6379$ grep -v "^#" sentinel.conf | grep -v "^$"
port 26379
dir /tmp
sentinel monitor mymaster 192.168.207.128 6379 2   #我隻是把預設的ip位址換成了真實的接口位址,其他保持預設
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
配置好後,啟動sentinel,如下操作:
redis@master:~/redis6379$ bin/redis-sentinel sentinel.conf
                _._                                                  
           _.-``__ ''-._                                            
      _.-``    `.  `_.  ''-._           Redis 3.0.4 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                  
 (    '      ,       .-`  | `,    )     Running in sentinel mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379
 |    `-._   `._    /     _.-'    |     PID: 1573
  `-._    `-._  `-./  _.-'    _.-'                                  
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                  
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                  
      `-._    `-.__.-'    _.-'                                      
          `-._        _.-'                                          
              `-.__.-'                                              
1573:X 01 Oct 15:24:49.865 # Sentinel runid is a99b3228db674545eec6dcf4be2934520e469a3a
1573:X 01 Oct 15:24:49.865 # +monitor master mymaster 192.168.207.128 6379 quorum 2
#sentinel啟動後也是在前台的,在調試階段可以讓标準輸出重定向到一個檔案中,就像記錄日志檔案一樣,這樣也便于觀察sentinel的啟動過程,我這裡就讓它在前台運作。      

而在192.168.207.130節點上的redis配置和sentinel配置隻是在端口設定上不同而已,這裡就不再贅述了,但要說明的一點是一個主機上運作着多個redis執行個體,記得要把pid檔案得改一下,兩個執行個體可不能共享一個pid檔案,建議就修改到自己的家目錄裡,并且在檔案上做好辨別,一眼就知道這是哪個redis程序的PID檔案,在192.168.207.130的兩個redis執行個體的redis.conf檔案中不要忘記配置"slaveof 192.168.207.128 6379"指向主節點,因為它們可是主節點的從執行個體,配置過程就不再給出了。

在192.168.207.130節點上的目錄結構是這樣的,如下:

redis@slave01:~$ ls
redis6380  redis6381
redis@slave01:~$ tree
.
├── redis6380
│   ├── bin
│   │   ├── redis-benchmark
│   │   ├── redis-check-aof
│   │   ├── redis-check-dump
│   │   ├── redis-cli
│   │   ├── redis-sentinel -> redis-server
│   │   └── redis-server
│   ├── dump.rdb
│   ├── log
│   │   └── redis6380.log
│   ├── redis6380.pid
│   ├── redis.conf
│   └── sentinel.conf
└── redis6381
    ├── bin
    │   ├── redis-benchmark
    │   ├── redis-check-aof
    │   ├── redis-check-dump
    │   ├── redis-cli
    │   ├── redis-sentinel -> redis-server
    │   └── redis-server
    ├── log
    │   └── redis6381.log
    ├── redis6381.pid
    ├── redis.conf
    └── sentinel.conf      

注:記得一定要按照上表細心的修改redis.conf和sentinel.conf檔案

把所有節點的redis和sentinel啟動好後在啟動sentinel的視窗中會列印一些啟動的日志資訊,這裡把三個執行個體的日志資訊羅列出來,如下:

redis6379:

1644:X 01 Oct 15:40:12.692 # Sentinel runid is e3bc2b0fc1cba2a12b9c9234d2983ab58a2df1e0
1644:X 01 Oct 15:40:12.693 # +monitor master mymaster 192.168.207.128 6379 quorum 2
1644:X 01 Oct 15:40:27.889 * +sentinel sentinel 192.168.207.130:26380 192.168.207.130 26380 @ mymaster 192.168.207.128 6379
1644:X 01 Oct 15:40:37.396 * +sentinel sentinel 192.168.207.130:26381 192.168.207.130 26381 @ mymaster 192.168.207.128 6379      

redis6380:

1931:X 01 Oct 15:40:25.833 # Sentinel runid is 0b6789bc75faf4e6b4f18114ea51442c2ea79dda
1931:X 01 Oct 15:40:25.833 # +monitor master mymaster 192.168.207.128 6379 quorum 2
1931:X 01 Oct 15:40:27.288 * +sentinel sentinel 192.168.207.128:26379 192.168.207.128 26379 @ mymaster 192.168.207.128 6379
1931:X 01 Oct 15:40:37.469 * +sentinel sentinel 192.168.207.130:26381 192.168.207.130 26381 @ mymaster 192.168.207.128 6379      

redis6381:

1943:X 01 Oct 15:40:35.409 # Sentinel runid is f0111604f01d66e12e7e9ddbc86d1f92eeb99587
1943:X 01 Oct 15:40:35.409 # +monitor master mymaster 192.168.207.128 6379 quorum 2
1943:X 01 Oct 15:40:37.641 * +sentinel sentinel 192.168.207.128:26379 192.168.207.128 26379 @ mymaster 192.168.207.128 6379
1943:X 01 Oct 15:40:38.271 * +sentinel sentinel 192.168.207.130:26380 192.168.207.130 26380 @ mymaster 192.168.207.128 6379      

對于上邊的日志輸出就不想多解釋了,一看就會明白sentinel在幹什麼事情。

接下來就來測試,分成兩個部份,第一是測試三個redis執行個體的主從複制結構是否可用,第二才是測試sentinel高可用是否能正常工作。

主從複制測試:

redis@master:~/redis6379$ bin/redis-cli -p 6379
127.0.0.1:6379> get foo  #起初foo這個key沒有值,下邊的兩個從節點也是
(nil)
127.0.0.1:6379> set foo bar  #賦予foo的值為bar
OK
127.0.0.1:6379> get foo  #當主節點的foo有值後,下邊兩個從節點也就有值了
"bar"
127.0.0.1:6379> 
redis@slave01:~/redis6380$ bin/redis-cli -p 6380
127.0.0.1:6380> get foo
(nil)
127.0.0.1:6380> get foo
"bar"
redis@slave01:~/redis6381$ bin/redis-cli -p 6381
127.0.0.1:6381> get foo
(nil)
127.0.0.1:6381> get foo
"bar"
127.0.0.1:6381>      

sentinel高可用測試:

redis@master:~/redis6379$ bin/redis-cli -p 26379   
127.0.0.1:26379> sentinel master mymaster  #此指令可列印出master主節點的一些狀态資訊,“mymaster”是指sentinel.conf配置檔案是配置的主節點名稱
 1) "name"
 2) "mymaster"
 3) "ip"
 4) "192.168.207.128"
 5) "port"
 6) "6379"
 7) "runid"
 8) "01d41d73fcf35e1c85f6d2305c54e368fdfc3578"
 9) "flags"
10) "master"
11) "pending-commands"
12) "0"
13) "last-ping-sent"
14) "0"
15) "last-ok-ping-reply"
16) "518"
17) "last-ping-reply"
18) "518"
19) "down-after-milliseconds"
20) "30000"
21) "info-refresh"
22) "3765"
23) "role-reported"
24) "master"
25) "role-reported-time"
26) "336155"
27) "config-epoch"
28) "0"
29) "num-slaves"
30) "2"
31) "num-other-sentinels"
32) "2"
33) "quorum"
34) "2"
35) "failover-timeout"
36) "180000"
37) "parallel-syncs"
38) "1"      

列印出mymaster這個組中從節點的狀态資訊,從下邊的輸出可看出有兩個從節點

127.0.0.1:26379> sentinel slaves mymaster
1)  1) "name"
    2) "192.168.207.130:6381"
    3) "ip"
    4) "192.168.207.130"
    5) "port"
    6) "6381"
    7) "runid"
    8) "84ad88633faffd65496d232fdd5f8cd3b57836eb"
    9) "flags"
   10) "slave"
   11) "pending-commands"
   12) "0"
   13) "last-ping-sent"
   14) "0"
   15) "last-ok-ping-reply"
   16) "445"
   17) "last-ping-reply"
   18) "445"
   19) "down-after-milliseconds"
   20) "30000"
   21) "info-refresh"
   22) "9710"
   23) "role-reported"
   24) "slave"
   25) "role-reported-time"
   26) "984624"
   27) "master-link-down-time"
   28) "0"
   29) "master-link-status"
   30) "ok"
   31) "master-host"
   32) "192.168.207.128"
   33) "master-port"
   34) "6379"
   35) "slave-priority"
   36) "100"
   37) "slave-repl-offset"
   38) "314641"
2)  1) "name"
    2) "192.168.207.130:6380"
    3) "ip"
    4) "192.168.207.130"
    5) "port"
    6) "6380"
    7) "runid"
    8) "b69a95dded62594ad295ced4a1f1ccefa942e901"
    9) "flags"
   10) "slave"
   11) "pending-commands"
   12) "0"
   13) "last-ping-sent"
   14) "0"
   15) "last-ok-ping-reply"
   16) "445"
   17) "last-ping-reply"
   18) "445"
   19) "down-after-milliseconds"
   20) "30000"
   21) "info-refresh"
   22) "9710"
   23) "role-reported"
   24) "slave"
   25) "role-reported-time"
   26) "984624"
   27) "master-link-down-time"
   28) "0"
   29) "master-link-status"
   30) "ok"
   31) "master-host"
   32) "192.168.207.128"
   33) "master-port"
   34) "6379"
   35) "slave-priority"
   36) "100"
   37) "slave-repl-offset"
   38) "314641"      

接下來我們殺掉運作在6379端口的redis執行個體後觀察sentinel是否能正常的選舉出新的主redis,同時觀察各執行個體的日志輸出就可知道當主redis挂點後到底發生了什麼,如下操作:

redis@master:~/redis6379$ ps aux | grep :6379
redis       882  0.1  0.3  38976  3920 ?        Ssl  14:45   0:05 bin/redis-server *:6379    
redis      1214  0.0  0.1  12948  1980 pts/1    S+   15:34   0:00 grep :6379
redis@master:~/redis6379$ kill 882      

redis 26379日志輸出:

1206:X 05 Oct 15:35:37.225 # +sdown master mymaster 192.168.207.128 6379
1206:X 05 Oct 15:35:37.302 # +new-epoch 1
1206:X 05 Oct 15:35:37.304 # +vote-for-leader 3123628221014c13a37183b9e054de2fad79f4f3 1
1206:X 05 Oct 15:35:38.317 # +odown master mymaster 192.168.207.128 6379 #quorum 3/2
1206:X 05 Oct 15:35:38.317 # Next failover delay: I will not start a failover before Mon Oct  5 15:41:38 2015
1206:X 05 Oct 15:35:38.394 # +config-update-from sentinel 192.168.207.130:26381 192.168.207.130 26381 @ mymaster 192.168.207.128 6379
1206:X 05 Oct 15:35:38.394 # +switch-master mymaster 192.168.207.128 6379 192.168.207.130 6381
1206:X 05 Oct 15:35:38.395 * +slave slave 192.168.207.130:6380 192.168.207.130 6380 @ mymaster 192.168.207.130 6381
1206:X 05 Oct 15:35:38.395 * +slave slave 192.168.207.128:6379 192.168.207.128 6379 @ mymaster 192.168.207.130 6381
1206:X 05 Oct 15:36:08.405 # +sdown slave 192.168.207.128:6379 192.168.207.128 6379 @ mymaster 192.168.207.130 6381      

redis 26380日志輸出:

1273:X 05 Oct 15:35:37.290 # +sdown master mymaster 192.168.207.128 6379
1273:X 05 Oct 15:35:37.295 # +new-epoch 1
1273:X 05 Oct 15:35:37.298 # +vote-for-leader 3123628221014c13a37183b9e054de2fad79f4f3 1
1273:X 05 Oct 15:35:37.390 # +odown master mymaster 192.168.207.128 6379 #quorum 3/2
1273:X 05 Oct 15:35:37.390 # Next failover delay: I will not start a failover before Mon Oct  5 15:41:38 2015
1273:X 05 Oct 15:35:38.388 # +config-update-from sentinel 192.168.207.130:26381 192.168.207.130 26381 @ mymaster 192.168.207.128 6379
1273:X 05 Oct 15:35:38.388 # +switch-master mymaster 192.168.207.128 6379 192.168.207.130 6381
1273:X 05 Oct 15:35:38.389 * +slave slave 192.168.207.130:6380 192.168.207.130 6380 @ mymaster 192.168.207.130 6381
1273:X 05 Oct 15:35:38.389 * +slave slave 192.168.207.128:6379 192.168.207.128 6379 @ mymaster 192.168.207.130 6381
1273:X 05 Oct 15:36:08.390 # +sdown slave 192.168.207.128:6379 192.168.207.128 6379 @ mymaster 192.168.207.130 6381      

redis 26381日志輸出:

1278:X 05 Oct 15:35:37.230 # +sdown master mymaster 192.168.207.128 6379
1278:X 05 Oct 15:35:37.291 # +odown master mymaster 192.168.207.128 6379 #quorum 2/2
1278:X 05 Oct 15:35:37.292 # +new-epoch 1
1278:X 05 Oct 15:35:37.292 # +try-failover master mymaster 192.168.207.128 6379
1278:X 05 Oct 15:35:37.293 # +vote-for-leader 3123628221014c13a37183b9e054de2fad79f4f3 1
1278:X 05 Oct 15:35:37.298 # 192.168.207.130:26380 voted for 3123628221014c13a37183b9e054de2fad79f4f3 1
1278:X 05 Oct 15:35:37.299 # 192.168.207.128:26379 voted for 3123628221014c13a37183b9e054de2fad79f4f3 1
1278:X 05 Oct 15:35:37.366 # +elected-leader master mymaster 192.168.207.128 6379
1278:X 05 Oct 15:35:37.367 # +failover-state-select-slave master mymaster 192.168.207.128 6379
1278:X 05 Oct 15:35:37.451 # +selected-slave slave 192.168.207.130:6381 192.168.207.130 6381 @ mymaster 192.168.207.128 6379
1278:X 05 Oct 15:35:37.452 * +failover-state-send-slaveof-noone slave 192.168.207.130:6381 192.168.207.130 6381 @ mymaster 192.168.207.128 6379
1278:X 05 Oct 15:35:37.528 * +failover-state-wait-promotion slave 192.168.207.130:6381 192.168.207.130 6381 @ mymaster 192.168.207.128 6379
1278:X 05 Oct 15:35:38.321 # +promoted-slave slave 192.168.207.130:6381 192.168.207.130 6381 @ mymaster 192.168.207.128 6379
1278:X 05 Oct 15:35:38.321 # +failover-state-reconf-slaves master mymaster 192.168.207.128 6379
1278:X 05 Oct 15:35:38.385 * +slave-reconf-sent slave 192.168.207.130:6380 192.168.207.130 6380 @ mymaster 192.168.207.128 6379
1278:X 05 Oct 15:35:39.325 * +slave-reconf-inprog slave 192.168.207.130:6380 192.168.207.130 6380 @ mymaster 192.168.207.128 6379
1278:X 05 Oct 15:35:39.427 # -odown master mymaster 192.168.207.128 6379
1278:X 05 Oct 15:35:40.342 * +slave-reconf-done slave 192.168.207.130:6380 192.168.207.130 6380 @ mymaster 192.168.207.128 6379
1278:X 05 Oct 15:35:40.426 # +failover-end master mymaster 192.168.207.128 6379
1278:X 05 Oct 15:35:40.426 # +switch-master mymaster 192.168.207.128 6379 192.168.207.130 6381
1278:X 05 Oct 15:35:40.426 * +slave slave 192.168.207.130:6380 192.168.207.130 6380 @ mymaster 192.168.207.130 6381
1278:X 05 Oct 15:35:40.426 * +slave slave 192.168.207.128:6379 192.168.207.128 6379 @ mymaster 192.168.207.130 6381
1278:X 05 Oct 15:36:10.476 # +sdown slave 192.168.207.128:6379 192.168.207.128 6379 @ mymaster 192.168.207.130 6381      

仔細觀察上邊的日志輸出,會得知各個sentinel程序都發現redis6379程序已不在了,于是就把master的狀态設定為sdown,當通過sentinel彼此間通訊後有大多數的sentinel都認為原master挂掉後就把原master設定為odown狀态,接下就是開始故障轉移的過程,在從節點中選出一個節點來作為新的master,并把其他的從節點的主節點更新為現在新的master節點(會更新sentinel.conf檔案),當從節點切換到新的主節點後它會重新同步資料,這在redis執行個體的日志檔案中可觀察到詳細的操作。

    到此redis的高可用的實作了,原理還是比較簡單,真正實作起來也是十分容易的。在真正的生産環境下連接配接redis叢集時可不是直接與redis執行個體所連接配接,而是和多個sentinel執行個體連接配接了。

    利用sentinel工具來實作redis的高可用也算是一種叢集方案了,但他隻是加強了redis的可用性,并沒有在性能上對redis進行擴充,同一時間可服務的也隻有master節點,這種主從加sentinel的架構能在一般壓力環境下能夠應對,但是在極高并發的環境下還是不适合,為了應用這樣的高并發場景,redis在從3.0開始就支援cluster了,這才是真正意義上的分布式叢集系統,他能讓redis向外擴充,能讓多個redis節點同步接受客戶的請求操作,讓資料跨躍多個節點并實作自動分片,這大大提高了系統 的吞吐量。既然redis cluster是一個分布式系統 ,那他也遵循CAP理論,在consistency上redis節點之間的資料也是異步的。

    redis cluster是一個怎樣的叢集系統呢?他有以下兩個特性:

    a、資料的分片是自動完成的;

    b、當有部分(少于半數的節點)節點挂點後,系統依然可用。

    redis cluster需要兩個TCP端口才能工作,一個是redis執行個體監聽的端口,預設是6379,這個端口是讓用戶端接入的;另一個tcp端口是redis執行個體端口+10000,此soket是cluster bus(叢集總線),如果reids執行個體商品為6379,那cluster bus的端口就是16379,在此總線上節點對節點間通過二進制協定進行通信,所完成的工作有故障檢查、配置更新、故障轉移等。用戶端工具不應該與此端口進行連接配接,但各個節點間應該開放此端口,若有防火牆一定要開放出來,不然叢集将不能正常的工作。

    在這樣一個分布式叢集環境下,資料是如何存放的?回想一下memcached在分布式運用上是怎樣實作的呢?memcached是采用一緻性hash算法實作資料的分布式存儲,不明此算法的原理請翻看前邊的部落格。而redis cluster并沒有采用一緻性hash算法,而是采用了一種叫“hash slot(散列槽)”的機制。在一個cluster中共有16384個散列槽,當需要在 Redis 叢集中放置一個 key-value 時,redis 先對 key 使用 crc16 算法算出一個結果,然後把結果對 16384 求餘數,這樣每個 key 都會對應一個編号在 0-16383 之間的哈希槽,redis 會根據節點數量大緻均等的将哈希槽映射到不同的節點,即各個節點負責16384個散列槽中的一個子集。hash slot的引入使得redis cluster非常容易向叢集中增加節點或是減少節點,如果是增加節點,隻要把現在一個節點上的一部分散列槽轉移到新節點上,如果是移除節點,隻要把這個節點上的散列槽移到另外的節點上,這個增加節點或移除節點都不會導緻叢集停止提供服務。

    接下來談一下cluster中的master-slave模式。試想一下如果把三個redis執行個體配置成一個cluster,那每個節點上都配置設定了一定資料的散列槽,當一個節點挂掉後,請問這個叢集還能夠正常工作嗎?這個問題的答案留在最後作答,但我們明白一個節點挂掉了,那它之前所配置設定的散列槽就不可用了,如果上邊存放有資料,用戶端就無法請求到。為了在有節點挂掉後還能保持叢集的高度可用,redis提供了這樣的一種叢集方案,可以為各可對外提供查詢的redis執行個體配置一個從節點,當主節點挂掉後,從節點可立馬提升為主節點,這樣叢集依然是一個完整的叢集,仍然可以正常工作。既然這裡又涉及到的主從,那意味着主與從的資料不可能做強一緻性的,是以也有一定的機率導緻資料的丢失,這一點我們也是需要明白的。如果主節點和從節點都一起挂了,那叢集也就不能工作了,即在redis cluster中必須有16384個slot存在,如果任何一個節點上的slot子集有缺失,那叢集将不會工作。

4.1、redis cluster環境搭建

 接下來我們就動手來搭建一個redis cluster環境,來感受一下這神奇的開源項目,規劃如下圖:

執行個體名 redis監聽端口
redis7000 7000
redis7001 7001
redis7002 7002
redis7003 7003
redis7004 7004
redis7005 7005

依然是上邊的兩個主機,分别部署三個redis執行個體,計劃讓其中的三個執行個體當作master,另外三個分另為三個master的slave,誰做master,誰是slave這是由redis cluster自己決定的。在配置叢集時需要用到“redis-trib.rb”這個ruby腳本,這個腳本在源碼目錄中可找到,既然是ruby腳本,那就需要ruby環境了。

各執行個體的目錄結構類似如下,這裡隻列出一個:

redis@master:~$ pwd
/home/redis
redis@master:~$ tree redis7000
redis7000
├── bin
│   ├── redis-benchmark
│   ├── redis-check-aof
│   ├── redis-check-dump
│   ├── redis-cli
│   ├── redis-sentinel -> redis-server
│   ├── redis-server
│   └── redis-trib.rb
└── redis.conf      

我們隻需要修改各個執行個體目錄下的redis.conf這個配置檔案,各個執行個體的配置檔案按照上表規劃的做修改即可,如下:

redis@master:~/redis7000$ grep -v "^#" redis.conf  | grep -v "^$"
daemonize yes   #背景運作
pidfile /home/redis/redis7000/redis7000.pid   #pid檔案
port 6000   #端口
tcp-backlog 511
bind 192.168.207.128 7000   #綁定的位址及端口
timeout 0
tcp-keepalive 0
loglevel notice
logfile "/home/redis/redis7000/redis7000.log"   #日志檔案
databases 16
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir ./
slave-serve-stale-data yes
slave-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
slave-priority 100
appendonly yes    #redis每次更新都記錄到日志檔案
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
lua-time-limit 5000
cluster-enabled yes   #啟用叢集
cluster-config-file nodes-7000.conf   #叢集配置檔案
cluster-node-timeout 10000   #叢集節點間通訊逾時時間
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-entries 512
list-max-ziplist-value 64
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes      

注意上邊有注釋的地方,各個執行個體隻是配置把相應的監聽端口、綁定位址等修改成自己的即可

把6個redis執行個體的配置檔案都按照上表進行修改後,那就一一把redfis執行個體啟動起來,確定各個執行個體都監聽在相應的端口上。

接着再回到redis7000所在主機上,因redis-trib.rb是ruby程式,是以系統首先需要安裝ruby環境,如下:

root@master:~# aptitude install -y ruby-full      

再更換ruby源,你懂的,原ruby源是被牆了的,如下:

root@master:~# gem source -l
*** CURRENT SOURCES ***
https://rubygems.org/
root@master:~# gem source --remove https://rubygems.org/
https://rubygems.org/ removed from sources
root@master:~# gem source -a http://ruby.taobao.org/
http://ruby.taobao.org/ added to sources
root@master:~# gem source -l
*** CURRENT SOURCES ***
http://ruby.taobao.org/      

要想使用redis-trib.rb腳本來把各個節點加入cluster還需要ruby下的redis接口的支援,是以要安裝redis支援,如下:

root@master:~# gem install redis   #安裝隻是幾秒鐘的事情      

接下就把各個節點加入到叢集中,如下指令:

redis@master:~/redis7000$ bin/redis-trib.rb create --replicas 1 192.168.207.128:7000 192.168.207.128:7001 192.168.207.128:7002 192.168.207.130:7003 192.168.207.130:7004 192.168.207.130:7005
##指令中的“create”表示建立一個叢集,“--replicas 1”表示每個master都有一個salve
>>> Creating cluster   #開始建立叢集
Connecting to node 192.168.207.128:7000: OK
Connecting to node 192.168.207.128:7001: OK
Connecting to node 192.168.207.128:7002: OK
Connecting to node 192.168.207.130:7003: OK
Connecting to node 192.168.207.130:7004: OK
Connecting to node 192.168.207.130:7005: OK
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:     #自動選擇出3個redis執行個體作為master節點和3個節點作為slave
192.168.207.128:7000
192.168.207.130:7003
192.168.207.128:7001
Adding replica 192.168.207.130:7004 to 192.168.207.128:7000
Adding replica 192.168.207.128:7002 to 192.168.207.130:7003
Adding replica 192.168.207.130:7005 to 192.168.207.128:7001
M: 7dae923773125c5956605fac6159412850b100b3 192.168.207.128:7000
   slots:0-5460 (5461 slots) master
M: 568669e03c61b3c4edc31643dcb47e85bc2c3e23 192.168.207.128:7001
   slots:10923-16383 (5461 slots) master
S: 0becd52cb1fa1a69f8d3135dd98f87cd8ccf9d78 192.168.207.128:7002
   replicates 8490b5e84bf0359871ea3fa55b97bb9877be0512
M: 8490b5e84bf0359871ea3fa55b97bb9877be0512 192.168.207.130:7003
   slots:5461-10922 (5462 slots) master
S: 9d076e70871fc7291485aba97b2623dc9fb3b3b0 192.168.207.130:7004
   replicates 7dae923773125c5956605fac6159412850b100b3
S: f3ba7c62307e0321f5d21310d14027c403c73907 192.168.207.130:7005
   replicates 568669e03c61b3c4edc31643dcb47e85bc2c3e23
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 192.168.207.128:7000)   #檢查叢集狀态,從結果輸出中可看出隻有master節點配置設定了hash slots
M: 7dae923773125c5956605fac6159412850b100b3 192.168.207.128:7000
   slots:0-5460 (5461 slots) master
M: 568669e03c61b3c4edc31643dcb47e85bc2c3e23 192.168.207.128:7001
   slots:10923-16383 (5461 slots) master
M: 0becd52cb1fa1a69f8d3135dd98f87cd8ccf9d78 192.168.207.128:7002
   slots: (0 slots) master
   replicates 8490b5e84bf0359871ea3fa55b97bb9877be0512
M: 8490b5e84bf0359871ea3fa55b97bb9877be0512 192.168.207.130:7003
   slots:5461-10922 (5462 slots) master
M: 9d076e70871fc7291485aba97b2623dc9fb3b3b0 192.168.207.130:7004
   slots: (0 slots) master
   replicates 7dae923773125c5956605fac6159412850b100b3
M: f3ba7c62307e0321f5d21310d14027c403c73907 192.168.207.130:7005
   slots: (0 slots) master
   replicates 568669e03c61b3c4edc31643dcb47e85bc2c3e23
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.      

至此,redis cluster建立成功

接下就是測試了,這裡用一種最簡單的方法來測試,直接用redis-cli用戶端工具,如下操作:

redis@slave01:~/redis7003$ bin/redis-cli -c -h 192.168.207.130 -p 7003     #“-c”表示是啟用cluster子產品
192.168.207.130:7003> get foo
-> Redirected to slot [12182] located at 192.168.207.128:7001
(nil)
192.168.207.128:7001> set foo bar
OK
192.168.207.128:7001> get foo
"bar"
192.168.207.128:7001> set key01 value01
OK
192.168.207.128:7001> get key01
"value01"
192.168.207.128:7001> set testkey testvalue
-> Redirected to slot [4757] located at 192.168.207.128:7000
OK
192.168.207.128:7000> get testkey
"testvalue"
192.168.207.128:7000>      

從上邊的測試來看,當我們在7003上擷取foll時被定向到了7001,當在7001上設定testkey時被定向到了7000。那怎樣檢視一個cluster中各個節點的資訊呢?運作下邊的指令即可:

192.168.207.128:7000> cluster nodes
568669e03c61b3c4edc31643dcb47e85bc2c3e23 192.168.207.128:7001 master - 0 1444268798177 2 connected 10923-16383
9d076e70871fc7291485aba97b2623dc9fb3b3b0 192.168.207.130:7004 slave 7dae923773125c5956605fac6159412850b100b3 0 1444268797169 5 connected
0becd52cb1fa1a69f8d3135dd98f87cd8ccf9d78 192.168.207.128:7002 slave 8490b5e84bf0359871ea3fa55b97bb9877be0512 0 1444268796159 4 connected
7dae923773125c5956605fac6159412850b100b3 192.168.207.128:7000 myself,master - 0 0 1 connected 0-5460
f3ba7c62307e0321f5d21310d14027c403c73907 192.168.207.130:7005 slave 568669e03c61b3c4edc31643dcb47e85bc2c3e23 0 1444268797169 6 connected
8490b5e84bf0359871ea3fa55b97bb9877be0512 192.168.207.130:7003 master - 0 1444268794141 4 connected 5461-10922
192.168.207.128:7000>      

接下來測試一下cluster的可用性,我這樣來測試,先去殺掉一個主節點,再檢視叢集的狀态:

redis@master:~/redis7000$ cat redis7000.pid
2184
redis@master:~/redis7000$ kill 2184  #把7000殺掉了
redis@slave01:~/redis7003$ bin/redis-cli -c -h 192.168.207.130 -p 7003
192.168.207.130:7003> cluster nodes
f3ba7c62307e0321f5d21310d14027c403c73907 192.168.207.130:7005 slave 568669e03c61b3c4edc31643dcb47e85bc2c3e23 0 1444268931560 6 connected
7dae923773125c5956605fac6159412850b100b3 192.168.207.128:7000 master,fail - 1444268887245 1444268883792 1 disconnected
0becd52cb1fa1a69f8d3135dd98f87cd8ccf9d78 192.168.207.128:7002 slave 8490b5e84bf0359871ea3fa55b97bb9877be0512 0 1444268933596 4 connected
568669e03c61b3c4edc31643dcb47e85bc2c3e23 192.168.207.128:7001 master - 0 1444268932580 2 connected 10923-16383
8490b5e84bf0359871ea3fa55b97bb9877be0512 192.168.207.130:7003 myself,master - 0 0 4 connected 5461-10922
9d076e70871fc7291485aba97b2623dc9fb3b3b0 192.168.207.130:7004 master - 0 1444268934613 7 connected 0-5460      

從上邊的節點資訊中可知,在起初7000的從節點是7004,現在7000被kill後,7004變成了master了。

在殺掉7000前,我們設定過testkey這個key,其值為testvalue,現在7000被殺掉後來測試一下此key是否能查詢,如下:

192.168.207.128:7001> get testkey
-> Redirected to slot [4757] located at 192.168.207.130:7004
"testvalue"      

正确從7004上傳回了testkey這個key的值。

如果現在又去把7000啟動,那他就會成為7004的從了,如下:

redis@master:~/redis7000$ bin/redis-server redis.conf 
192.168.207.130:7004> cluster nodes
f3ba7c62307e0321f5d21310d14027c403c73907 192.168.207.130:7005 slave 568669e03c61b3c4edc31643dcb47e85bc2c3e23 0 1444269002483 6 connected
568669e03c61b3c4edc31643dcb47e85bc2c3e23 192.168.207.128:7001 master - 0 1444269003498 2 connected 10923-16383
8490b5e84bf0359871ea3fa55b97bb9877be0512 192.168.207.130:7003 master - 0 1444269005530 4 connected 5461-10922
0becd52cb1fa1a69f8d3135dd98f87cd8ccf9d78 192.168.207.128:7002 slave 8490b5e84bf0359871ea3fa55b97bb9877be0512 0 1444269006546 4 connected
9d076e70871fc7291485aba97b2623dc9fb3b3b0 192.168.207.130:7004 myself,master - 0 0 7 connected 0-5460
7dae923773125c5956605fac6159412850b100b3 192.168.207.128:7000 slave 9d076e70871fc7291485aba97b2623dc9fb3b3b0 0 1444269004514 7 connected      

至此,cluster高可用性已得到了驗證。

4.2、redis cluster增加節點

    随着業務的增長,有一天你發現現在的redis叢集規模已不能滿足業務需求了,你得向叢集中增加節點來擴充redis cluster的處理能力。向一個redis cluster增加節點也是一件愉快的事情,當然首先你得準備好一個空的redis執行個體,就像我下邊一樣我先準備好了一個“redis7006”執行個體:

redis@slave01:~$ ls
redis7003  redis7004  redis7005  redis7006
redis@slave01:~$ tree redis7006
redis7006
├── bin
│   ├── redis-benchmark
│   ├── redis-check-aof
│   ├── redis-check-dump
│   ├── redis-cli
│   ├── redis-sentinel
│   ├── redis-server
│   └── redis-trib.rb
└── redis.conf      

配置檔案的修改就是修改一端口号、pid檔案字尾、日志檔案字尾這些資訊,這裡就不再給出。

接着把新的執行個體啟動起來:

redis@slave01:~$ cd redis7006/
redis@slave01:~/redis7006$ bin/redis-server redis.conf      

新的執行個體準備好了,接下就把此執行個體增加到叢集中吧,它增加到叢集中是擔任master,還是擔任slave呢?這都是可用參數來控制的,預設不指定時是作為master。增加節點的指令如下:

./redis-trib.rb add-node IP:PORT IP:PORT      

第一個IP:PORT是指新執行個體的ip位址和端口号,第二個IP:PORT是指現有叢集中的任意一個節點的ip位址和端口,是master可以,是slave也可以。如果增加的節點是做salve,那指令如下:

./redis-trib.rb add-node --slave IP:PORT IP:PORT      

第一個IP:PORT是指新執行個體的ip位址和端口号,第二個IP:PORT是指叢集中任意一個節點的ip位址和端口,采用這樣的方式增加的slave節點我們并不能控制他是哪個節點的從,如果要想指定加入的節點是哪個節點的從節點,那如下指令:

./redis-trib.rb add-node --slave --master-id ID 
 
IP:PORT IP:PORT      

不再解釋上邊指令了,也是很好了解的。

掌握了增加節點的指令,那就把redis7006這個執行個體加入到現有叢集中,如下操作:

redis@master:~/redis7000$ bin/redis-trib.rb add-node 192.168.207.130:7006 192.168.207.128:7002
>>> Adding node 192.168.207.130:7006 to cluster 192.168.207.128:7002
Connecting to node 192.168.207.128:7002: OK
Connecting to node 192.168.207.130:7003: OK
Connecting to node 192.168.207.130:7004: OK
Connecting to node 192.168.207.128:7001: OK
Connecting to node 192.168.207.128:7000: OK
Connecting to node 192.168.207.130:7005: OK
>>> Performing Cluster Check (using node 192.168.207.128:7002)
S: 0becd52cb1fa1a69f8d3135dd98f87cd8ccf9d78 192.168.207.128:7002
   slots: (0 slots) slave
   replicates 8490b5e84bf0359871ea3fa55b97bb9877be0512
M: 8490b5e84bf0359871ea3fa55b97bb9877be0512 192.168.207.130:7003
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
M: 9d076e70871fc7291485aba97b2623dc9fb3b3b0 192.168.207.130:7004
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
M: 568669e03c61b3c4edc31643dcb47e85bc2c3e23 192.168.207.128:7001
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: 7dae923773125c5956605fac6159412850b100b3 192.168.207.128:7000
   slots: (0 slots) slave
   replicates 9d076e70871fc7291485aba97b2623dc9fb3b3b0
S: f3ba7c62307e0321f5d21310d14027c403c73907 192.168.207.130:7005
   slots: (0 slots) slave
   replicates 568669e03c61b3c4edc31643dcb47e85bc2c3e23
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
Connecting to node 192.168.207.130:7006: OK
>>> Send CLUSTER MEET to node 192.168.207.130:7006 to make it join the cluster.
[OK] New node added correctly.      

成功把節點加入到叢集後再來檢查一下叢集狀态:

192.168.207.130:7003> cluster nodes
b502b7efac704e92ac439933a42edf613f908fea 192.168.207.130:7006 master - 0 1444270807484 0 connected
f3ba7c62307e0321f5d21310d14027c403c73907 192.168.207.130:7005 slave 568669e03c61b3c4edc31643dcb47e85bc2c3e23 0 1444270805452 6 connected
7dae923773125c5956605fac6159412850b100b3 192.168.207.128:7000 slave 9d076e70871fc7291485aba97b2623dc9fb3b3b0 0 1444270806468 7 connected
0becd52cb1fa1a69f8d3135dd98f87cd8ccf9d78 192.168.207.128:7002 slave 8490b5e84bf0359871ea3fa55b97bb9877be0512 0 1444270804437 4 connected
568669e03c61b3c4edc31643dcb47e85bc2c3e23 192.168.207.128:7001 master - 0 1444270804437 2 connected 10923-16383
8490b5e84bf0359871ea3fa55b97bb9877be0512 192.168.207.130:7003 myself,master - 0 0 4 connected 5461-10922
9d076e70871fc7291485aba97b2623dc9fb3b3b0 192.168.207.130:7004 master - 0 1444270804437 7 connected 0-5460      

從上邊的輸出中可知redis7006已是一個master節點,但此時此節點不存放任何資料,因為它沒有被配置設定hash slot,是以想讓此節點真正的工作起來,你還得做一個切分操作,把在其他節點上的hash slot轉移一部份到新增的節點上來,這個操作也是通過redis-trib.rb工具來完成的,具體用法如下:

./redis-trib.rb reshard IP:PORT      

采用reshard參數表示重新切分,後邊的IP:PORT是叢集中任意一個節點的ip位址和端口,redis-trib.rb工具會自動尋找叢集中的其他節點。

現在我們就來把7004上的2000個slot轉移到7006上,如下操作:

redis@master:~/redis7000$ bin/redis-trib.rb reshard 192.168.207.128:7000
Connecting to node 192.168.207.128:7000: OK
Connecting to node 192.168.207.130:7004: OK
Connecting to node 192.168.207.130:7003: OK
Connecting to node 192.168.207.128:7002: OK
Connecting to node 192.168.207.128:7001: OK
Connecting to node 192.168.207.130:7006: OK
Connecting to node 192.168.207.130:7005: OK
>>> Performing Cluster Check (using node 192.168.207.128:7000)
S: 7dae923773125c5956605fac6159412850b100b3 192.168.207.128:7000
   slots: (0 slots) slave
   replicates 9d076e70871fc7291485aba97b2623dc9fb3b3b0
M: 9d076e70871fc7291485aba97b2623dc9fb3b3b0 192.168.207.130:7004
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
M: 8490b5e84bf0359871ea3fa55b97bb9877be0512 192.168.207.130:7003
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
S: 0becd52cb1fa1a69f8d3135dd98f87cd8ccf9d78 192.168.207.128:7002
   slots: (0 slots) slave
   replicates 8490b5e84bf0359871ea3fa55b97bb9877be0512
M: 568669e03c61b3c4edc31643dcb47e85bc2c3e23 192.168.207.128:7001
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
M: b502b7efac704e92ac439933a42edf613f908fea 192.168.207.130:7006
   slots: (0 slots) master
   0 additional replica(s)
S: f3ba7c62307e0321f5d21310d14027c403c73907 192.168.207.130:7005
   slots: (0 slots) slave
   replicates 568669e03c61b3c4edc31643dcb47e85bc2c3e23
[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)? 2000   #輸入2000
What is the receiving node ID? b502b7efac704e92ac439933a42edf613f908fea   #輸入哪個節點想接收這些slot,這裡就是7006的ID
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:9d076e70871fc7291485aba97b2623dc9fb3b3b0    #輸入想從哪個節點移動slot,我這裡輸入了7004的ID
Source node #2:done   #輸入done回車後會輸出具體會移動的slot
    Moving slot 0 from 9d076e70871fc7291485aba97b2623dc9fb3b3b0
    .........略........
    Moving slot 1995 from 9d076e70871fc7291485aba97b2623dc9fb3b3b0
    Moving slot 1996 from 9d076e70871fc7291485aba97b2623dc9fb3b3b0
    Moving slot 1997 from 9d076e70871fc7291485aba97b2623dc9fb3b3b0
    Moving slot 1998 from 9d076e70871fc7291485aba97b2623dc9fb3b3b0
    Moving slot 1999 from 9d076e70871fc7291485aba97b2623dc9fb3b3b0
Do you want to proceed with the proposed reshard plan (yes/no)? yes   #執行計劃,開始真正移動slot
Moving slot 0 from 192.168.207.130:7004 to 192.168.207.130:7006:
.....略.....
Moving slot 1993 from 192.168.207.130:7004 to 192.168.207.130:7006:
Moving slot 1994 from 192.168.207.130:7004 to 192.168.207.130:7006:
Moving slot 1995 from 192.168.207.130:7004 to 192.168.207.130:7006:
Moving slot 1996 from 192.168.207.130:7004 to 192.168.207.130:7006:
Moving slot 1997 from 192.168.207.130:7004 to 192.168.207.130:7006:
Moving slot 1998 from 192.168.207.130:7004 to 192.168.207.130:7006:
Moving slot 1999 from 192.168.207.130:7004 to 192.168.207.130:7006:
redis@master:~/redis7000$      

移動完成後再檢視一下叢集狀态,如下:

192.168.207.130:7003> cluster nodes
b502b7efac704e92ac439933a42edf613f908fea 192.168.207.130:7006 master - 0 1444273978574 8 connected 0-1999    #已有2000個slot
f3ba7c62307e0321f5d21310d14027c403c73907 192.168.207.130:7005 slave 568669e03c61b3c4edc31643dcb47e85bc2c3e23 0 1444273977559 6 connected
7dae923773125c5956605fac6159412850b100b3 192.168.207.128:7000 slave 9d076e70871fc7291485aba97b2623dc9fb3b3b0 0 1444273975530 7 connected
0becd52cb1fa1a69f8d3135dd98f87cd8ccf9d78 192.168.207.128:7002 slave 8490b5e84bf0359871ea3fa55b97bb9877be0512 0 1444273977559 4 connected
568669e03c61b3c4edc31643dcb47e85bc2c3e23 192.168.207.128:7001 master - 0 1444273975530 2 connected 10923-16383
8490b5e84bf0359871ea3fa55b97bb9877be0512 192.168.207.130:7003 myself,master - 0 0 4 connected 5461-10922
9d076e70871fc7291485aba97b2623dc9fb3b3b0 192.168.207.130:7004 master - 0 1444273976544 7 connected 2000-5460   #少了2000個solt      

至此,新節點已增加到叢集并能正常工作。

4.3、redis cluster删除節點

    有增加節點的操作,當然也會有删除一個節點,當業務量下降後,叢集中redis節點數量服務能力大大超過了業務所帶來的壓力,此時我們應該移除一些節點,回收主機資源,以免造成資源的浪費。

移除一個節點用如下指令:

./redis-trib.rb del-node IP:PORT 'node-id'      

 IP:PORT表示叢集中任意一個節點的ip位址和端口,node-id表示你想要移除的節點ID号

接下來就測試一下删除一個節點的操作,我們計劃把7004這個節點删除,那運作如下指令:

redis@master:~/redis7000$ bin/redis-trib.rb del-node 192.168.207.128:7000 '9d076e70871fc7291485aba97b2623dc9fb3b3b0'
>>> Removing node 9d076e70871fc7291485aba97b2623dc9fb3b3b0 from cluster 192.168.207.128:7000
Connecting to node 192.168.207.128:7000: OK
Connecting to node 192.168.207.130:7004: OK
Connecting to node 192.168.207.130:7003: OK
Connecting to node 192.168.207.128:7002: OK
Connecting to node 192.168.207.128:7001: OK
Connecting to node 192.168.207.130:7006: OK
Connecting to node 192.168.207.130:7005: OK
[ERR] Node 192.168.207.130:7004 is not empty! Reshard data away and try again.      

  上邊報錯了,說是這個節點不是空的,需要重新切片後再嘗試,這是因為在這個節點上還有2000-5460的slot,需要把這些slot移走後才能删除此節點,我們就把7004上的所有slot移到7006後再來删除此節點試試:

redis@master:~/redis7000$ bin/redis-trib.rb reshard  --from 9d076e70871fc7291485aba97b2623dc9fb3b3b0 --to b502b7efac704e92ac439933a42edf613f908fea --slots 3461 --yes 192.168.207.128:7000      

#上邊的指令是一種非互動子產品下的資料遷移指令,用“--from...--to”的結構表示從哪個節點把資料遷移到哪個節點,官方指令格式是“./redis-trib.rb reshard <host>:<port> --from <node-id> --to <node-id> --slots --yes”這樣的,但在實際運用時發現“<host>:<port>”需要寫在最後,這個是表示叢集中任意一個節點的ip位址和端口資訊。

運作上表指令并等待一會兒後,資料就遷移完畢,再來觀察一下叢集中7004節點的狀态資訊:

192.168.207.130:7004> cluster nodes
f3ba7c62307e0321f5d21310d14027c403c73907 192.168.207.130:7005 slave 568669e03c61b3c4edc31643dcb47e85bc2c3e23 0 1444283310797 6 connected
568669e03c61b3c4edc31643dcb47e85bc2c3e23 192.168.207.128:7001 master - 0 1444283307772 2 connected 10923-16383
8490b5e84bf0359871ea3fa55b97bb9877be0512 192.168.207.130:7003 master - 0 1444283306763 4 connected 5461-10922
0becd52cb1fa1a69f8d3135dd98f87cd8ccf9d78 192.168.207.128:7002 slave 8490b5e84bf0359871ea3fa55b97bb9877be0512 0 1444283308780 4 connected
9d076e70871fc7291485aba97b2623dc9fb3b3b0 192.168.207.130:7004 myself,master - 0 0 7 connected
     
7dae923773125c5956605fac6159412850b100b3 192.168.207.128:7000 slave 9d076e70871fc7291485aba97b2623dc9fb3b3b0 0 1444283308780 7 connected
b502b7efac704e92ac439933a42edf613f908fea 192.168.207.130:7006 master - 0 1444283309788 8 connected 0-5460      

看見了吧,上邊輸出資訊中7004已沒有slot了,現在再來移除此節點試試:

redis@master:~/redis7000$ bin/redis-trib.rb del-node 192.168.207.128:7000 '9d076e70871fc7291485aba97b2623dc9fb3b3b0'
>>> Removing node 9d076e70871fc7291485aba97b2623dc9fb3b3b0 from cluster 192.168.207.128:7000
Connecting to node 192.168.207.128:7000: OK
Connecting to node 192.168.207.130:7004: OK
Connecting to node 192.168.207.130:7003: OK
Connecting to node 192.168.207.128:7002: OK
Connecting to node 192.168.207.128:7001: OK
Connecting to node 192.168.207.130:7006: OK
Connecting to node 192.168.207.130:7005: OK
>>> Sending CLUSTER FORGET messages to the cluster...
>>> 192.168.207.128:7000 as replica of 192.168.207.130:7006
>>> SHUTDOWN the node.      

移除成功了,移除後還會重新計算叢集中的主從關系,并把移除的節點shutdown,這裡就把7000作為7006的從節點了,再來檢視叢集狀态就是這樣了:

redis@slave01:~/redis7004$ bin/redis-cli -c -h 192.168.207.130 -p 7003
192.168.207.130:7003> cluster nodes
b502b7efac704e92ac439933a42edf613f908fea 192.168.207.130:7006 master - 0 1444283726189 8 connected 0-5460
f3ba7c62307e0321f5d21310d14027c403c73907 192.168.207.130:7005 slave 568669e03c61b3c4edc31643dcb47e85bc2c3e23 0 1444283728207 6 connected
7dae923773125c5956605fac6159412850b100b3 192.168.207.128:7000 slave b502b7efac704e92ac439933a42edf613f908fea 0 1444283725182 8 connected
     #看下他的主節點是7006
0becd52cb1fa1a69f8d3135dd98f87cd8ccf9d78 192.168.207.128:7002 slave 8490b5e84bf0359871ea3fa55b97bb9877be0512 0 1444283729216 4 connected
568669e03c61b3c4edc31643dcb47e85bc2c3e23 192.168.207.128:7001 master - 0 1444283728207 2 connected 10923-16383
8490b5e84bf0359871ea3fa55b97bb9877be0512 192.168.207.130:7003 myself,master - 0 0 4 connected 5461-10922      

4.4、redis cluster主從手動切換

    也許在一些特殊的場景你需要切換叢集中主從節點,比如你想讓一個主節點下線更新維護時,當然你可簡單粗爆的把這個主節點shutdown,然後redis cluster會監測到叢集中少了一個主節點,叢集就會把他的從節點提升為主節點,然後你再把shutdown的節點啟動,那他會成為一個從節點運作,這樣你就可以做你想做的了。但這樣粗爆的行為是會導緻叢集短暫的停止服務,有一個切換的時間,如果是一個可控的維護工作,我們還是希望更為平滑,那叢集中手動切換工具就能滿足我們的需求。

    我們先連接配接到叢集中,檢視一下叢集狀态資訊,如下:

redis@slave01:~/redis7004$ bin/redis-cli -c -h 192.168.207.128 -p 7002
    #連接配接到7002從節點
192.168.207.128:7002> cluster nodes
8490b5e84bf0359871ea3fa55b97bb9877be0512 192.168.207.130:7003 master - 0 1444285238614 4 connected 5461-10922
0becd52cb1fa1a69f8d3135dd98f87cd8ccf9d78 192.168.207.128:7002 myself,slave 8490b5e84bf0359871ea3fa55b97bb9877be0512 0 0 3 connected
   #7002的主節點是7003
568669e03c61b3c4edc31643dcb47e85bc2c3e23 192.168.207.128:7001 master - 0 1444285240634 2 connected 10923-16383
b502b7efac704e92ac439933a42edf613f908fea 192.168.207.130:7006 master - 0 1444285237604 8 connected 0-5460
7dae923773125c5956605fac6159412850b100b3 192.168.207.128:7000 slave b502b7efac704e92ac439933a42edf613f908fea 0 1444285239625 8 connected
f3ba7c62307e0321f5d21310d14027c403c73907 192.168.207.130:7005 slave 568669e03c61b3c4edc31643dcb47e85bc2c3e23 0 1444285239625 6 connected      

接下來就進行手動切換操作,把7002與7003的主從關系調換:

192.168.207.128:7002> cluster failover
    #這就是切換指令
OK
192.168.207.128:7002> cluster nodes
8490b5e84bf0359871ea3fa55b97bb9877be0512 192.168.207.130:7003 slave 0becd52cb1fa1a69f8d3135dd98f87cd8ccf9d78 0 1444285980634 9 connected
   #變成slave了
0becd52cb1fa1a69f8d3135dd98f87cd8ccf9d78 192.168.207.128:7002 myself,master - 0 0 9 connected 5461-10922
    #變成master了
568669e03c61b3c4edc31643dcb47e85bc2c3e23 192.168.207.128:7001 master - 0 1444285977604 2 connected 10923-16383
b502b7efac704e92ac439933a42edf613f908fea 192.168.207.130:7006 master - 0 1444285976594 8 connected 0-5460
7dae923773125c5956605fac6159412850b100b3 192.168.207.128:7000 slave b502b7efac704e92ac439933a42edf613f908fea 0 1444285979624 8 connected
f3ba7c62307e0321f5d21310d14027c403c73907 192.168.207.130:7005 slave 568669e03c61b3c4edc31643dcb47e85bc2c3e23 0 1444285978615 6 connected
192.168.207.128:7002>      

在上邊的主從切換測試中幾乎是瞬間完成,這樣業務是不受到影響的。值得注意的是“cluster failover”指令隻能在slave節點上運作,這也是在上邊我是連接配接到7002的原因。在主從切換時采用何種方法,這也許這就是一個優秀的運維工程師和一個菜鳥的差別吧!

    斷斷續續的寫了好幾天才完成此博文,通過此文我也對redis有了更深入的認識,也讓我更能走近redis,才能發現redis之美,之強。保持一顆求的心繼續上路。

參考資料:

http://redis.io/topics/replication#how-redis-replication-works

http://redis.io/topics/sentinel