centos6下redis cluster叢集部署過程

散盡浮華發表於2017-11-16

 

一般來說,redis主從和mysql主從目的差不多,但redis主從配置很簡單,主要在從節點配置檔案指定主節點ip和埠,比如:slaveof 192.168.10.10 6379,然後啟動主從,主從就搭建好了。redis主從中如果主節點發生故障,不會自動切換,需要藉助redis的Sentinel(哨兵模式)或者keepalive來實現主的故障轉移。

今天介紹下redis cluster叢集模式:
redis叢集是一個無中心的分散式redis儲存架構,可以在多個節點之間進行資料共享,解決了redis高可用、可擴充套件等問題,redis叢集提供了以下兩個好處:
1)將資料自動切分(split)到多個節點
2)當叢集中的某一個節點故障時,redis還可以繼續處理客戶端的請求。

一個 Redis 叢集包含 16384 個雜湊槽(hash slot),資料庫中的每個資料都屬於這16384個雜湊槽中的一個。叢集使用公式 CRC16(key) % 16384 來計算鍵 key 屬於哪個槽。叢集中的每一個節點負責處理一部分雜湊槽。
叢集中的主從複製
叢集中的每個節點都有1個至N個複製品,其中一個為主節點,其餘的為從節點,如果主節點下線了,叢集就會把這個主節點的一個從節點設定為新的主節點,繼續工作。這樣叢集就不會因為一個主節點的下線而無法正常工作。

==========從Redis3.x開始已經支援Load Balance功能了===========

Redis Cluster叢集功能推出已經有一段時間了。在單機版的Redis中,每個Master之間是沒有任何通訊的,所以一般在Jedis客戶端或者Codis這樣的代理中做Pre-sharding。按照CAP理論來說,單機版的Redis屬於保證CP(Consistency & Partition-Tolerancy)而犧牲A(Availability),也就說Redis能夠保證所有使用者看到相同的資料(一致性,因為Redis不自動冗餘資料)和網路通訊出問題時,暫時隔離開的子系統能繼續執行(分割槽容忍性,因為Master之間沒有直接關係,不需要通訊),但是不保證某些結點故障時,所有請求都能被響應(可用性,某個Master結點掛了的話,那麼它上面分片的資料就無法訪問了)。

有了Cluster功能後,Redis從一個單純的NoSQL記憶體資料庫變成了分散式NoSQL資料庫,CAP模型也從CP變成了AP。也就是說,通過自動分片和冗餘資料,Redis具有了真正的分散式能力,某個結點掛了的話,因為資料在其他結點上有備份,所以其他結點頂上來就可以繼續提供服務,保證了Availability。然而,也正因為這一點,Redis無法保證曾經的強一致性了。這也是CAP理論要求的,三者只能取其二。

Redis Cluster 是Redis的叢集實現,內建資料自動分片機制,叢集內部將所有的key對映到16384個Slot中,叢集中的每個Redis Instance負責其中的一部分的Slot的讀寫。叢集客戶端連線叢集中任一Redis Instance即可傳送命令,當Redis Instance收到自己不負責的Slot的請求時,會將負責請求Key所在Slot的Redis Instance地址返回給客戶端,客戶端收到後自動將原請求重新發往這個地址,對外部透明。一個Key到底屬於哪個Slot由crc16(key) % 16384 決定。在Redis Cluster裡對於負載均衡和HA相關都已經支援的相當完善了。

負載均衡(Load Balance):叢集的Redis Instance之間可以遷移資料,以Slot為單位,但不是自動的,需要外部命令觸發。
叢集成員管理:叢集的節點(Redis Instance)和節點之間兩兩定期交換叢集內節點資訊並且更新,從傳送節點的角度看,這些資訊包括:叢集內有哪些節點,IP和PORT是什麼,節點名字是什麼,節點的狀態(比如OK,PFAIL,FAIL,後面詳述)是什麼,包括節點角色(master 或者 slave)等。
關於可用性,叢集由N組主從Redis Instance組成。

主可以沒有從,但是沒有從 意味著主當機後主負責的Slot讀寫服務不可用。

一個主可以有多個從,主當機時,某個從會被提升為主,具體哪個從被提升為主,協議類似於Raft,參見這裡。如何檢測主當機?Redis Cluster採用quorum+心跳的機制。從節點的角度看,節點會定期給其他所有的節點傳送Ping,cluster-node-timeout(可配置,秒級)時間內沒有收到對方的回覆,則單方面認為對端節點當機,將該節點標為PFAIL狀態。通過節點之間交換資訊收集到quorum個節點都認為這個節點為PFAIL,則將該節點標記為FAIL,並且將其傳送給其他所有節點,其他所有節點收到後立即認為該節點當機。從這裡可以看出,主當機後,至少cluster-node-timeout時間內該主所負責的Slot的讀寫服務不可用。

Redis Cluster的特點如下:

  • 節點自動發現
  • slave->master選舉,叢集容錯
  • Hot resharding:線上分片
  • 叢集管理:clusterxxx
  • 基於配置(nodes-port.conf)的叢集管理
  • ASK 轉向/MOVED轉向機制
  • 佈署無需指定master
  • 可以支援超過1,000臺節點的叢集

======Redis-Cluster採用無中心結構,每個節點儲存資料和整個叢集狀態,每個節點都和其他所有節點連線======
redis-cluster架構圖如下:

 

