天天看點

redis叢集 + 哨兵 + zookeeper_redis專題系列16 -- redis 叢集模式之哨兵模式叢集架構叢集部署簡單示例哨兵叢集部署注意事項基本原理經驗之談常用配置參數說明常用指令Java代碼使用哨兵模式

雖然redis為我們提供了主從模式,但master一旦當機,那麼整個叢集則不能夠繼續寫入,需要人工手動指定slave節點為master,這段時間會造成部分請求失敗,費時費力,使用者體驗極差。為了實作master自動切換,redis為我們提供了哨兵模式,以提高redis叢集的高可用。

哨兵模式是一種特殊的模式,首先Redis提供了哨兵的指令,哨兵是一個獨立的程序,作為程序,它會獨立運作。其原理是哨兵通過發送指令,等待Redis伺服器響應,進而監控運作的多個Redis執行個體。

叢集架構

redis叢集 + 哨兵 + zookeeper_redis專題系列16 -- redis 叢集模式之哨兵模式叢集架構叢集部署簡單示例哨兵叢集部署注意事項基本原理經驗之談常用配置參數說明常用指令Java代碼使用哨兵模式

它由兩部分組成:

  • 哨兵節點:哨兵系統由一個或多個哨兵節點組成,哨兵節點是特殊的Redis節點,不存儲資料。
  • 資料節點:主節點和從節點都是資料節點。

叢集部署簡單示例

系統環境: Win10 X64 , redis版本:3.2.100

1.在安裝環境下,copy兩份redis配置檔案,分别為redis.windows.6380.conf,redis.windows.6381.conf,内容如下:

#redis.conf

port 6379

daemonize yes

logfile ""

dbfilename "dump-6379.rdb"

#redis.windows.6380.conf

port 6380

daemonize yes

logfile ""

dbfilename ""

slaveof 127.0.0.1 6379

#redis.windows.6381.conf

port 6381

daemonize yes

logfile ""

dbfilename "dump-6381.rdb"

slaveof 127.0.0.1 6379

配置完成後,一次啟動主節點和2個從節點。

redis pathedis.windows.conf

redis pathedis.windows.6380.conf

redis pathedis.windows.6381.conf

檢視主從節點狀态:

127.0.0.1:6379> info replication

# Replication

role:master

connected_slaves:2

slave0:ip=127.0.0.1,port=6381,state=online,offset=113,lag=1

slave1:ip=127.0.0.1,port=6380,state=online,offset=113,lag=1

master_repl_offset:113

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:2

repl_backlog_histlen:112

2.部署哨兵節點

#sentine.conf

port 26379

daemonize yes

logfile ""

sentinel monitor mymaster 127.0.0.1 6379 2

sentinel failover-timeout mymaster 15000

sentinel config-epoch mymaster 1

bind 127.0.0.1

#sentinel.26380.conf

port 26380

daemonize yes

logfile ""

sentinel monitor mymaster 127.0.0.1 6379 2

sentinel failover-timeout mymaster 15000

sentinel config-epoch mymaster 1

bind 127.0.0.1

本配置檔案力求簡化,友善大家排查糾錯,後續再将哨兵的配置參數詳解。

sentinel monitor mymaster 127.0.0.1 6379 2 意思是目前哨兵監控的主節點為127.0.0.1:6379, 節點名稱為mymaster(可自定義),最後的2用來判斷節點故障:隻要2個節點主觀認為節點不可用, 才會判定為故障節點并進行故障轉移。

在linux上哨兵節點有2中指令來啟動:

redis-sentinel sentinel.conf

redis-server sentinel.conf --sentinel

但在windows上我們隻能采用第二種啟動方式,

啟動哨兵節點

redis-server pathsentinel.conf --sentinel

redis-server pathsentinel.26380.conf --sentinel

啟動成功後,檢視哨兵節點監控資訊:

127.0.0.1:26379> info sentinel

# Sentinel

sentinel_masters:1

sentinel_tilt:0

sentinel_running_scripts:0

sentinel_scripts_queue_length:0

sentinel_simulate_failure_flags:0

master0:name=mymaster,status=ok,address=127.0.0.1:6379,slaves=2,sentinels=2

此時可以看到,哨兵節點監控主節點為 127.0.0.1:6379 ,并同時發現了另外兩個從節點及總共2個哨兵節點(包含其本身)

細心的朋友會發現哨兵節點的配置檔案也追加了新的資訊:

# Generated by CONFIG REWRITE

