搭建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 進入文件夾,執行編譯命令

[root@ redis-3.2.8]# make

#step2 為了后面開發測試的方便,把啟動腳本,配置文件,日志文件統一放到redis目錄下

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

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

[root@ 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
sysctl -p  #-p 從指定的文件加載系統參數,如不指定即從/etc/sysctl.conf中加載

[root@centos224]# vi /etc/rc.local
if test -f /sys/kernel/mm/transparent_hugepage/enabled; then
echo never > /sys/kernel/mm/transparent_hugepage/enabled
fi
if test -f /sys/kernel/mm/transparent_hugepage/defrag; then
echo never > /sys/kernel/mm/transparent_hugepage/defrag
fi

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。

[root@ 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

開啟從機服務

[root@ bin]# ./redis_9997 start
[root@ 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狀態時

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM