1. 程式人生 > >搭建redis-sentinel(哨兵機制)叢集

搭建redis-sentinel(哨兵機制)叢集

redis怎麼才能做到高可用
對於redis主從架構,slave可以對應多個本身可以保障高可用,但是對於一個master節點,如果宕機,整個快取系統就無法進行寫的操作,顯然整個系統會無法做到高可用
sentinel哨兵可以監測master節點是否正常執行(會自動識別出所有的slave資訊),如果出現宕機,則會在對應的slave節點中通過投票的方式來選取一個slave節點作為新的master節點,
舊的master節點恢復之後會被接管成為新的master節點的slave節點。同時sentinel哨兵節點本身也是叢集的方式部署來保障自身的高可用,並且一個sentinel是可以同時監聽多個master節點

對於sentinel哨兵節點的一些核心概念:


1、sdown和odown轉換機制

sdown和odown兩種失敗狀態

sdown是主觀宕機,就一個哨兵如果自己覺得一個master宕機了,那麼就是主觀宕機

odown是客觀宕機,如果quorum數量的哨兵都覺得一個master宕機了,那麼就是客觀宕機

sdown達成的條件很簡單,如果一個哨兵ping一個master,超過了is-master-down-after-milliseconds指定的毫秒數之後,就主觀認為master宕機

sdown到odown轉換的條件很簡單,如果一個哨兵在指定時間內,收到了quorum指定數量的其他哨兵也認為那個master是sdown了,那麼就認為是odown了,客觀認為master宕機

2、哨兵叢集的自動發現機制

哨兵互相之間的發現,是通過redis的pub/sub系統實現的,每個哨兵都會往__sentinel__:hello這個channel裡傳送一個訊息,這時候所有其他哨兵都可以消費到這個訊息,並感知到其他的哨兵的存在

每隔兩秒鐘,每個哨兵都會往自己監控的某個master+slaves對應的__sentinel__:hello channel裡傳送一個訊息,內容是自己的host、ip和runid還有對這個master的監控配置

每個哨兵也會去監聽自己監控的每個master+slaves對應的__sentinel__:hello channel,然後去感知到同樣在監聽這個master+slaves的其他哨兵的存在

每個哨兵還會跟其他哨兵交換對master的監控配置,互相進行監控配置的同步

3、slave配置的自動糾正

哨兵會負責自動糾正slave的一些配置,比如slave如果要成為潛在的master候選人,哨兵會確保slave在複製現有master的資料; 如果slave連線到了一個錯誤的master上,比如故障轉移之後,那麼哨兵會確保它們連線到正確的master上

4、slave->master選舉演算法

如果一個master被認為odown了,而且majority哨兵都允許了主備切換,那麼某個哨兵就會執行主備切換操作,此時首先要選舉一個slave來

會考慮slave的一些資訊

(1)跟master斷開連線的時長
(2)slave優先順序
(3)複製offset
(4)run id

如果一個slave跟master斷開連線已經超過了down-after-milliseconds的10倍,外加master宕機的時長,那麼slave就被認為不適合選舉為master