其結構特點:

  • 所有的redis節點彼此互聯(PING-PONG機制),內部使用二進位制協議優化傳輸速度和頻寬。
  • 節點的fail是通過叢集中超過半數的節點檢測失效時才生效。
  • 客戶端與redis節點直連,不需要中間proxy層.客戶端不需要連線叢集所有節點,連線叢集中任何一個可用節點即可。
  • redis-cluster把所有的物理節點對映到[0-16383]slot上(不一定是平均分配),cluster 負責維護node<->slot<->value。
  • Redis叢集預分好16384個桶,當需要在 Redis 叢集中放置一個 key-value 時,根據 CRC16(key) mod 16384的值,決定將一個key放到哪個桶中。

redis cluster叢集是為了降低單節點或單純主從redis的壓力,主主節點之間是不存在同步關係的,各主從之間的資料存在同步關係。有多少主節點,就會把16384個雜湊槽(hash slot)平均分配到這些主節點上當往redis裡寫入資料時,會根據雜湊演算法算出這個數的雜湊槽,決定它放到哪一個主節點上,然後這個主節點的從節點去自動同步。在客戶端隨便連線一個主節點即可,主節點之間會進行內部跳轉!當取對應資料時,各節點之間會自動跳轉到所取資料所在的主節點上!

1)redis cluster節點分配
假設現有有三個主節點分別是:A、 B、C ,它們可以是一臺機器上的三個埠,也可以是三臺不同的伺服器。那麼,採用雜湊槽 (hash slot)的方式
來分配16384個slot 的話,它們三個節點分別承擔的slot 區間是:
節點A         覆蓋0-5460;
節點B         覆蓋5461-10922;
節點C        覆蓋10923-16383.

獲取資料:
如果存入一個值,按照redis cluster雜湊槽的演算法: CRC16('key')%16384 = 6782。 那麼就會把這個key 的儲存分配到 B 上了。同樣,當我連線
(A,B,C)任何一個節點想獲取'key'這個key時,也會這樣的演算法,然後內部跳轉到B節點上獲取資料

新增一個主節點:
新增一個節點D,redis cluster的這種做法是從各個節點的前面各拿取一部分slot到D上,我會在接下來的實踐中實驗。大致就會變成這樣:
節點A         覆蓋1365-5460
節點B        覆蓋6827-10922
節點C       覆蓋12288-16383
節點D       覆蓋0-1364,5461-6826,10923-12287

同樣刪除一個節點也是類似,移動完成後就可以刪除這個節點了。

2)Redis Cluster主從模式
redis cluster 為了保證資料的高可用性,加入了主從模式,一個主節點對應一個或多個從節點,主節點提供資料存取,從節點則是從主節點拉取資料
備份,當這個主節點掛掉後,就會有這個從節點選取一個來充當主節點,從而保證叢集不會掛掉。

上面那個例子裡, 叢集有A、B、C三個主節點, 如果這3個節點都沒有加入從節點,如果B掛掉了,我們就無法訪問整個叢集了。A和C的slot也無法訪問。
所以在叢集建立的時候,一定要為每個主節點都新增了從節點, 比如像這樣, 叢集包含主節點A、B、C, 以及從節點A1、B1、C1, 那麼即使B掛掉系統也
可以繼續正確工作。B1節點替代了B節點,所以Redis叢集將會選擇B1節點作為新的主節點,叢集將會繼續正確地提供服務。 當B重新開啟後,它就會變成B1的從節點。

不過需要注意,如果節點B和B1同時掛了,Redis叢集就無法繼續正確地提供服務了。

===========廢話不多說,下面記錄下搭建redis cluster叢集==========
由於最小的redis叢集需要3個主節點(即Redis Cluster叢集至少需要3個master節點,也就是說至少需要6個節點才能構建Redis cluster叢集),一臺機器可執行多個redis例項(一般使用兩臺機器,每臺啟動3個redis例項,即三個主節點,三個從節點)。很多案例使用單臺伺服器開6個埠,操作差不多,只是配置基本相對簡單點,多臺伺服器更接近生產環境。【當叢集最開始建立好後,要記住各節點的主從關係(或是建立的時候指定主從關係);若是其中一臺機器重啟,重啟後,需重新將其加入到redis cluster叢集中;這就需要將這臺機器上的各節點之前的從節點變為主節點(客戶端執行slaveof no one),然後再根據新的主節點新增這臺機器的各節點到叢集中,新增後變為從節點】
本案例redis cluster節點資訊:
redis01
172.16.51.175:7000
172.16.51.175:7001
172.16.51.175:7002
redis02
172.16.51.176:7003
172.16.51.176:7004
172.16.51.176:7005
redis03
172.16.51.178:7006
172.16.51.178:7007
172.16.51.178:7008

先說下redis01節點的部署過程(其他兩臺節點部署過程一致)

個人運維習慣,會專門建立一個app賬號,使用者部署應用程式。本案例應用程式都部署在/data目錄下,將/data許可權設定成app
[root@bl-redis01 ~]# useradd app
[root@bl-redis01 ~]# passwd app
[root@bl-redis01 ~]# chown -R app.app /data
 