dir "C:甥敳獲jli2"

sentinel config-epoch mymaster 0

sentinel leader-epoch mymaster 0

sentinel known-slave mymaster 127.0.0.1 6380

sentinel known-slave mymaster 127.0.0.1 6381

sentinel known-sentinel mymaster 127.0.0.1 26379 d0b006d092d8da0567bcda0be9983409de053354

sentinel current-epoch 0

其中,dir隻是顯式聲明了資料和日志所在的目錄(在哨兵語境下隻有日志);known-slave和known-sentinel顯示哨兵已經發現了從節點和其他哨兵;帶有epoch的參數與配置紀元有關(配置紀元是一個從0開始的計數器,每進行一次上司者哨兵選舉,都會+1;上司者哨兵選舉是故障轉移階段的一個操作,在後文原理部分會介紹), d0b006d092d8da0567bcda0be9983409de053354 指另外一個哨兵節點的id(如果沒有配置,哨兵啟動時會自動生成)。

3.故障轉移示例

S1.我們嘗試kill掉主節點的背景服務,根據端口後找到其pid,拿到pid後,執行kill指令,在win10下,操作如下:

查找6379的pid有兩種方法:

1>.啟動日志

redis叢集 + 哨兵 + zookeeper_redis專題系列16 -- redis 叢集模式之哨兵模式叢集架構叢集部署簡單示例哨兵叢集部署注意事項基本原理經驗之談常用配置參數說明常用指令Java代碼使用哨兵模式

PID:444

2>.查找端口号為6379程序的pid, 指令: netstat |findstr 6379

redis叢集 + 哨兵 + zookeeper_redis專題系列16 -- redis 叢集模式之哨兵模式叢集架構叢集部署簡單示例哨兵叢集部署注意事項基本原理經驗之談常用配置參數說明常用指令Java代碼使用哨兵模式

6379程序對應的pid為444

S2.強制kill掉程序号為444的程序:

redis叢集 + 哨兵 + zookeeper_redis專題系列16 -- redis 叢集模式之哨兵模式叢集架構叢集部署簡單示例哨兵叢集部署注意事項基本原理經驗之談常用配置參數說明常用指令Java代碼使用哨兵模式

S3.故障節點轉移需要一段時間,過段時間,觀察哨兵節點的監控資訊:

127.0.0.1:26379> info sentinel

# Sentinel

sentinel_masters:1

sentinel_tilt:0

sentinel_running_scripts:0

sentinel_scripts_queue_length:0

sentinel_simulate_failure_flags:0

master0:name=mymaster,status=ok,address=127.0.0.1:6380,slaves=2,sentinels=2

但是同時可以發現,哨兵節點認為新的主節點仍然有2個從節點,這是因為哨兵在将6380切換成主節點的同時,将6379節點置為其從節點;雖然6379從節點已經挂掉,但是由于哨兵并不會對從節點進行客觀下線(其含義将在原理部分介紹),是以認為該從節點一直存在。當6379節點重新啟動後,會自動變成6380節點的從節點。下面驗證一下。

redis叢集 + 哨兵 + zookeeper_redis專題系列16 -- redis 叢集模式之哨兵模式叢集架構叢集部署簡單示例哨兵叢集部署注意事項基本原理經驗之談常用配置參數說明常用指令Java代碼使用哨兵模式

6379變為了6380的從節點

同時你也可以在任何資料節點看到6379和6380的主從關系:

redis叢集 + 哨兵 + zookeeper_redis專題系列16 -- redis 叢集模式之哨兵模式叢集架構叢集部署簡單示例哨兵叢集部署注意事項基本原理經驗之談常用配置參數說明常用指令Java代碼使用哨兵模式

S4. 資料節點配置檔案的更新

# redis.conf 即原來的主節點配置資訊,變為6380的從節點

port 6379

daemonize yes

logfile ""

dbfilename "dump-6379.rdb"

bind 127.0.0.1

# Generated by CONFIG REWRITE

dir "C:Redis-x64-3.2.100"

slaveof 127.0.0.1 6380

#redis.windows.6380.conf 新主節點

port 6380

daemonize yes

logfile ""

dbfilename "dump-6380.rdb"

# Generated by CONFIG REWRITE

dir "C:甥敳獲jli2"

#redis.windows.6381.conf 更新為6380的從節點

port 6381

daemonize yes

logfile ""

dbfilename "dump-6381.rdb"

slaveof 127.0.0.1 6380