(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state

接下來會對slave進行排序

(1)按照slave優先順序進行排序,slave priority越低,優先順序就越高
(2)如果slave priority相同,那麼看replica offset,哪個slave複製了越多的資料,offset越靠後,優先順序就越高
(3)如果上面兩個條件都相同,那麼選擇一個run id比較小的那個slave

5、quorum和majority

每次一個哨兵要做主備切換,首先需要quorum數量的哨兵認為odown,然後選舉出一個哨兵來做切換,這個哨兵還得得到majority哨兵的授權,才能正式執行切換

如果quorum < majority,比如5個哨兵,majority就是3,quorum設定為2,那麼就3個哨兵授權就可以執行切換

但是如果quorum >= majority,那麼必須quorum數量的哨兵都授權,比如5個哨兵,quorum是5,那麼必須5個哨兵都同意授權,才能執行切換

6、configuration epoch

哨兵會對一套redis master+slave進行監控,有相應的監控的配置

執行切換的那個哨兵,會從要切換到的新master(salve->master)那裡得到一個configuration epoch,這就是一個version號,每次切換的version號都必須是唯一的

如果第一個選舉出的哨兵切換失敗了,那麼其他哨兵,會等待failover-timeout時間,然後接替繼續執行切換,此時會重新獲取一個新的configuration epoch,作為新的version號

7、configuraiton傳播

哨兵完成切換之後,會在自己本地更新生成最新的master配置,然後同步給其他的哨兵,就是通過之前說的pub/sub訊息機制

這裡之前的version號就很重要了,因為各種訊息都是通過一個channel去釋出和監聽的,所以一個哨兵完成一次新的切換之後,新的master配置是跟著新的version號的

其他的哨兵都是根據版本號的大小來更新自己的master配置的

 

1redis安裝

解壓完成後可以看到INSTALL和README.md檔案,檢視以獲取更多有用資訊。

在README檔案中可以獲取到軟體的安裝步驟。以下安裝步驟基於此。

#step1 進入資料夾,執行編譯命令

[[email protected] redis-3.2.8]# make

#step2 為了後面開發測試的方便,把啟動指令碼,配置檔案,日誌檔案統一放到redis目錄下

[[email protected] redis-3.2.8]# mkdir /usr/local/redis
[[email protected] redis-3.2.8]# mkdir /usr/local/redis/logs
[[email protected] redis-3.2.8]# mkdir /usr/local/redis/bin
[[email protected] redis-3.2.8]# mkdir /usr/local/redis/conf
[[email protected] redis-3.2.8]# mkdir /etc/sentinel
[[email protected] redis-3.2.8]# mkdir -p /var/sentinel/26377
[[email protected] redis-3.2.8]# mkdir -p /var/sentinel/26378
[[email protected] redis-3.2.8]# mkdir -p /var/sentinel/26379 [[email protected] redis-3.2.8]# cp redis.conf sentinel.conf /usr/local/redis/conf/ [[email protected] src]# cp redis-server redis-sentinel redis-cli /usr/local/redis/bin/

#step3 開啟Redis服務,檢測其可用性

[[email protected] bin]# redis-server ../conf/redis.conf 

可以看到日誌資訊

其中有3個警告

第一個警告:The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.

意思是:TCP  backlog設定值,511沒有成功,因為 /proc/sys/net/core/somaxconn這個設定的是更小的128.

第二個警告:overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to/etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.

意思是:overcommit_memory引數設定為0!在記憶體不足的情況下,後臺程式save可能失敗。建議在檔案 /etc/sysctl.conf 中將overcommit_memory修改為1。

第三個警告:you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix thisissue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain thesetting after a reboot. Redis must be restarted after THP is disabled.

意思是:你使用的是透明大頁,可能導致redis延遲和記憶體使用問題。執行 echo never > /sys/kernel/mm/transparent_hugepage/enabled 修復該問題。

臨時解決方法:

  echo 511 > /proc/sys/net/core/somaxconn

  echo "vm.overcommit_memory=1" > /etc/sysctl.conf

  echo never > /sys/kernel/mm/transparent_hugepage/enabled。

永久解決方法:

vim /etc/sysctl.conf
net.core.somaxconn = 512
vm.overcommit_memory = 1

kernel.mm.transparent_hugepage.enabled = never

Redis server使用預設埠6379啟動成功。

#step4 修改配置檔案,使其以後臺服務方式執行。

複製程式碼
#what?區域網內本機IP。
#我是部署到同一機器上所以IP都一樣,埠不同
bind 127.0.0.1
#修改預設埠,避免被惡意指令碼掃描。
port 9999
loglevel debug
logfile /usr/local/redis/logs/redis.log.9999
#為服務設定安全密碼
requirepass redispass
#以守護程序方式執行 daemonize yes
複製程式碼

#step5 重新啟動redis。

[[email protected] bin]# redis-cli -p 9999 -a redispass shutdown
我使用指令碼啟動方式
  啟動指令碼 redis_init_script 位於位於Redis的 /utils/ 目錄下,redis_init_script指令碼程式碼如下:
#!/bin/sh
#
# Simple Redis init.d script conceived to work on Linux systems
# as it does use of the /proc filesystem.
 
#redis伺服器監聽的埠
REDISPORT=9999
 
#服務端所處位置
EXEC=/usr/local/bin/redis-server
 
#客戶端位置
CLIEXEC=/usr/local/bin/redis-cli
 
#redis的PID檔案位置,需要修改
PIDFILE=/var/run/redis_${REDISPORT}.pid
 
#redis的配置檔案位置,需將${REDISPORT}修改為檔名
CONF="/etc/redis/${REDISPORT}.conf"
 
case "$1" in
    start)
        if [ -f $PIDFILE ]
        then
                echo "$PIDFILE exists, process is already running or crashed"
        else
                echo "Starting Redis server..."
                $EXEC $CONF
        fi
        ;;
    stop)
        if [ ! -f $PIDFILE ]
        then
                echo "$PIDFILE does not exist, process is not running"
        else
                PID=$(cat $PIDFILE)
                echo "Stopping ..."
                $CLIEXEC -p $REDISPORT shutdown
                while [ -x /proc/${PID} ]
                do
                    echo "Waiting for Redis to shutdown ..."
                    sleep 1
                done
                echo "Redis stopped"
        fi
        ;;
    *)
        echo "Please use start or stop as first argument"
        ;;