前提準備
1)安裝 GCC 編譯工具 不然會有編譯不過的問題
[root@bl-redis01 ~]# yum install -y gcc g++ make gcc-c++ kernel-devel automake autoconf libtool make wget tcl vim ruby rubygems unzip git
 
2)升級所有的包,防止出現版本過久不相容問題
[root@bl-redis01 ~]# yum -y update
 
3)關閉防火牆 節點之前需要開放指定埠,為了方便,生產不要禁用
[root@bl-redis01 ~]# /etc/init.d/iptables stop
[root@bl-redis01 ~]# setenforce 0
[root@bl-redis01 ~]# vim /etc/sysconfig/selinux
......
SELINUX=disabled
......
 
redis cluster叢集部署
4)下載並編譯安裝redis
[root@bl-redis01 ~]# su - app
[app@bl-redis01 ~]$ mkdir /data/software/
[app@bl-redis01 software]$ wget http://download.redis.io/releases/redis-4.0.1.tar.gz
[app@bl-redis01 software]$ tar -zvxf redis-4.0.1.tar.gz
[app@bl-redis01 software]$ mv redis-4.0.1 /data/
[app@bl-redis01 software]$ cd /data/redis-4.0.1/
[app@bl-redis01 redis-4.0.1]$ make
--------------------------------------------------------------------------------------
如果因為上次編譯失敗,有殘留的檔案,做法如下:
[app@bl-redis01 redis-4.0.1]$ make distclean
--------------------------------------------------------------------------------------
 
5)建立節點
首先在172.16.51.175機器(redis01)上/data/redis-4.0.1目錄下建立redis-cluster目錄
[app@bl-redis01 redis-4.0.1]$ mkdir /data/redis-4.0.1/redis-cluster
 
接著在redis-cluster目錄下,建立名為7000、7001、7002的目錄
[app@bl-redis01 redis-cluster]$ mkdir 7000
[app@bl-redis01 redis-cluster]$ mkdir 7001
[app@bl-redis01 redis-cluster]$ mkdir 7002
 
分別修改這三個配置檔案redis.conf
[app@bl-redis01 redis-4.0.1]$ cd redis-cluster/
[app@bl-redis01 redis-cluster]$ ll
total 12
drwxrwxr-x 2 app app 4096 Nov 16 17:38 7000
drwxrwxr-x 2 app app 4096 Nov 16 17:39 7001
drwxrwxr-x 2 app app 4096 Nov 16 17:39 7002
[app@bl-redis01 redis-cluster]$ cat 7000/redis.conf
port 7000
bind 172.16.51.175
daemonize yes
pidfile /var/run/redis_7000.pid
cluster-enabled yes
cluster-config-file nodes_7000.conf
cluster-node-timeout 10100
appendonly yes
[app@bl-redis01 redis-cluster]$ cat 7001/redis.conf
port 7001
bind 172.16.51.175
daemonize yes
pidfile /var/run/redis_7001.pid
cluster-enabled yes
cluster-config-file nodes_7001.conf
cluster-node-timeout 10100
appendonly yes
[app@bl-redis01 redis-cluster]$ cat 7002/redis.conf
port 7002
bind 172.16.51.175
daemonize yes
pidfile /var/run/redis_7002.pid
cluster-enabled yes
cluster-config-file nodes_7002.conf
cluster-node-timeout 10100
appendonly yes
 
----------------------------------------------------------------------------------------------------
redis.conf的配置說明:
#埠7000,7001,7002
port 7000
 
#預設ip為127.0.0.1,需要改為其他節點機器可訪問的ip,否則建立叢集時無法訪問對應的埠,無法建立叢集
bind 172.16.51.175
 
#redis後臺執行
daemonize yes
 
#pidfile檔案對應7000,7001,7002
pidfile /var/run/redis_7000.pid
 
#開啟叢集,把註釋#去掉
cluster-enabled yes
 
#叢集的配置,配置檔案首次啟動自動生成 7000,7001,7002         
cluster-config-file nodes_7000.conf
 
#請求超時,預設15秒,可自行設定
cluster-node-timeout 10100   
         
#aof日誌開啟,有需要就開啟,它會每次寫操作都記錄一條日誌
appendonly yes
----------------------------------------------------------------------------------------------------
 
接著在另外兩臺機器上(172.16.51.176,172.16.51.178)重複以上三步,只是把目錄改為7003、7004、7005和7006、7007、7008,對應的配置檔案也按照這個規則修改即可(即修改redis.conf檔案中的埠就行了)
 
6)啟動叢集(依次啟動7000-7008埠)
#第一個節點機器上執行 3個節點
[app@bl-redis01 redis-cluster]$ for((i=0;i<=2;i++)); do /data/redis-4.0.1/src/redis-server /data/redis-4.0.1/redis-cluster/700$i/redis.conf; done
 
#第二個節點機器上執行 3個節點
[app@bl-redis01 redis-cluster]$ for((i=3;i<=5;i++)); do /data/redis-4.0.1/src/redis-server /data/redis-4.0.1/redis-cluster/700$i/redis.conf; done
 
#第三個節點機器上執行 3個節點
[app@bl-redis01 redis-cluster]$ for((i=6;i<=8;i++)); do /data/redis-4.0.1/src/redis-server /data/redis-4.0.1/redis-cluster/700$i/redis.conf; done
 