# Generated by CONFIG REWRITE

dir "C:甥敳獲jli2"

#兩個哨兵節點

#26379

port 26379

daemonize yes

logfile ""

sentinel myid d0b006d092d8da0567bcda0be9983409de053354

sentinel monitor mymaster 127.0.0.1 6380 2

bind 127.0.0.1

# Generated by CONFIG REWRITE

dir "C:甥敳獲jli2"

sentinel config-epoch mymaster 1

sentinel leader-epoch mymaster 1

sentinel known-slave mymaster 127.0.0.1 6379

sentinel known-slave mymaster 127.0.0.1 6381

sentinel known-sentinel mymaster 127.0.0.1 26380 37e8c55a99ca7ce1c97a1ff19967fd98f2b296d1

sentinel current-epoch

#26379

port 26380

daemonize yes

logfile ""

sentinel myid 37e8c55a99ca7ce1c97a1ff19967fd98f2b296d1

sentinel monitor mymaster 127.0.0.1 6380 2

sentinel failover-timeout mymaster 15000

bind 127.0.0.1

# Generated by CONFIG REWRITE

dir "C:甥敳獲jli2"

sentinel config-epoch mymaster 1

sentinel leader-epoch mymaster 1

sentinel known-slave mymaster 127.0.0.1 6379

sentinel known-slave mymaster 127.0.0.1 6381

sentinel known-sentinel mymaster 127.0.0.1 26379 d0b006d092d8da0567bcda0be9983409de053354

sentinel current-epoch 1

哨兵叢集部署注意事項

哨兵系統中的主從節點,與普通的主從節點并沒有什麼差別,故障發現和轉移是由哨兵來控制和完成的。

哨兵節點本質上是Redis節點。

每個哨兵節點,隻需要配置監控主節點,便可以自動發現其他的哨兵節點和從節點。

在哨兵節點啟動和故障轉移階段,各個節點的配置檔案會被重寫(Config Rewrite)。

例子中,一個哨兵隻監控了一個主節點;實際上,一個哨兵可以監控多個主節點,通過配置多條sentinel monitor即可實作。

基本原理

在原理講解之前,先了解幾個概念:

定時任務:每個哨兵節點維護了3個定時任務。定時任務的功能分别如下:通過向主從節點發送info指令擷取最新的主從結構;通過釋出訂閱功能擷取其他哨兵節點的資訊;通過向其他節點發送ping指令進行心跳檢測,判斷是否下線。

主觀下線:在心跳檢測的定時任務中,如果其他節點超過一定時間沒有回複,哨兵節點就會将其進行主觀下線。顧名思義,主觀下線的意思是一個哨兵節點“主觀地”判斷下線;與主觀下線相對應的是客觀下線。

客觀下線:哨兵節點在對主節點進行主觀下線後,會通過sentinel is-master-down-by-addr指令詢問其他哨兵節點該主節點的狀态;如果判斷主節點下線的哨兵數量達到一定數值,則對該主節點進行客觀下線。

需要特别注意的是,客觀下線是主節點才有的概念;如果從節點和哨兵節點發生故障,被哨兵主觀下線後,不會再有後續的客觀下線和故障轉移操作。

選舉上司者哨兵節點:當主節點被判斷客觀下線以後,各個哨兵節點會進行協商,選舉出一個上司者哨兵節點,并由該上司者節點對其進行故障轉移操作。

監視該主節點的所有哨兵都有可能被選為上司者,選舉使用的算法是Raft算法;Raft算法的基本思路是先到先得:即在一輪選舉中,哨兵A向B發送成為上司者的申請,如果B沒有同意過其他哨兵,則會同意A成為上司者。選舉的具體過程這裡不做較長的描述,一般來說,哨兵選擇的過程很快,誰先完成客觀下線,一般就能成為上司者。

故障轉移:選舉出的上司者哨兵,開始進行故障轉移操作,該操作大體可以分為3個步驟:

  • 在從節點中選擇新的主節點:選擇的原則是,首先過濾掉不健康的從節點;然後選擇優先級最高的從節點(由slave-priority指定);如果優先級無法區分,則選擇複制偏移量最大的從節點;如果仍無法區分,則選擇runid最小的從節點。
  • 更新主從狀态:通過slaveof no one指令,讓選出來的從節點成為主節點;并通過slaveof指令讓其他節點成為其從節點。
  • 将已經下線的主節點(即6379)設定為新的主節點的從節點,當6379重新上線後,它會成為新的主節點的從節點。