esac

可以根據你自己埠進行修改

mkdir /etc/redis
cp redis.conf /etc/redis/9999.conf
將啟動指令碼複製到/etc/init.d目錄下,本例將啟動指令碼命名為redisd(通常都以d結尾表示是後臺自啟動服務)。
cp redis_init_script /etc/init.d/redis_9999
./redis_9999 start

2開啟主從複製(master-slave)

主從模式的兩個重要目的,提升系統可靠性和讀寫分離提升效能。

這裡通過修改埠的方式,再啟動埠為9997和9998的服務作為備(從)機。

備機啟動需要修改配置檔案部分屬性(在9999配置的基礎上)。

複製程式碼
port 9997
logfile /usr/local/redis/logs/redis.log.9997
#指定master ip port
slaveof 127.0.0.1 9999
#認證master時需要的密碼。必須和master配置的requirepass 保持一致
masterauth redispass
requirepass redispass protected-mode no
複製程式碼

從機9998配置同理

port 9998
logfile /usr/local/redis/logs/redis.log.9998
slaveof 127.0.0.1 9999
masterauth redispass
requirepass redispass protected-mode no

開啟從機服務

[[email protected] bin]# ./redis_9997 start
[[email protected] bin]# ./redis_9998 start

檢視slave 9998日誌(省略部分資訊),可以看出,slave在啟動時成功連線master,並接收到了104位元組的同步資料。

6472:S 30 Mar 11:18:17.206 * Connecting to MASTER 127.0.0.1:9999
6472:S 30 Mar 11:18:17.206 * MASTER <-> SLAVE sync started
6472:S 30 Mar 11:18:17.223 * MASTER <-> SLAVE sync: receiving 104 bytes from master
6472:S 30 Mar 11:18:17.223 * MASTER <-> SLAVE sync: Finished with success

redis做一個基準的壓測

你如果要對自己剛剛搭建好的redis做一個基準的壓測,測一下你的redis的效能和QPS(query per second)

redis自己提供的redis-benchmark壓測工具,是最快捷最方便的,當然啦,這個工具比較簡單,用一些簡單的操作和場景去壓測

1、對redis讀寫分離架構進行壓測,單例項寫QPS+單例項讀QPS

redis-3.2.8/src

./redis-benchmark -h 127.0.0.1

-c <clients> Number of parallel connections (default 50)
-n <requests> Total number of requests (default 100000)
-d <size> Data size of SET/GET value in bytes (default 2)

根據你自己的高峰期的訪問量,在高峰期,瞬時最大使用者量會達到10萬+,-c 100000,-n 10000000,-d 500

1、QPS,自己不同公司,不同伺服器,自己去測試,跟生產環境還有區別

生產環境,大量的網路請求的呼叫,網路本身就有開銷,你的redis的吞吐量就不一定那麼高了

QPS的兩個殺手:一個是複雜操作,lrange,挺多的; value很大,2 byte,我之前用redis做大規模的快取

做商品詳情頁的cache,可能是需要把大串資料,拼接在一起,作為一個json串,大小可能都幾k,幾個byte

2、水平擴容redis讀節點,提升度吞吐量

就按照上一節課講解的,再在其他伺服器上搭建redis從節點,單個從節點讀請QPS在5萬左右,兩個redis從節點,所有的讀請求打到兩臺機器上去,承載整個叢集讀QPS在10萬+

3 sentinel模式故障自動遷移

Master-slave主從複製避免了資料丟失帶來的災難性後果。

但是單點故障仍然存在,在執行期間master宕機需要停機手動切換。

Sentinel很好的解決了這個問題,當Master-slave模式中的Master宕機後,能夠自主切換,選擇另一個可靠的redis-server充當master角色,使系統仍正常執行。

一般來說sentinel server需要大於等於3個。