7)檢查服務
檢查各 Redis 各個節點啟動情況
[app@bl-redis01 redis-cluster]$ ps -ef | grep redis 
app       2564  2405  0 20:13 pts/0    00:00:00 grep redis
app      15197     1  0 17:57 ?        00:00:05 /data/redis-4.0.1/src/redis-server 172.16.51.175:7000 [cluster]                  
app      15199     1  0 17:57 ?        00:00:05 /data/redis-4.0.1/src/redis-server 172.16.51.175:7001 [cluster]                  
app      15201     1  0 17:57 ?        00:00:05 /data/redis-4.0.1/src/redis-server 172.16.51.175:7002 [cluster]                  
[app@bl-redis01 redis-cluster]$ ps -ef | grep redis 
app       2566  2405  0 20:13 pts/0    00:00:00 grep redis
app      15197     1  0 17:57 ?        00:00:05 /data/redis-4.0.1/src/redis-server 172.16.51.175:7000 [cluster]                  
app      15199     1  0 17:57 ?        00:00:05 /data/redis-4.0.1/src/redis-server 172.16.51.175:7001 [cluster]                  
app      15201     1  0 17:57 ?        00:00:05 /data/redis-4.0.1/src/redis-server 172.16.51.175:7002 [cluster]
 
8)安裝 Ruby(需要切換到root賬號下進行安裝,app賬號下許可權不夠)
[root@bl-redis01 ~]# yum -y install ruby ruby-devel rubygems rpm-build
[root@bl-redis01 ~]# gem install redis
-----------------------------------------------------------------------------------------------------
注意:在centos6.x下執行上面的"gem install redis"操作可能會報錯,坑很多!
預設yum安裝的ruby版本是1.8.7,版本太低,需要升級到ruby2.2以上,否則執行上面安裝會報錯!
 
首先安裝rvm(或者直接下載證照:https://pan.baidu.com/s/1slTyJ7n  金鑰:7uan   下載並解壓後直接執行"curl -L get.rvm.io | bash -s stable"即可)
[root@bl-redis01 ~]# curl -L get.rvm.io | bash -s stable          //可能會報錯,需要安裝提示進行下面一步操作
[root@bl-redis01 ~]# curl -sSL https://rvm.io/mpapis.asc | gpg2 --import -      //然後再接著執行:curl -L get.rvm.io | bash -s stable
[root@bl-redis01 ~]# find / -name rvm.sh
/etc/profile.d/rvm.sh
[root@bl-redis01 ~]# source /etc/profile.d/rvm.sh
[root@bl-redis01 ~]# rvm requirements
 
然後升級ruby到2.3
[root@bl-redis01 ~]# rvm install ruby 2.3.1
[root@bl-redis01 ~]# ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-linux]
 
列出所有ruby版本
[root@bl-redis01 ~]# rvm list
 
設定預設的版本
[root@bl-redis01 ~]# rvm --default use 2.3.1
 
更新下載源
[root@bl-redis01 ~]# gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org
https://gems.ruby-china.org/ added to sources
source https://rubygems.org not present in cache
 
[root@bl-redis01 ~]# gem sources
*** CURRENT SOURCES ***
 
https://rubygems.org/
https://gems.ruby-china.org/
 
最後就能順利安裝了
[root@bl-redis01 src]# gem install redis
Successfully installed redis-4.0.1
Parsing documentation for redis-4.0.1
Done installing documentation for redis after 1 seconds
1 gem installed
-----------------------------------------------------------------------------------------------------
 
9)建立叢集
千萬注意:在任意一臺上執行即可,不要在每臺機器上都執行,一臺就夠了!!!!
Redis 官方提供了 redis-trib.rb 這個工具,就在解壓目錄的 src 目錄中
[root@bl-redis01 ~]# su - app
[app@bl-redis01 ~]$ /data/redis-4.0.1/src/redis-trib.rb create --replicas 1 172.16.51.175:7000 172.16.51.175:7001 172.16.51.175:7002 172.16.51.176:7003 172.16.51.176:7004 172.16.51.176:7005 172.16.51.178:7006 172.16.51.178:7007 172.16.51.178:7008
 
出現下面資訊,從下面資訊可以看出,本案例三臺伺服器啟動9個例項,配置成4主5從,其中有一個是一主兩從,其他3個都是一主一從。
>>> Creating cluster
>>> Performing hash slots allocation on 9 nodes...
Using 4 masters:
172.16.51.175:7000
172.16.51.176:7003
172.16.51.178:7006
172.16.51.175:7001
Adding replica 172.16.51.176:7004 to 172.16.51.175:7000
Adding replica 172.16.51.178:7007 to 172.16.51.176:7003
Adding replica 172.16.51.175:7002 to 172.16.51.178:7006
Adding replica 172.16.51.176:7005 to 172.16.51.175:7001
Adding replica 172.16.51.178:7008 to 172.16.51.175:7000
M: 7c622ac191edd40dd61d9b79b27f6f69d02a5bbf 172.16.51.175:7000
   slots:0-4095 (4096 slots) master
M: 44c81c15b01d992cb9ede4ad35477ec853d70723 172.16.51.175:7001
   slots:12288-16383 (4096 slots) master
S: 38f03c27af39723e1828eb62d1775c4b6e2c3638 172.16.51.175:7002
   replicates f1abb62a8c9b448ea14db421bdfe3f1d8075189c
