在之前的博客《Redis實戰總結-配置、持久化、復制》給出了一種Redis主從復制機制,簡單地實現了Redis高可用。然后,如果Master服務器宕機,會導致整個Redis癱瘓,這種方式的高可用性較低。正常會采用多台Redis服務器構成一個集群,即使某台,或者某幾台Redis宕機,Redis集群仍能正常運行,從而提高其高可用性。
在Redis中,主要存在兩種方式實現Redis集群機制:
-
Redis Sentinel集群機制:在Redis2.X版本,往往都是通過這種方式實現Redis的高可用。redis-sentinel是在master-slave機制上加入監控機制哨兵Sentinel實現的。
-
Redis Cluster集群機制:在Redis3.0版本后推出了redis-cluster集群機制。redis-cluster集群中各個節點之間是對等的,即master-master模式。
**注意:**Redis Sentinel集群是解決HA問題的(主從同步),Redis Cluster集群是解決sharding問題的(分區),兩種不重復,可以混合使用。
- Sharding機制:http://blog.csdn.net/basycia/article/details/52013098
- HA機制:https://baike.baidu.com/item/%E9%AB%98%E5%8F%AF%E7%94%A8%E6%80%A7(HA)/2355576
下面詳解這兩種集群,並給出具體的演示示例。
1. Redis Sentinel集群機制
Redis-Sentinel是在master-slave機制上加入監控機制哨兵Sentinel實現的。Sentinel主要功能就是為Redis Master-Slave集群提供:
- 監控(Monitoring): Sentinel 會不斷地檢查你的主服務器和從服務器是否運作正常。
- 提醒(Notification): 當被監控的某個 Redis 服務器出現問題時, Sentinel 可以通過 API 向管理員或者其他應用程序發送通知。
- 自動故障遷移(Automatic failover): 當一個主服務器不能正常工作時, Sentinel 會開始一次自動故障遷移操作, 它會將失效主服務器的其中一個從服務器升級為新的主服務器, 並讓失效主服務器的其他從服務器改為復制新的主服務器; 當客戶端試圖連接失效的主服務器時, 集群也會向客戶端返回新主服務器的地址, 使得集群可以使用新主服務器代替失效服務器。
在Sentinel集群中,一個最小的Master-Slave單元包含一個master和一個slave服務器。當master失效后,sentinel自動將slave提升為master,從而可以減少管理員的人工切換slave的操作過程。
1.1 Redis-Sentinel集群架構圖
1.2 各個機器配置
部署在本地機器上,保證各個端口號不一樣,具體配置如下
-
Redis服務器:
- master:127.0.0.1:6379
- slave01:127.0.0.1:6389
- slave02:127.0.0.1:6399
-
Sentinel服務器
- sentinel01:127.0.0.1:26379
- sentinel02:127.0.0.1:26389
- sentinel03:127.0.0.1:26399
1.3 redis.conf和sentinel.conf配置
-
redis.conf
- master特殊配置如下:
# 后台線程啟動 daemonize yes # 監聽端口號 port 6379 # 訪問驗證密碼 requirepass "123456"
-
- slave特殊配置如下:
# 后台線程啟動 daemonize yes # 監聽端口號,如果為slave02,端口號為6399 port 6389 # 主節點訪問密碼 masterauth "123456" # 訪問驗證密碼 requirepass "123456" # 主節點服務器IP和端口號 slaveof 127.0.0.1 6379
-
sentinel.conf
# 后台線程啟動 daemonize yes # 監聽端口號,如果為sentinel02,則端口號為26389,如果為sentinel01,則端口號為26399 port 26379 #1表示在sentinel集群中只要有兩個節點檢測到redis主節點出故障就進行切換 sentinel monitor mymaster 127.0.0.1 6379 1 # master節點密碼驗證 sentinel auth-pass mymaster 123456 #如果3秒內mymaster無響應,則認為mymaster宕機了 sentinel down-after-milliseconds mymaster 3000 # 選項指定了在執行故障轉移時, 最多可以有多少個從服務器同時對新的主服務器進行同步, 這個數字越小, 完成故障轉移所需的時間就越長 sentinel parallel-syncs mymaster 1 #如果10秒后,mysater仍沒活過來,則啟動failover sentinel failover-timeout mymaster 10000
注意:
- 1.如果上述涉及的所有配置均放置在同一目錄下,需保證各配置名稱不同;
- 2.在配置中,不同實例的日志輸出、快照文件要求名稱不能一樣,具體可自行配置;
- 3.一定要保證”sentinel myid”不相同,否則無法進行故障轉移
1.4 啟動集群及啟動后結果詳情展示
-
各Redis節點啟動:
redis-server redis_****.conf
-
各Sentinel節點啟動
redis-sentinel sentinel_*****.conf
- Redis Master節點詳情展示
-
Redis Slave節點效果截圖展示
各個Sentinel節點詳情展示
1.5 高可用性場景測試
- Master宕機
- sentinel使用failover機制重新選舉出master
- Master恢復
- master節點恢復后,由Master變成slave
- Slave宕機
- 哨兵發現6399已經宕機,等待6399的恢復(主觀下線)
- Slave重啟6399節點
如果想詳細了解sentinel機制的話,可以參考博客:
http://shift-alt-ctrl.iteye.com/blog/1884370
2. Redis Cluster集群機制
2.1 Redis-cluster介紹
Redis-cluster是一種服務器Sharding技術,Redis3.0以后版本正式提供支持。
Redis-cluster沒有使用一致性hash,而是引入了哈希槽的概念。Redis-cluster中有16384個哈希槽,每個key通過CRC16校驗后對16384取模來決定放置哪個槽。Cluster中的每個節點負責一部分hash槽(hash slot),比如集群中存在三個節點,則可能存在的一種分配如下:
- 節點A包含0到5500號哈希槽;
- 節點B包含5501到11000號哈希槽;
- 節點C包含11001 到 16384號哈希槽。
這種集群架構很容易擴展,如果擴充一個節點D,只需要將A、B、C節點中的部分槽放置在D上;如果想移除節點A,只需要將A的slot轉移到B和C節點上。由於將哈希槽從一個節點移動到另一個節點不需要停止服務,只需要通過命令直接再分配,因而上述拓展不會造成集群不可用。目前這種方式還是一種半自動的方式,需要人工介入。
2.2 Redis-Cluster主從復制
在Redis-Cluster中,如果某個節點宕機或者處在不可用狀態時,那它負責的Hash槽也將失效,導致整個集群不可用。因而為了提供高可用性,正常會將每個節點配置成主從式結構,即一個master節點,掛在多個slave節點。如果Master節點失效時,集群便會選取一個slave節點作為master,繼續提供服務,從而不會導致整個集群不可用。
2.3 Redis-Cluster集群模擬
2.3.1 Redis-Cluster集群准備
- 集群部署圖
-
集群由三個節點組成,每個節點均為主從式架構。因而共需要創建6個Redis實例,分配如下:
- Redis01:127.0.0.1:7000
- Redis02:127.0.0.1:7001
- Redis03:127.0.0.1:7002
- Redis04:127.0.0.1:7003
- Redis05:127.0.0.1:7004
- Redis06:127.0.0.1:7005
對於每個實例的redis_700*.conf配置如下:
# 監聽端口號 port 700* # 開啟集群 cluster-enabled yes # 修改集群加載配置文件,不需要手動創建,啟動后默認生成,並且需要時自動更新 cluster-config-file /Users/guweiyu/develop/redis/redis-cluster/workpid/nodes-7000.conf # 集群中的節點能夠失聯的最大時間,超過這個時間,該節點就會被認為故障 cluster-node-timeout 15000 # 默認為“no”,表示部分Key所在的節點不可用時,集群仍然為可達節點提供服務;如果為“yes”,表示部分key所在的節點不可用時,則整個集群停止服務。注意:實際使用中要修改為"yes" cluster-require-full-coverage no
-
安裝ruby,如果為Mac OS系統,直接執行即可:
brew install ruby
2.3.2 集群啟動
-
啟動所有Redis實例,可以編寫一個啟動和停止所有redis實例的腳本(start.sh,stop.sh)
redis-server redis_7000.conf redis-server redis_7001.conf redis-server redis_7002.conf redis-server redis_7003.conf redis-server redis_7004.conf redis-server redis_7005.conf ps -ef | grep redis-server echo "redis 7000-7005全部啟動完成"
-
redis-cli -p 7000 shutdown redis-cli -p 7001 shutdown redis-cli -p 7002 shutdown redis-cli -p 7003 shutdown redis-cli -p 7004 shutdown redis-cli -p 7005 shutdown ps -ef | grep redis-server echo "redis-server 7000-7005節點已全部停止"
1創建redis-cluster
Redis中創建集群是通過redis-trib.rb命令實現的,redis-trib.rb位於Redis源碼的src目錄下,可將其直接拷貝到當前目錄下。
運行命令
./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
如果出現如下錯誤:
/System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- redis (LoadError) from /System/Library/Frameworks/Ruby.framework/Versions/2.3/usr/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require' from ./redis-trib.rb:25:in `<main>'
這是由於沒有安裝redis的第三方接口導致的。因此需要給Ruby安裝client包,如下(必須加上sudo執行,否則會執行失敗):
sudo gem install redis
再執行創建集群命令,結果如下:
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes... Using 3 masters: 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 Adding replica 127.0.0.1:7004 to 127.0.0.1:7000 Adding replica 127.0.0.1:7005 to 127.0.0.1:7001 Adding replica 127.0.0.1:7003 to 127.0.0.1:7002 >>> Trying to optimize slaves allocation for anti-affinity [WARNING] Some slaves are in the same host as their master M: aab0162a039d2f224322afe6caf2e153230f2d82 127.0.0.1:7000 slots:0-5460 (5461 slots) master M: 058204226f52757925a606b9697a8e39756bfdff 127.0.0.1:7001 slots:5461-10922 (5462 slots) master M: 857075aef280cf35cd369ebc30738cd31c05e479 127.0.0.1:7002 slots:10923-16383 (5461 slots) master S: 7dac141fa9510315905f505be52bba0208c391ab 127.0.0.1:7003 replicates aab0162a039d2f224322afe6caf2e153230f2d82 S: 65a2bc432e5930e97f0fd172eb838af9f07229b6 127.0.0.1:7004 replicates 058204226f52757925a606b9697a8e39756bfdff S: 3d2a665d2e2eb28acb0a187c1a0b4bbce9ce87d2 127.0.0.1:7005 replicates 857075aef280cf35cd369ebc30738cd31c05e479 Can I set the above configuration? (type 'yes' to accept): yes >>> Nodes configuration updated >>> Assign a different config epoch to each node >>> Sending CLUSTER MEET messages to join the cluster Waiting for the cluster to join... >>> Performing Cluster Check (using node 127.0.0.1:7000) M: aab0162a039d2f224322afe6caf2e153230f2d82 127.0.0.1:7000 slots:0-5460 (5461 slots) master 1 additional replica(s) S: 3d2a665d2e2eb28acb0a187c1a0b4bbce9ce87d2 127.0.0.1:7005 slots: (0 slots) slave replicates 857075aef280cf35cd369ebc30738cd31c05e479 S: 65a2bc432e5930e97f0fd172eb838af9f07229b6 127.0.0.1:7004 slots: (0 slots) slave replicates 058204226f52757925a606b9697a8e39756bfdff S: 7dac141fa9510315905f505be52bba0208c391ab 127.0.0.1:7003 slots: (0 slots) slave replicates aab0162a039d2f224322afe6caf2e153230f2d82 M: 857075aef280cf35cd369ebc30738cd31c05e479 127.0.0.1:7002 slots:10923-16383 (5461 slots) master 1 additional replica(s) M: 058204226f52757925a606b9697a8e39756bfdff 127.0.0.1:7001 slots:5461-10922 (5462 slots) master 1 additional replica(s) [OK] All nodes agree about slots configuration. >>> Check for open slots... >>> Check slots coverage... [OK] All 16384 slots covered.
創建成功,16384個Hash槽分配完成,所有節點(Master和slave節點)均已加入到集群中。三個Master節點分配的Hash槽及從節點如下:
-
Master01:127.0.0.1:7000
M: aab0162a039d2f224322afe6caf2e153230f2d82 slots:0-5460 (5461 slots) master 127.0.0.1:7004 to 127.0.0.1:7000
-
Master02:127.0.0.1:7001
-
M: 058204226f52757925a606b9697a8e39756bfdff slots:5461-10922 (5462 slots) master 127.0.0.1:7005 to 127.0.0.1:7001
Master03:127.0.0.1:7002
-
M: 857075aef280cf35cd369ebc30738cd31c05e479 slots:10923-16383 (5461 slots) master 127.0.0.1:7003 to 127.0.0.1:7002
2.3.3 集群測試
- 測試集群存取值
客戶端命令redis-cli連接集群需要帶上”-c”, 比如redis-cli -c -p 端口號
127.0.0.1:7000> set test1 guweiyu OK 127.0.0.1:7000> set name guweiyu -> Redirected to slot [5798] located at 127.0.0.1:7001 OK 127.0.0.1:7001> get name "guweiyu" 127.0.0.1:7001> get test1 -> Redirected to slot [4768] located at 127.0.0.1:7000 "guweiyu" 127.0.0.1:7000>
測試發現”set test1 guweiyu”,直接返回OK,說明該值就是存儲在7000上,執行“set name guweiyu”發生了Redirected到7001上,獲取的時候,同樣出現上述情況。這個是Redis Cluster去中心特性,訪問集群中的任一節點,均可直接操作集群。
-
主節點宕機測試
-
從節點宕機