這裡通過修改埠的方式開啟3個sentinel server。修改配置檔案sentinel.conf部分屬性

複製程式碼
#服務執行埠號
port 26379
sentinel monitor mumaster 1270.0.0.1 9999 2 #mymaster為指定的master伺服器起一個別名 #master IP和埠號 #2的含義:當開啟的sentinel server認為當前master主觀下線的(+sdown)數量達到2時,則sentinel server認為當前master客觀下線(+odown)系統開始自動遷移。2的計算(建議):
#sentinel server數量的大多數,至少為count(sentinel server)/2 向上取整。2>3/2(主觀下線與客觀下線?) #master別名和認證密碼。這就提醒了使用者,在master-slave系統中,各服務的認證密碼應該保持一致。 sentinel auth-pass mymaster redispass #以守護程序方式執行 daemonize yes logfile /usr/local/redis/logs/sentinel.log.26379 protected-mode no sentinel down-after-milliseconds mymaster 6000 sentinel failover-timeout mymaster 18000
複製程式碼

(多開服務只需要在以上配置基礎上修改埠號,其它保持不變 port 26378/port 26377)

開啟Sentinel服務

redis-sentinel /etc/sentinel/26377.conf
redis-sentinel /etc/sentinel/26378.conf
redis-sentinel /etc/sentinel/26379.conf

啟動之後可以看到日誌資訊,每個哨兵都能去監控到對應的redis master,並能夠自動發現對應的slave,哨兵之間,互相會自動進行發現,用的就是之前說的pub/sub,訊息釋出和訂閱channel訊息系統和機制

檢查哨兵狀態
redis-cli -h 127.0.0.1 -p 26377 -a "redispass"

sentinel master mymaster
SENTINEL slaves mymaster
SENTINEL sentinels mymaster

SENTINEL get-master-addr-by-name mymaster

哨兵節點相關配置

 

1、哨兵節點的增加和刪除

增加sentinal,會自動發現

刪除sentinal的步驟

(1)停止sentinal程序
(2)SENTINEL RESET *,在所有sentinal上執行,清理所有的master狀態
(3)SENTINEL MASTER mastername,在所有sentinal上執行,檢視所有sentinal對數量是否達成了一致

2、slave的永久下線

讓master摘除某個已經下線的slave:SENTINEL RESET mastername,在所有的哨兵上面執行

3、slave切換為Master的優先順序

slave->master選舉優先順序:slave-priority,值越小優先順序越高

4、基於哨兵叢集架構下的安全認證

每個slave都有可能切換成master,所以每個例項都要配置兩個指令

master上啟用安全認證,requirepass
master連線口令,masterauth

sentinal,sentinel auth-pass <master-group-name> <pass>

 

5、容災演練

通過哨兵看一下當前的master:SENTINEL get-master-addr-by-name mymaster

把master節點kill -9掉,pid檔案也刪除掉

檢視sentinal的日誌,是否出現+sdown字樣,識別出了master的宕機問題; 然後出現+odown字樣,就是指定的quorum哨兵數量,都認為master宕機了

(1)三個哨兵程序都認為master是sdown了
(2)超過quorum指定的哨兵程序都認為sdown之後,就變為odown
(3)哨兵1是被選舉為要執行後續的主備切換的那個哨兵
(4)哨兵1去新的master(slave)獲取了一個新的config version
(5)嘗試執行failover
(6)投票選舉出一個slave區切換成master,每隔哨兵都會執行一次投票
(7)讓salve,slaveof noone,不讓它去做任何節點的slave了; 把slave提拔成master; 舊的master認為不再是master了
(8)哨兵就自動認為之前的master變成slave,將投票出的slave變成master 
(9)哨兵去探查了一下之前的master(變成來salve)的狀態,認為它sdown了 

 

故障恢復,再將舊的master重新啟動,檢視是否被哨兵自動切換成slave節點

檢視到結果將9999 切換為slave節點