M: 987965baf505a9aa43e50e46c76189c51a8f17ec 172.16.51.176:7003
   slots:4096-8191 (4096 slots) master
S: 6555292fed9c5d52fcf5b983c441aff6f96923d5 172.16.51.176:7004
   replicates 7c622ac191edd40dd61d9b79b27f6f69d02a5bbf
S: 2b5ba254a0405d4efde4c459867b15176f79244a 172.16.51.176:7005
   replicates 44c81c15b01d992cb9ede4ad35477ec853d70723
M: f1abb62a8c9b448ea14db421bdfe3f1d8075189c 172.16.51.178:7006
   slots:8192-12287 (4096 slots) master
S: eb4067373d36d8a8df07951f92794e67a6aac022 172.16.51.178:7007
   replicates 987965baf505a9aa43e50e46c76189c51a8f17ec
S: 2919e041dd3d1daf176d6800dcd262f4e727f366 172.16.51.178:7008
   replicates 7c622ac191edd40dd61d9b79b27f6f69d02a5bbf
Can I set the above configuration? (type 'yes' to accept): yes
 
輸入 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 172.16.51.175:7000)
M: 7c622ac191edd40dd61d9b79b27f6f69d02a5bbf 172.16.51.175:7000
   slots:0-4095 (4096 slots) master
   2 additional replica(s)
S: 6555292fed9c5d52fcf5b983c441aff6f96923d5 172.16.51.176:7004
   slots: (0 slots) slave
   replicates 7c622ac191edd40dd61d9b79b27f6f69d02a5bbf
M: 44c81c15b01d992cb9ede4ad35477ec853d70723 172.16.51.175:7001
   slots:12288-16383 (4096 slots) master
   1 additional replica(s)
S: 2919e041dd3d1daf176d6800dcd262f4e727f366 172.16.51.178:7008
   slots: (0 slots) slave
   replicates 7c622ac191edd40dd61d9b79b27f6f69d02a5bbf
M: f1abb62a8c9b448ea14db421bdfe3f1d8075189c 172.16.51.178:7006
   slots:8192-12287 (4096 slots) master
   1 additional replica(s)
S: eb4067373d36d8a8df07951f92794e67a6aac022 172.16.51.178:7007
   slots: (0 slots) slave
   replicates 987965baf505a9aa43e50e46c76189c51a8f17ec
S: 38f03c27af39723e1828eb62d1775c4b6e2c3638 172.16.51.175:7002
   slots: (0 slots) slave
   replicates f1abb62a8c9b448ea14db421bdfe3f1d8075189c
S: 2b5ba254a0405d4efde4c459867b15176f79244a 172.16.51.176:7005
   slots: (0 slots) slave
   replicates 44c81c15b01d992cb9ede4ad35477ec853d70723
M: 987965baf505a9aa43e50e46c76189c51a8f17ec 172.16.51.176:7003
   slots:4096-8191 (4096 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.
 
10)關閉叢集
推薦做法:
[app@bl-redis01 ~]$ pkill redis
[app@bl-redis02 ~]$ pkill redis
[app@bl-redis03 ~]$ pkill redis
 
或者迴圈節點逐個關閉
[app@bl-redis01 ~]$ for((i=0;i<=2;i++)); do /opt/redis-4.0.1/src/redis-cli -c -h 172.16.51.175 -p 700$i shutdown; done
[app@bl-redis02 ~]$ for((i=3;i<=5;i++)); do /opt/redis-4.0.1/src/redis-cli -c -h 172.16.51.176 -p 700$i shutdown; done
[app@bl-redis03 ~]$ for((i=6;i<=8;i++)); do /opt/redis-4.0.1/src/redis-cli -c -h 172.16.51.178 -p 700$i shutdown; done
 
11)叢集驗證
連線叢集測試
引數-C可連線到叢集,因為redis.conf將bind改為了ip地址,所以-h引數不可以省略,-p引數為埠號
 
可以先在172.16.51.175機器redis 7000 的節點set一個key
[app@bl-redis01 ~]$ /data/redis-4.0.1/src/redis-cli -h 172.16.51.175 -c -p 7000
172.16.51.175:7000> set name www.ymq.io
-> Redirected to slot [5798] located at 172.16.51.176:7003
OK
172.16.51.176:7003> get name
"www.ymq.io"
172.16.51.176:7003>
 
由上面資訊可發現redis set name 之後重定向到172.16.51.176機器 redis 7003 這個節點
 
然後在172.16.51.178機器redis 7008 的節點get一個key
[app@bl-redis03 ~]$ /data/redis-4.0.1/src/redis-cli -h 172.16.51.178 -c -p 7008
172.16.51.178:7008> get name
-> Redirected to slot [5798] located at 172.16.51.176:7003
"www.ymq.io"
172.16.51.176:7003>
 
發現redis get name 重定向到172.16.51.176機器 redis 7003 這個節點.
 
如果看到這樣的現象,說明redis cluster叢集已經是可用的了!!!!!!
 