通過上述幾個關鍵概念,可以基本了解哨兵的工作原理。為了更形象的說明,下圖展示了上司者哨兵節點的日志,包括從節點啟動到完成故障轉移。

下面結合哨兵leader節點的log了解一下:

redis叢集 + 哨兵 + zookeeper_redis專題系列16 -- redis 叢集模式之哨兵模式叢集架構叢集部署簡單示例哨兵叢集部署注意事項基本原理經驗之談常用配置參數說明常用指令Java代碼使用哨兵模式

STEP1: 擷取到了主從節點的資訊,并通過sub訂閱到了其他哨兵的資訊。

STEP2:通過ping指令,對主節點進行主管下線

STEP3: 通過詢問其他哨兵節點關于主節點的資訊來進行主管下線

STEP4:新紀元開始,通過raft算法,選舉哨兵leader節點

STEP5:完成故障轉移

STEP6:6379重新開機後設定為從節點。

經驗之談

哨兵節點的數量應不止一個。一方面增加哨兵節點的備援,避免哨兵本身成為高可用的瓶頸;另一方面減少對下線的誤判。此外,這些不同的哨兵節點應部署在不同的實體機上。

哨兵節點的數量應該是奇數,便于哨兵快速通過投票做出“決策”:上司者選舉的決策、客觀下線的決策等。

各個哨兵節點的配置應一緻,包括硬體、參數等;此外,所有節點都應該使用ntp或類似服務,保證時間準确、一緻。

哨兵的配置提供者和通知用戶端功能,需要用戶端的支援才能實作,如前文所說的Jedis;如果開發者使用的庫未提供相應支援,則可能需要開發者自己實作。

當哨兵系統中的節點在Docker(或其他可能進行端口映射的軟體)中部署時,應特别注意端口映射可能會導緻哨兵系統無法正常工作,因為哨兵的工作基于與其他節點的通信,而Docker的端口映射可能導緻哨兵無法連接配接到其他節點。例如,哨兵之間互相發現,依賴于它們對外宣稱的IP和port,如果某個哨兵A部署在做了端口映射的Docker中,那麼其他哨兵使用A宣稱的port無法連接配接到A。

常用配置參數說明

1.sentinel monitor {masterName} {masterIp} {masterPort} {quorum}

sentinel monitor是哨兵最核心的配置,在前文講述部署哨兵節點時已說明,其中:masterName指定了主節點名稱,masterIp和masterPort指定了主節點位址,quorum是判斷主節點客觀下線的哨兵數量門檻值:當判定主節點下線的哨兵數量達到quorum時,對主節點進行客觀下線。建議取值為哨兵數量的一半加1。

2.sentinel down-after-milliseconds {masterName} {time}

sentinel down-after-milliseconds與主觀下線的判斷有關:哨兵使用ping指令對其他節點進行心跳檢測,如果其他節點超過down-after-milliseconds配置的時間沒有回複,哨兵就會将其進行主觀下線。該配置對主節點、從節點和哨兵節點的主觀下線判定都有效。

down-after-milliseconds的預設值是30000,即30s;可以根據不同的網絡環境和應用要求來調整:值越大,對主觀下線的判定會越寬松,好處是誤判的可能性小,壞處是故障發現和故障轉移的時間變長,用戶端等待的時間也會變長。例如,如果應用對可用性要求較高,則可以将值适當調小,當故障發生時盡快完成轉移;如果網絡環境相對較差,可以适當提高該門檻值,避免頻繁誤判。

3.sentinel parallel - syncs {masterName} {number}

sentinel parallel-syncs與故障轉移之後從節點的複制有關:它規定了每次向新的主節點發起複制操作的從節點個數。例如,假設主節點切換完成之後,有3個從節點要向新的主節點發起複制;如果parallel-syncs=1,則從節點會一個一個開始複制;如果parallel-syncs=3,則3個從節點會一起開始複制。

parallel-syncs取值越大,從節點完成複制的時間越快,但是對主節點的網絡負載、硬碟負載造成的壓力也越大;應根據實際情況設定。例如,如果主節點的負載較低,而從節點對服務可用的要求較高,可以适量增加parallel-syncs取值。parallel-syncs的預設值是1。

4.sentinel failover - timeout {masterName} {time}

