1. 程式人生 > >Redis實戰總結-Redis的高可用性

Redis實戰總結-Redis的高可用性

在之前的部落格《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問題的(分割槽),兩種不重複,可以混合使用。

下面詳解這兩種叢集,並給出具體的演示示例。

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的恢復(主觀下線)

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節點已全部停止"
  • 建立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去中心特性,訪問叢集中的任一節點,均可直接操作叢集。

  • 主節點宕機測試

  • 從節點宕機

  • *