12)檢查叢集狀態(通過下面的命令,可以看到本案例實現的是4主5從,4個主節點會預設分配到三個機器上,每個機器上都要有master;另:建立叢集的時候可以指定master和slave。這裡我是預設建立的)
[app@bl-redis01 ~]$ /data/redis-4.0.1/src/redis-cli -h 172.16.51.175 -c -p 7000
172.16.51.175:7000>
[app@bl-redis01 ~]$ /data/redis-4.0.1/src/redis-trib.rb check 172.16.51.175:7000
>>> Performing Cluster Check (using node 172.16.51.175:7000)
M: 5a43e668f53ff64da68be31afe6dc6ea1f3c14c5 172.16.51.175:7000
   slots:0-4095 (4096 slots) master
   2 additional replica(s)
M: c64b0839e0199f73c5c192cc8c90f12c999f79b2 172.16.51.175:7001
   slots:12288-16383 (4096 slots) master
   1 additional replica(s)
S: 81347f01cf38d8f0faef1ad02676ebb4cffbec9e 172.16.51.176:7005
   slots: (0 slots) slave
   replicates c64b0839e0199f73c5c192cc8c90f12c999f79b2
M: da5dde3f2f02c232784bf3163f5f584b8cf046f2 172.16.51.178:7006
   slots:8192-12287 (4096 slots) master
   1 additional replica(s)
M: b217ab2a6c05497af3b2a859c1bb6b3fae5e0d92 172.16.51.176:7003
   slots:4096-8191 (4096 slots) master
   1 additional replica(s)
S: 0420c49fbc9f1fe16066d189265cca2f5e71c86e 172.16.51.178:7007
   slots: (0 slots) slave
   replicates b217ab2a6c05497af3b2a859c1bb6b3fae5e0d92
S: 5ad89453fb36e50ecc4560de6b4acce1dbbb78b3 172.16.51.176:7004
   slots: (0 slots) slave
   replicates 5a43e668f53ff64da68be31afe6dc6ea1f3c14c5
S: bbd1f279b99b95cf00ecbfab22b6b8dd5eb05989 172.16.51.178:7008
   slots: (0 slots) slave
   replicates 5a43e668f53ff64da68be31afe6dc6ea1f3c14c5
S: e95407b83bfeb30e3cc537161eadc372d6aa1fa2 172.16.51.175:7002
   slots: (0 slots) slave
   replicates da5dde3f2f02c232784bf3163f5f584b8cf046f2
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
 
13)列出叢集節點
列出叢集當前已知的所有節點(node),以及這些節點的相關資訊
[app@bl-redis01 ~]$ /data/redis-4.0.1/src/redis-cli -h 172.16.51.175 -c -p 7000
172.16.51.175:7000> cluster nodes
5a43e668f53ff64da68be31afe6dc6ea1f3c14c5 172.16.51.175:7000@17000 myself,master - 0 1510836027000 1 connected 0-4095
c64b0839e0199f73c5c192cc8c90f12c999f79b2 172.16.51.175:7001@17001 master - 0 1510836030068 2 connected 12288-16383
81347f01cf38d8f0faef1ad02676ebb4cffbec9e 172.16.51.176:7005@17005 slave c64b0839e0199f73c5c192cc8c90f12c999f79b2 0 1510836031000 6 connected
da5dde3f2f02c232784bf3163f5f584b8cf046f2 172.16.51.178:7006@17006 master - 0 1510836031000 7 connected 8192-12287
b217ab2a6c05497af3b2a859c1bb6b3fae5e0d92 172.16.51.176:7003@17003 master - 0 1510836030000 4 connected 4096-8191
0420c49fbc9f1fe16066d189265cca2f5e71c86e 172.16.51.178:7007@17007 slave b217ab2a6c05497af3b2a859c1bb6b3fae5e0d92 0 1510836029067 8 connected
5ad89453fb36e50ecc4560de6b4acce1dbbb78b3 172.16.51.176:7004@17004 slave 5a43e668f53ff64da68be31afe6dc6ea1f3c14c5 0 1510836032672 5 connected
bbd1f279b99b95cf00ecbfab22b6b8dd5eb05989 172.16.51.178:7008@17008 slave 5a43e668f53ff64da68be31afe6dc6ea1f3c14c5 0 1510836031000 9 connected
e95407b83bfeb30e3cc537161eadc372d6aa1fa2 172.16.51.175:7002@17002 slave da5dde3f2f02c232784bf3163f5f584b8cf046f2 0 1510836031672 7 connected
 
14)列印叢集資訊
[app@bl-redis01 ~]$ /data/redis-4.0.1/src/redis-cli -h 172.16.51.175 -c -p 7000
172.16.51.175: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:9
cluster_size:4
cluster_current_epoch:9
cluster_my_epoch:1
cluster_stats_messages_ping_sent:8627
cluster_stats_messages_pong_sent:8581
cluster_stats_messages_sent:17208
cluster_stats_messages_ping_received:8573
cluster_stats_messages_pong_received:8626
cluster_stats_messages_meet_received:8
cluster_stats_messages_received:17207

------------------------------------------------------------------------------------------------
[root@bl-redis01 src]# pwd
/data/redis-4.0.1/src
[root@bl-redis01 src]# ./redis-trib.rb help
Usage: redis-trib <command> <options> <arguments ...>

  create          host1: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.