sentinel failover-timeout與故障轉移逾時的判斷有關,但是該參數不是用來判斷整個故障轉移階段的逾時,而是其幾個子階段的逾時,例如如果主節點晉升從節點時間超過timeout,或從節點向新的主節點發起複制操作的時間(不包括複制資料的時間)超過timeout,都會導緻故障轉移逾時失敗。

failover-timeout的預設值是180000,即180s;如果逾時,則下一次該值會變為原來的2倍。

常用指令

1.基礎查詢:

通過這些指令,可以查詢哨兵系統的拓撲結構、節點資訊、配置資訊等。

  • info sentinel:擷取監控的所有主節點的基本資訊。
  • sentinel masters:擷取監控的所有主節點的詳細資訊。
  • sentinel master mymaster:擷取監控的主節點mymaster的詳細資訊。
  • sentinel slaves mymaster:擷取監控的主節點mymaster的從節點的詳細資訊。
  • sentinel sentinels mymaster:擷取監控的主節點mymaster的哨兵節點的詳細資訊。
  • sentinel get - master - addr - by- name mymaster:擷取監控的主節點mymaster的位址資訊,前文已有介紹。
  • sentinel is-master-down-by-addr:哨兵節點之間可以通過該指令詢問主節點是否下線,進而對是否客觀下線做出判斷。

2.增加/移除對主節點的監控:

sentinel monitor mymaster2 192.168.92.128 16379 2:與部署哨兵節點時配置檔案中的sentinel monitor功能完全一樣,不再詳述。

sentinel remove mymaster2:取消目前哨兵節點對主節點mymaster2的監控。

3.強制故障轉移:

sentinel failover mymaster:該指令可以強制對mymaster執行故障轉移,即便目前的主節點運作完好;例如,如果目前主節點所在機器即将報廢,便可以提前通過failover指令進行故障轉移。

Java代碼使用哨兵模式

redis叢集 + 哨兵 + zookeeper_redis專題系列16 -- redis 叢集模式之哨兵模式叢集架構叢集部署簡單示例哨兵叢集部署注意事項基本原理經驗之談常用配置參數說明常用指令Java代碼使用哨兵模式

Jdeis示例

Jedis用戶端對哨兵提供了很好的支援。如上述代碼所示,我們隻需要向Jedis提供哨兵節點集合和masterName,構造Jedis SentinelPool對象;然後便可以像使用普通Redis連接配接池一樣來使用了:通過pool.getResource()擷取連接配接,執行具體的指令。

在整個過程中,我們的代碼不需要顯式的指定主節點的位址,就可以連接配接到主節點;代碼中對故障轉移沒有任何展現,就可以在哨兵完成故障轉移後自動的切換主節點。之是以可以做到這一點,是因為在JedisSentinelPool的構造器中,進行了相關的工作,主要包括以下兩點:

周遊哨兵節點,擷取主節點資訊:周遊哨兵節點,通過其中一個哨兵節點+masterName獲得主節點的資訊;該功能是通過調用哨兵節點的sentinel get-master-addr-by-name指令實作,該指令示例如下

redis叢集 + 哨兵 + zookeeper_redis專題系列16 -- redis 叢集模式之哨兵模式叢集架構叢集部署簡單示例哨兵叢集部署注意事項基本原理經驗之談常用配置參數說明常用指令Java代碼使用哨兵模式

一旦獲得主節點資訊,停止周遊(是以一般來說周遊到第一個哨兵節點,循環就停止了)。

增加對哨兵的監聽:這樣當發生故障轉移時,用戶端便可以收到哨兵的通知,進而完成主節點的切換。具體做法是:利用Redis提供的釋出訂閱功能,為每一個哨兵節點開啟一個單獨的線程,訂閱哨兵節點的+switch-master頻道,當收到消息時,重新初始化連接配接池。

總結:

通過用戶端原理的介紹,可以加深對哨兵功能的了解,如下:

配置提供者:用戶端可以通過哨兵節點+masterName擷取主節點資訊,在這裡哨兵起到的作用就是配置提供者。

需要注意的是,哨兵隻是配置提供者,而不是代理。二者的差別在于:

  • 如果是配置提供者,用戶端在通過哨兵獲得主節點資訊後,會直接建立到主節點的連接配接,後續的請求(如set/get)會直接發向主節點;
  • 如果是代理,用戶端的每一次請求都會發向哨兵,哨兵再通過主節點處理請求。

通知:哨兵節點在故障轉移完成後,會将新的主節點資訊發送給用戶端,以便用戶端及時切換主節點。

内容有點多,希望大家慢慢系消化!!