一般來說,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.