上面已經多次出現了slot這個詞,略為解釋一下:
redis-cluster把整個叢集的儲存空間劃分為16384個slot(譯為:插槽?),當9個例項分為3主6從時,相當於整個cluster中有3組HA的節點,
3個master會平均分攤所有slot,每次向cluster中的key做操作時(比如:讀取/寫入快取),redis會對key值做CRC32演算法處理,得到一個數值,
然後再對16384取模,通過餘數判斷該快取項應該落在哪個slot上,確定了slot,也就確定了儲存在哪個master節點上,當cluster擴容或刪除
節點時,只需要將slot重新分配即可(即:把部分slot從一些節點移動到其它節點)。

---------------------------------------------------------------------------------------------------------
在程式碼裡連線以上redis cluster叢集節點配置如下:
spring.redis.cluster.nodes = 172.16.51.175:7000,172.16.51.175:7001,172.16.51.175:7002,172.16.51.176:7003,172.16.51.176:7004,172.16.51.176:7005,172.16.51.178:7006,172.16.51.178:7007,172.16.51.178:7008

==========================叢集模式配置======================

以下這種方式貌似不能按照自己的思路新增主從
redis-trib.rb create --replicas 1 192.168.1.101:6381 192.168.1.102:6382  192.168.1.103:6383 192.168.1.102:6381 192.168.1.103:6382   192.168.1.101:6383
 
思路改為先加主庫 再加從庫
新增主庫
redis-trib.rb create  192.168.1.101:6381 192.168.1.102:6382  192.168.1.103:6383
 
新增從庫
把 102的6381 作為從庫加入 101的6381
redis-trib.rb add-node --slave 192.168.1.102:6381   192.168.1.101:6381
 
redis-trib.rb add-node --slave 192.168.1.103:6382   192.168.1.102:6382
redis-trib.rb add-node --slave 192.168.1.101:6383   192.168.1.103:6383
 
檢測
redis-trib.rb check 192.168.1.101:6381
redis-trib.rb check 192.168.1.102:6382
redis-trib.rb check 192.168.1.103:6383

==========================redis cluster常見的幾個問題======================

1)問題一
由於redis clster叢集節點當機(或節點的redis服務重啟),導致了部分slot資料分片丟失;在用check檢查叢集執行狀態時,遇到錯誤;
[root@slave2 redis]# redis-trib.rb check 192.168.1.100:7000
........
[ERR] Not all 16384 slots are covered by nodes.
    
原因分析:
這個往往是由於主node移除了,但是並沒有移除node上面的slot,從而導致了slot總數沒有達到16384,其實也就是slots分佈不正確。
所以在刪除節點的時候一定要注意刪除的是否是Master主節點。
    
解決辦法:
官方是推薦使用redis-trib.rb fix 來修復叢集。通過cluster nodes看到7001這個節點被幹掉了。可以按照下面操作進行修復
[root@slave2 redis]# redis-trib.rb fix 192.168.1.100:7000
    
修復完成後再用check命令檢查下是否正確(檢視別的節點)
[root@slave2 redis]# redis-trib.rb check 192.168.1.101:7002
    
只要輸入任意叢集中節點即可,會自動檢查所有相關節點。
可以檢視相應的輸出看下是否是每個Master都有了slots。
    
如果分佈不均勻那可以使用下面的方式重新分配slot:
[root@slave2 redis]# redis-trib.rb reshard 192.168.1.100:7000
 
特別注意:
在部分節點重啟後重新回到叢集中的過程期間,在check叢集狀態的時候會出現"[ERR] Not all 16384 slots are covered by nodes."這個報錯,
需要稍微等待一會,等重啟節點完全回到叢集中後,這個報錯就會消失!
======================================================
問題二:
在往redis cluster叢集環境中新增節點時遇到一個問題,提示新增的Node不為空:
[root@slave2 redis]# redis-trib.rb add-node --slave 192.168.1.103:7004  192.168.1.102:7002
.......
[ERR] Node 192.168.1.103:7004 is not empty. Either the nodealready knows other nodes (check with CLUSTER NODES) or
contains some key in database 0.
    
解決辦法:(如果redis cluster所有節點同時斷電同時當機, 則節點重啟後, 只能重新建立叢集, 之前的叢集資料全部丟失! 重新建立叢集前,各節點要如下操作)
1)將192.168.1.103節點機redis下的aof、rdb等本地備份檔案全部刪除
2)同時將新Node的叢集配置檔案刪除,也即是刪除redis.conf裡面cluster-config-file指定所在的檔案;
3)"redis-cli -c -h 192.168.1.103 -p 7004"登陸後,執行 "flushdb"命令進行清除操作
4)重啟reds服務
5)最後再次執行節點新增操作
    
=============================================================================================
溫馨提示:
-  叢集中只要有一組master-slave節點同時掛點,則叢集服務也會掛掉;待該組master和slave節點的redis恢復後,這部分slot槽的資料也會丟失。
-  叢集中1/2或master節點掛掉,則叢集服務也會掛掉;待這些master節點服務重啟後,會自動加入到叢集中,需等待一段時間,叢集恢復正常,資料不會丟失。
  
- 叢集中master節點關閉,需要等待一小段時間,它對應的slave節點就會變成master節點,叢集服務正常,資料會隨之到新的maser節點的slot。
- master節點掛掉後,重啟redis服務(一定要在原來的aof和nodes*.conf檔案路徑下啟動),則會自動加入到cluster叢集中,並會變成slave節點。
  
