您好,登錄后才能下訂單哦!
Redis 集群是一個分布式(distributed)、容錯(fault-tolerant)的 Redis 實現,集群可以使用的功能是普通單機 Redis 所能使用的功能的一個子集(subset)。
Redis 集群中不存在中心(central)節點或者代理(proxy)節點,集群的其中一個主要設計目標是達到線性可擴展性(linear scalability)。
Redis 集群為了保證一致性(consistency)而犧牲了一部分容錯性:系統會在保證對網絡斷線(net split)和節點失效(node failure)具有有限(limited)抵抗力的前提下,盡可能地保持數據的一致性。
請注意,本教程使用于Redis3.0(包括3.0)以上版本
如果你計劃部署集群,那么我們建議你從閱讀這個文檔開始。
Redis集群介紹
Redis 集群是一個提供在多個Redis間節點間共享數據的程序集。
Redis集群并不支持處理多個keys的命令,因為這需要在不同的節點間移動數據,從而達不到像Redis那樣的性能,在高負載的情況下可能會導致不可預料的錯誤.
Redis 集群通過分區來提供一定程度的可用性,在實際環境中當某個節點宕機或者不可達的情況下繼續處理命令. Redis 集群的優勢:
自動分割數據到不同的節點上。
整個集群的部分節點失敗或者不可達的情況下能夠繼續處理命令。
Redis 集群的數據分片
Redis 集群沒有使用一致性hash, 而是引入了 哈希槽的概念.
Redis 集群有16384個哈希槽,每個key通過CRC16校驗后對16384取模來決定放置哪個槽.集群的每個節點負責一部分hash槽,舉個例子,比如當前集群有3個節點,那么:
節點 A 包含 0 到 5500號哈希槽.
節點 B 包含5501 到 11000 號哈希槽.
節點 C 包含11001 到 16384號哈希槽.
這種結構很容易添加或者刪除節點. 比如如果我想新添加個節點D, 我需要從節點 A, B, C中得部分槽到D上. 如果我像移除節點A,需要將A中得槽移到B和C節點上,然后將沒有任何槽的A節點從集群中移除即可. 由于從一個節點將哈希槽移動到另一個節點并不會停止服務,所以無論添加刪除或者改變某個節點的哈希槽的數量都不會造成集群不可用的狀態.
Redis 集群的主從復制模型
為了使在部分節點失敗或者大部分節點無法通信的情況下集群仍然可用,所以集群使用了主從復制模型,每個節點都會有N-1個復制品.
在我們例子中具有A,B,C三個節點的集群,在沒有復制模型的情況下,如果節點B失敗了,那么整個集群就會以為缺少5501-11000這個范圍的槽而不可用.
然而如果在集群創建的時候(或者過一段時間)我們為每個節點添加一個從節點A1,B1,C1,那么整個集群便有三個master節點和三個slave節點組成,這樣在節點B失敗后,集群便會選舉B1為新的主節點繼續服務,整個集群便不會因為槽找不到而不可用了
不過當B和B1 都失敗后,集群是不可用的.
Redis 一致性保證
Redis 并不能保證數據的強一致性. 這意味這在實際中集群在特定的條件下可能會丟失寫操作.
第一個原因是因為集群是用了異步復制. 寫操作過程:
客戶端向主節點B寫入一條命令.
主節點B向客戶端回復命令狀態.
主節點將寫操作復制給他得從節點 B1, B2 和 B3.
主節點對命令的復制工作發生在返回命令回復之后, 因為如果每次處理命令請求都需要等待復制操作完成的話, 那么主節點處理命令請求的速度將極大地降低 —— 我們必須在性能和一致性之間做出權衡。 注意:Redis 集群可能會在將來提供同步寫的方法。 Redis 集群另外一種可能會丟失命令的情況是集群出現了網絡分區, 并且一個客戶端與至少包括一個主節點在內的少數實例被孤立。
舉個例子 假設集群包含 A 、 B 、 C 、 A1 、 B1 、 C1 六個節點, 其中 A 、B 、C 為主節點, A1 、B1 、C1 為A,B,C的從節點, 還有一個客戶端 Z1 假設集群中發生網絡分區,那么集群可能會分為兩方,大部分的一方包含節點 A 、C 、A1 、B1 和 C1 ,小部分的一方則包含節點 B 和客戶端 Z1 .
Z1仍然能夠向主節點B中寫入, 如果網絡分區發生時間較短,那么集群將會繼續正常運作,如果分區的時間足夠讓大部分的一方將B1選舉為新的master,那么Z1寫入B中得數據便丟失了.
注意, 在網絡分裂出現期間, 客戶端 Z1 可以向主節點 B 發送寫命令的最大時間是有限制的, 這一時間限制稱為節點超時時間(node timeout), 是 Redis 集群的一個重要的配置選項:
搭建并使用Redis集群
搭建集群的第一件事情我們需要一些運行在 集群模式的Redis實例. 這意味這集群并不是由一些普通的Redis實例組成的,集群模式需要通過配置啟用,開啟集群模式后的Redis實例便可以使用集群特有的命令和特性了.
目前redis支持的cluster特性
1):節點自動發現
2):slave->master 選舉,集群容錯
3):Hot resharding:在線分片
4):進群管理:cluster xxx
5):基于配置(nodes-port.conf)的集群管理
6):ASK 轉向/MOVED 轉向機制.
1)redis-cluster架構圖
架構細節:
(1)所有的redis節點彼此互聯(PING-PONG機制),內部使用二進制協議優化傳輸速度和帶寬.
(2)節點的fail是通過集群中超過半數的節點檢測失效時才生效.
(3)客戶端與redis節點直連,不需要中間proxy層.客戶端不需要連接集群所有節點,連接集群中任何一個可用節點即可
(4)redis-cluster把所有的物理節點映射到[0-16383]slot上,cluster 負責維護node<->slot<->value2) redis-cluster選舉:容錯
(1)領著選舉過程是集群中所有master參與,如果半數以上master節點與master節點通信超過(cluster- node-timeout),認為當前master節點掛掉.
(2):什么時候整個集群不可用(cluster_state:fail),當集群不可用時,所有對集群的操作做都不可用,收到 ((error) CLUSTERDOWN The cluster is down)錯誤
a:如果集群任意master掛掉,且當前master沒有slave.集群進入fail狀態,也可以理解成進群的slot映射 [0-16383]不完成時進入fail狀態.
b:如果進群超過半數以上master掛掉,無論是否有slave集群進入fail狀態.
一、環境
os:centos7 ip:192.168.19.132 redis:3.2.9 gem-redis:3.2.2
二、搭建集群
1、本機下載redis-3.2.9.tar.gz
[root@zookeeper ~]# cd /usr/local/src/ [root@zookeeper src]# wget http://download.redis.io/releases/redis-3.2.9.tar.gz
2、安裝
root@zookeeper ~]# yum -y install tcl-8.5* [root@zookeeper src]# tar zxf redis-3.2.9.tar.gz -C /usr/local/ [root@zookeeper src]# ln -s /usr/local/redis-3.2.9 /usr/local/redis [root@zookeeper src]# cd /usr/local/redis 第一種: [root@zookeeper redis]# make MALLOC=libc && make install [root@zookeeper redis]# make test(可選,等待時間長) ...... \o/ All tests passed without errors! Cleanup: may take some time... OK make[1]: Leaving directory `/usr/local/redis-3.2.9/src' 第二種make: make完成之后,進行install,默認安裝路徑為/usr/local/bin下,這里我們把他安裝目錄放到/usr/local/redis下,使用PREFIX指定目錄: [root@zookeeper redis]# make && make PREFIX=/usr/local/redis install
將redis可執行目錄添加到環境變量中,編輯~/.bash_profile添加redis環境變量:
[root@zookeeper ~]# vim ~/.bash_profile # .bash_profile # Get the aliases and functions if [ -f ~/.bashrc ]; then . ~/.bashrc fi # User specific environment and startup programs PATH=$PATH:$HOME/bin:/usr/local/redis/bin export PATH [root@zookeeper ~]# source ~/.bash_profile
3、創建文件夾
[root@zookeeper redis]# mkdir -p /data/cluster [root@zookeeper redis]# cd /data/cluster/ [root@zookeeper cluster]# mkdir 7000 7001 7002 7003 7004 7005
4、拷貝修改配置文件
[root@zookeeper cluster]# mkdir /var/log/redis/ [root@zookeeper cluster]# cp /usr/local/redis/redis.conf 7000/redis-7000.conf vim 7000/redis-7000.conf ...... bind 192.168.19.132 port 7000 daemonize yes cluster-enabled yes cluster-config-file nodes-7000.conf cluster-node-timeout 15000 pidfile /var/run/redis_7000.pid logfile "/var/log/redis/redis-7000.log" 改完之后將此配置文件cp到所有節點上,并且修改端口號和cluster-config-file項。 [root@zookeeper cluster]# cp 7000/redis-7000.conf 7001/redis-7001.conf [root@zookeeper cluster]# cp 7000/redis-7000.conf 7002/redis-7002.conf [root@zookeeper cluster]# cp 7000/redis-7000.conf 7003/redis-7003.conf [root@zookeeper cluster]# cp 7000/redis-7000.conf 7004/redis-7004.conf [root@zookeeper cluster]# cp 7000/redis-7000.conf 7005/redis-7005.conf ......(修改配置文件請參考redis-7000.conf) [root@zookeeper cluster]# vim 7001/redis-7001.conf [root@zookeeper cluster]# vim 7002/redis-7002.conf [root@zookeeper cluster]# vim 7003/redis-7003.conf [root@zookeeper cluster]# vim 7004/redis-7004.conf [root@zookeeper cluster]# vim 7005/redis-7005.conf
5、啟動6個實例
[root@zookeeper cluster]# redis-server 7000/redis-7000.conf [root@zookeeper cluster]# redis-server 7001/redis-7001.conf [root@zookeeper cluster]# redis-server 7002/redis-7002.conf [root@zookeeper cluster]# redis-server 7003/redis-7003.conf [root@zookeeper cluster]# redis-server 7004/redis-7004.conf [root@zookeeper cluster]# redis-server 7005/redis-7005.conf [root@zookeeper cluster]# 關閉命令:[root@zookeeper cluster]# redis-cli -p 端口號 shutdown
用redis-cli -c -h -p命令登錄
-c是以集群方式登錄;
-h后跟主機號 ;
-p后跟端口號。
綁定了127.0.0.1則可以省略-h參數。不加-c則客戶端不自動切換。
例如:客戶端登錄7000端口的,設置的數據應該存放在7001上則會報錯請轉到7001。而加上-c啟動則會自動切換到7001客戶端保存。
6、查看redis進程啟動狀態
[root@zookeeper cluster]# ps -ef| grep redis root 18839 1 0 22:58 ? 00:00:00 redis-server 192.168.19.132:7000 [cluster] root 18843 1 0 22:58 ? 00:00:00 redis-server 192.168.19.132:7001 [cluster] root 18847 1 0 22:58 ? 00:00:00 redis-server 192.168.19.132:7002 [cluster] root 18851 1 0 22:59 ? 00:00:00 redis-server 192.168.19.132:7003 [cluster] root 18855 1 0 22:59 ? 00:00:00 redis-server 192.168.19.132:7004 [cluster] root 18859 1 0 22:59 ? 00:00:00 redis-server 192.168.19.132:7005 [cluster] root 18865 2891 0 22:59 pts/1 00:00:00 grep --color=auto redis [root@zookeeper cluster]#
7、部署集群
7.1、安裝ruby依賴,返回安裝軟件目錄
root@zookeeper src]# yum install ruby rubygems -y [root@zookeeper src]# wget https://rubygems.org/downloads/redis-3.2.2.gem 安裝集群管理工具 Redis作者應該是個Ruby愛好者,Ruby客戶端就是他開發的。這次集群的管理功能沒有嵌入到Redis代碼中,于是作者又順手寫了個叫做redis-trib的管理腳本。redis-trib依賴Ruby和RubyGems,以及redis擴展。可以先用which命令查看是否已安裝ruby和rubygems,用gem list –local查看本地是否已安裝redis擴展。 [root@zookeeper src]# gem install -l redis-3.2.2.gem Successfully installed redis-3.2.2 Parsing documentation for redis-3.2.2 Installing ri documentation for redis-3.2.2 1 gem installed
7.2、將集群管理程序復制到/usr/local/bin/
[root@zookeeper src]# cp /usr/local/redis/src/redis-trib.rb /usr/local/bin/redis-trib
可以看到redis-trib.rb具有以下功能:
1、create:創建集群
2、check:檢查集群
3、info:查看集群信息
4、fix:修復集群
5、reshard:在線遷移slot
6、rebalance:平衡集群節點slot數量
7、add-node:將新節點加入集群
8、del-node:從集群中刪除節點
9、set-timeout:設置集群節點間心跳連接的超時時間
10、call:在集群全部節點上執行命令
11、import:將外部redis數據導入集群
8、創建集群
[root@zookeeper cluster]# redis-trib create --replicas 1 192.168.19.132:7000 192.168.19.132:7001 192.168.19.132:7002 192.168.19.132:7003 192.168.19.132:7004 192.168.19.132:7005 >>> Creating cluster >>> Performing hash slots allocation on 7 nodes... Using 3 masters: 192.168.19.132:7000 192.168.19.132:7001 192.168.19.132:7002 Adding replica 192.168.19.132:7003 to 192.168.19.132:7000 Adding replica 192.168.19.132:7004 to 192.168.19.132:7001 Adding replica 192.168.19.132:7005 to 192.168.19.132:7002 M: 3546a9930ce08543731c4d49ae8609d75b0b8193 192.168.19.132:7000 slots:0-16383 (16384 slots) master M: 1dd532b0f41b98574b6cd355fa58a2773c9da8fe 192.168.19.132:7001 slots:5461-10922 (5462 slots) master M: 2900e315a4a01df8609eafe0f9fd2a1d779ecc69 192.168.19.132:7002 slots:10923-16383 (5461 slots) master S: 71c8cea8e3e9c913eb7c09bd3f95c03985938eca 192.168.19.132:7003 replicates 3546a9930ce08543731c4d49ae8609d75b0b8193 S: 046a02ea253d8912b87c13e98b28f81e6c54c0b1 192.168.19.132:7004 replicates 1dd532b0f41b98574b6cd355fa58a2773c9da8fe S: 8a666ed58930673b7dfc6d005c2a937751350f77 192.168.19.132:7005 replicates 2900e315a4a01df8609eafe0f9fd2a1d779ecc69 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.19.132:7000) M: 3da69162cde5884f21cec07f6f812ffbdda0cfc4 192.168.19.132:7000 slots:0-10922 (10923 slots) master 3 additional replica(s) M: d30be1d1232e55f3cc69d8d11e9eb9a870160ac1 192.168.19.132:7001 slots:10923-16383 (5461 slots) master 1 additional replica(s) S: 6bd6589a69ce37da5335ffd10b042ce0b02e3247 192.168.19.132:7004 slots: (0 slots) slave replicates d30be1d1232e55f3cc69d8d11e9eb9a870160ac1 S: 12d7db519133b96bac51b79204f69eabdfe75627 192.168.19.132:7002 slots: (0 slots) slave replicates 3da69162cde5884f21cec07f6f812ffbdda0cfc4 S: 8a9d6189b42bef127ab388e221d8225938c3f038 192.168.19.132:7003 slots: (0 slots) slave replicates 3da69162cde5884f21cec07f6f812ffbdda0cfc4 S: 2cfb927fc17988be6fee6b5eb1249e2789a76f82 192.168.19.132:7005 slots: (0 slots) slave replicates 3da69162cde5884f21cec07f6f812ffbdda0cfc4 [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
當我們同意這份計劃之后輸入yes,,Can I set the above configuration? (type 'yes' to accept): yes,開始執行節點握手和槽分配操作。
最后輸出報告說明,16384個槽全部被分配,集群創建成功。這里需要注意給redis-trib.rb的節點地址必須是不包含任何槽/數據的節點,否則會拒絕創建集群。
--replicascas參數制定集群中每個主節點配置幾個從節點,這里設置為1.節點列表順序用于確定主從角色,先主節點之后是從節點。
創建流程如下:
1、首先為每個節點創建ClusterNode對象,包括連接每個節點。檢查每個節點是否為獨立且db為空的節點。執行load_info方法導入節點信息。
2、檢查傳入的master節點數量是否大于等于3個。只有大于3個節點才能組成集群。
3、計算每個master需要分配的slot數量,以及給master分配slave。分配的算法大致如下:
先把節點按照host分類,這樣保證master節點能分配到更多的主機中。
不停遍歷遍歷host列表,從每個host列表中彈出一個節點,放入interleaved數組。直到所有的節點都彈出為止。
master節點列表就是interleaved前面的master數量的節點列表。保存在masters數組。
計算每個master節點負責的slot數量,保存在slots_per_node對象,用slot總數除以master數量取整即可。
遍歷masters數組,每個master分配slots_per_node個slot,最后一個master,分配到16384個slot為止。
接下來為master分配slave,分配算法會盡量保證master和slave節點不在同一臺主機上。對于分配完指定slave數量的節點,還有多余的節點,也會為這些節點尋找master。分配算法會遍歷兩次masters數組。
第一次遍歷masters數組,在余下的節點列表找到replicas數量個slave。每個slave為第一個和master節點host不一樣的節點,如果沒有不一樣的節點,則直接取出余下列表的第一個節點。
第二次遍歷是在對于節點數除以replicas不為整數,則會多余一部分節點。遍歷的方式跟第一次一樣,只是第一次會一次性給master分配replicas數量個slave,而第二次遍歷只分配一個,直到余下的節點被全部分配出去。
4、打印出分配信息,并提示用戶輸入“yes”確認是否按照打印出來的分配方式創建集群。
5、輸入“yes”后,會執行flush_nodes_config操作,該操作執行前面的分配結果,給master分配slot,讓slave復制master,對于還沒有握手(cluster meet)的節點,slave復制操作無法完成,不過沒關系,flush_nodes_config操作出現異常會很快返回,后續握手后會再次執行flush_nodes_config。
6、給每個節點分配epoch,遍歷節點,每個節點分配的epoch比之前節點大1。
7、節點間開始相互握手,握手的方式為節點列表的其他節點跟第一個節點握手。
8、然后每隔1秒檢查一次各個節點是否已經消息同步完成,使用ClusterNode的get_config_signature方法,檢查的算法為獲取每個節點cluster nodes信息,排序每個節點,組裝成node_id1:slots|node_id2:slot2|...的字符串。如果每個節點獲得字符串都相同,即認為握手成功。
9、此后會再執行一次flush_nodes_config,這次主要是為了完成slave復制操作。
10、最后再執行check_cluster,全面檢查一次集群狀態。包括和前面握手時檢查一樣的方式再檢查一遍。確認沒有遷移的節點。確認所有的slot都被分配出去了。
11、至此完成了整個創建流程,返回[OK] All 16384 slots covered.。
9、集群完整性檢查
[root@zookeeper ~]# redis-trib check 192.168.19.132:7000 >>> Performing Cluster Check (using node 192.168.19.132:7000) M: 8a628ee2e98c70a404be020cba3dfc1172a38335 192.168.19.132:7000 slots:0-5460 (5461 slots) master 1 additional replica(s) S: 154e2f4f3fad75a564f9fe2efcde7820284116c6 192.168.19.132:7003 slots: (0 slots) slave replicates 8a628ee2e98c70a404be020cba3dfc1172a38335 S: f2707a3052d3dc91358b73b4786e4c8e20662a79 192.168.19.132:7004 slots: (0 slots) slave replicates 0e4d1ee05b090c45ce979bc9e8ad4c027d5332ef M: 0e4d1ee05b090c45ce979bc9e8ad4c027d5332ef 192.168.19.132:7001 slots:5461-10922 (5462 slots) master 1 additional replica(s) M: 08d3663dc9e0f5f02e2bff07640d67e406211e49 192.168.19.132:7002 slots:10923-16383 (5461 slots) master 1 additional replica(s) S: a44237119e6b2129e457d2f48a584b94b1b815f5 192.168.19.132:7005 slots: (0 slots) slave replicates 08d3663dc9e0f5f02e2bff07640d67e406211e49 [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered. [root@zookeeper ~]# redis-trib check 192.168.19.132:7004 >>> Performing Cluster Check (using node 192.168.19.132:7004) S: f2707a3052d3dc91358b73b4786e4c8e20662a79 192.168.19.132:7004 slots: (0 slots) slave replicates 0e4d1ee05b090c45ce979bc9e8ad4c027d5332ef M: 0e4d1ee05b090c45ce979bc9e8ad4c027d5332ef 192.168.19.132:7001 slots:5461-10922 (5462 slots) master 1 additional replica(s) S: 154e2f4f3fad75a564f9fe2efcde7820284116c6 192.168.19.132:7003 slots: (0 slots) slave replicates 8a628ee2e98c70a404be020cba3dfc1172a38335 M: 08d3663dc9e0f5f02e2bff07640d67e406211e49 192.168.19.132:7002 slots:10923-16383 (5461 slots) master 1 additional replica(s) M: 8a628ee2e98c70a404be020cba3dfc1172a38335 192.168.19.132:7000 slots:0-5460 (5461 slots) master 1 additional replica(s) S: a44237119e6b2129e457d2f48a584b94b1b815f5 192.168.19.132:7005 slots: (0 slots) slave replicates 08d3663dc9e0f5f02e2bff07640d67e406211e49 [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
10 測試
[root@zookeeper ~]# redis-cli -h 192.168.19.132 -p 7000 192.168.19.132: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:6 cluster_size:3 cluster_current_epoch:6 cluster_my_epoch:1 cluster_stats_messages_sent:414 cluster_stats_messages_received:414 3192.168.19.132:7000> CLUSTER NODES 154e2f4f3fad75a564f9fe2efcde7820284116c6 192.168.19.132:7003 slave 8a628ee2e98c70a404be020cba3dfc1172a38335 0 1496720263710 4 connected f2707a3052d3dc91358b73b4786e4c8e20662a79 192.168.19.132:7004 slave 0e4d1ee05b090c45ce979bc9e8ad4c027d5332ef 0 1496720264715 5 connected 0e4d1ee05b090c45ce979bc9e8ad4c027d5332ef 192.168.19.132:7001 master - 0 1496720262702 2 connected 5461-10922 08d3663dc9e0f5f02e2bff07640d67e406211e49 192.168.19.132:7002 master - 0 1496720265722 3 connected 10923-16383 a44237119e6b2129e457d2f48a584b94b1b815f5 192.168.19.132:7005 slave 08d3663dc9e0f5f02e2bff07640d67e406211e49 0 1496720266730 6 connected 8a628ee2e98c70a404be020cba3dfc1172a38335 192.168.19.132:7000 myself,master - 0 0 1 connected 0-5460
當前集群狀態是OK,集群進入在線狀態。cluster nodes可以看到節點和槽的分配關系,目前還有三個及誒按沒有使用,作為一個完整的集群,每個負責處理槽的節點都應該具有從節點,保證當它出現故障時可以自動進行故障轉移。集群模式下,Redis節點角色分為主節點和從節點。首次啟動的節點和被分配槽的節點都是主節點,從節點負責復制主節點槽信息和相關數據。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。