容災演練日誌
Sentinel ID is ea82430cf7f6d452eb22bbf29b92fcf001c734c8
3010:X 21 Nov 22:37:31.405 # +monitor master mymaster 127.0.0.1 9999 quorum 2
3010:X 21 Nov 23:01:12.589 # +sdown master mymaster 127.0.0.1 9999
3010:X 21 Nov 23:01:12.642 # +odown master mymaster 127.0.0.1 9999 #quorum 3/2           -- 進入ODOWN狀態時。有三個哨兵認為master當機了
3010:X 21 Nov 23:01:12.642 # +new-epoch 7                                                -- 當前配置版本被更新時。
3010:X 21 Nov 23:01:12.642 # +try-failover master mymaster 127.0.0.1 9999                -- 嘗試故障轉移,正等待其他sentinel的選舉。
3010:X 21 Nov 23:01:12.658 # +vote-for-leader ea82430cf7f6d452eb22bbf29b92fcf001c734c8 7 -- 投票給領導
3010:X 21 Nov 23:01:12.668 # edace82644513417b676ee6eced3184771d6361d voted for ea82430cf7f6d452eb22bbf29b92fcf001c734c8 7
3010:X 21 Nov 23:01:12.668 # 7e68a54266703cbf429f5c6512a50a39ab94b943 voted for ea82430cf7f6d452eb22bbf29b92fcf001c734c8 7
3010:X 21 Nov 23:01:12.716 # +elected-leader master mymaster 127.0.0.1 9999              -- 被選舉為去執行failover的時候。
3010:X 21 Nov 23:01:12.716 # +failover-state-select-slave master mymaster 127.0.0.1 9999 -- 開始要選擇一個slave當選新master時。
3010:X 21 Nov 23:01:12.792 # +selected-slave slave 127.0.0.1:9998 127.0.0.1 9998 @ mymaster 127.0.0.1 9999 -- 找到了port:9998一個適合的slave來擔當新master
                              -- 當把選擇為新master的slave的身份進行切換的時候。
3010:X 21 Nov 23:01:12.792 * +failover-state-send-slaveof-noone slave 127.0.0.1:9998 127.0.0.1 9998 @ mymaster 127.0.0.1 9999 
                              -- 等待提升 9998 為新的master
3010:X 21 Nov 23:01:12.851 * +failover-state-wait-promotion slave 127.0.0.1:9998 127.0.0.1 9998 @ mymaster 127.0.0.1 9999
3010:X 21 Nov 23:01:13.699 # +promoted-slave slave 127.0.0.1:9998 127.0.0.1 9998 @ mymaster 127.0.0.1 9999        -- 提升 9998 master
3010:X 21 Nov 23:01:13.699 # +failover-state-reconf-slaves master mymaster 127.0.0.1 9999                         -- Failover狀態變為reconf-slaves狀態時
3010:X 21 Nov 23:01:13.749 * +slave-reconf-sent slave 127.0.0.1:9997 127.0.0.1 9997 @ mymaster 127.0.0.1 9999     -- 重新配置 9997為slave
3010:X 21 Nov 23:01:14.770 # -odown master mymaster 127.0.0.1 9999                                                -- 離開ODOWN狀態時。
                             -- inprog 9997 slave被重新配置為9998的master的slave,但資料複製還未發生時。
3010:X 21 Nov 23:01:14.770 * +slave-reconf-inprog slave 127.0.0.1:9997 127.0.0.1 9997 @ mymaster 127.0.0.1 9999 
                             -- done   9997 slave被重新配置為9998的master的slave,並且資料複製已經與master同步時。
3010:X 21 Nov 23:01:14.770 * +slave-reconf-done slave 127.0.0.1:9997 127.0.0.1 9997 @ mymaster 127.0.0.1 9999
3010:X 21 Nov 23:01:14.841 # +failover-end master mymaster 127.0.0.1 9999                                        -- 故障轉移結束
3010:X 21 Nov 23:01:14.841 # +switch-master mymaster 127.0.0.1 9999 127.0.0.1 9998                               -- master由9999 替換為 9998
3010:X 21 Nov 23:01:14.841 * +slave slave 127.0.0.1:9997 127.0.0.1 9997 @ mymaster 127.0.0.1 9998                -- 檢測到9997slave並新增進slave列表時
3010:X 21 Nov 23:01:14.842 * +slave slave 127.0.0.1:9999 127.0.0.1 9999 @ mymaster 127.0.0.1 9998                -- 檢測到9999slave
3010:X 21 Nov 23:01:44.849 # +sdown slave 127.0.0.1:9999 127.0.0.1 9999 @ mymaster 127.0.0.1 9998                -- 進入SDOWN狀態時;
3010:X 21 Nov 23:04:19.457 # -sdown slave 127.0.0.1:9999 127.0.0.1 9999 @ mymaster 127.0.0.1 9998                -- 離開SDOWN狀態時