-  新新增的master節點的slot預設為0,master主節點如果沒有slots,存取資料就都不會被選中! 故要為新增加的master節點進行reshard重新分配slot。
-  slave從節點的slot為0,資料不會儲存在slave節點!只會儲存在master主節點中,master節點才有slot數值。

======================================================
注意:每一組的master-slave節點不能同時掛掉或短時間內先後掛掉,否則這部分slot內的資料就會丟失。
比如說一主一從,當master節點掛掉後,資料都儲存到slave節點內,稍過一會,slave節點就會被選舉為新的master節點。
老的master節點重啟後重新回到叢集中,並自動變為它原來的slave(現在是新的master)的slave節點,並自動同步資料。
這個時候新的master節點如果掛掉,則資料同樣會儲存到新的slave節點中,新的slave節點過一段時間同樣會被再次選舉為新的master,如此類推....
如果master節點和它的slave節點同時掛掉,或者在其中一個掛掉後還沒有來得及恢復到叢集中,另一個就掛掉,這種情況下,這部分slot槽的資料肯定就沒有了。
所以說,一般會重啟一個節點,待該節點恢復到叢集中後,再可以重啟它對應的slave或master節點。
 
redis作為純快取服務時,資料丟失,一般對業務是無感的,不影響業務,丟失後會再次寫入。但如果作為儲存服務(即作為儲存資料庫),資料丟失則對業務影響很大。
不過一般業務場景,儲存資料庫會用mysql、oracle或mongodb。

======================================================
redis cluster叢集節點重啟後,要想恢復叢集狀態,正確的做法是:
1)要在各個節點原來的appendonly.aof ,dump.rdb,nodes_*.conf 檔案所在路徑下重啟redis服務。這樣就能確保redis啟動後用到之前的資料檔案。
(可以使用find命令查詢這些檔案所在路徑,然後在這個路徑下啟動redis服務)
2)各個節點的redis服務正常啟動後,就可以直接檢視redis cluster狀態了,檢查叢集狀態是否恢復。
      
注意:
一定要在原來的資料檔案的路徑下啟動redis,如果啟動的路徑錯誤,則讀取的資料檔案就不是之前的了,這樣叢集就很難恢復了。這個時候就需要刪除之前的資料檔案,
重新建立叢集了。(或者直接在/data/redis-4.0.6/redis-cluster/700*目錄下的redis.conf檔案裡的cluster-config-file指定檔案的絕對路徑)
   
叢集節點的redis服務重啟後,check叢集狀態,如有下面告警資訊,處理如下:
[root@redis-node01 redis-cluster]# /data/redis-4.0.6/src/redis-trib.rb check 192.168.1.100:7000
...........
...........
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
[WARNING] Node 192.168.1.100:7000 has slots in importing state (5798,11479).
[WARNING] Node 192.168.1.100:7001 has slots in importing state (1734,5798).
[WARNING] Node 192.168.1.101:7002 has slots in importing state (11479).
[WARNING] The following slots are open: 5798,11479,1734
>>> Check slots coverage...
[OK] All 16384 slots covered.
   
解決辦法:
一定要登入到告警資訊中的節點和對應的埠上進行操作。
執行"cluster setslot <slot> stable"命令,表示取消對槽slot 的匯入( import)或者遷移( migrate)。
執行後,這部分slot槽的資料就沒了。
[root@redis-node01 redis-cluster]# /data/redis-4.0.6/src/redis-cli -h 192.168.1.100 -c -p 7000
192.168.1.100:7000> cluster setslot 5798 stable
OK
192.168.1.100:7000> cluster setslot 11479 stable
OK
   
[root@redis-node01 redis-cluster]# /data/redis-4.0.6/src/redis-cli -h 192.168.1.100 -c -p 7001
192.168.1.100:7001> cluster setslot 1734 stable
OK
192.168.1.100:7001> cluster setslot 5798 stable
OK
   
[root@redis-node01 redis-cluster]# /data/redis-4.0.6/src/redis-cli -h 192.168.1.101 -c -p 7002
192.168.1.101:7002> cluster setslot 11479 stable
OK
   
再次檢查redis cluster叢集狀態,就會發現一切正常了!
[root@redis-node01 redis-cluster]# /data/redis-4.0.6/src/redis-trib.rb check 192.168.1.100:7000
>>> Performing Cluster Check (using node 192.168.1.100:7000)
M: 39737de1c48fdbaec304f0d11294286593553365 192.168.1.100:7000
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
S: 61a0cc84069ced156b6e1459bb71cab225182385 192.168.1.101:7003
   slots: (0 slots) slave
   replicates 39737de1c48fdbaec304f0d11294286593553365
S: 75de8c46eda03aee1afdd39de3ffd39cc42a5eec 172.16.60.209:7005
   slots: (0 slots) slave
   replicates 70a24c750995e2f316ee15320acb73441254a7aa
M: 70a24c750995e2f316ee15320acb73441254a7aa 192.168.1.101:7002
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
S: 5272bd14768e3e32e165284c272525a7da47b47e 192.168.1.100:7001
   slots: (0 slots) slave
   replicates c1b71d52b0d804f499c9166c0c1f4e3c35077ee9
M: c1b71d52b0d804f499c9166c0c1f4e3c35077ee9 172.16.60.209:7004
   slots:10923-16383 (5461 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.

相關文章