Redis高可用方案

語言: CN / TW / HK

前序

在多數後端專案中,快取這塊兒Redis屬於一枝獨秀。只要是個java程式設計師基本少不了跟redis打交道,無論是專案中實際應用或者跟面試官切磋。我們知道Redis雖然單機QPS也有好幾萬,但生產環境上基本沒人敢上單機。因為分散式環境中,不穩定因素很多,萬一哪天網線被刨斷了或者伺服器掛了。影響到客戶就不得了了。那麼為了應對Redis的單機故障,我們一般有如下的三種高可用方案。

Redis高可用方案

方案一(主從+keepalived+VIP)

主從.png 適用場景:之前的單機模式下,在redis負載高時可能會崩潰。故給主節點增加從節點做備用節點,在主掛掉時立馬提升為新主。該場景適用於redis負載不是很大,對redis高可用有需求並且客戶端對主從切換無感的場景。

Keepalived:叢集管理中高可用的一個服務軟體,通過健康檢查指令碼去檢測例項節點。當檢查失敗時會將對應節點的priority值減少。若主節點priority值比備用節點的小時,執行切換VIP指令碼跟從節點升主指令碼。

VIP:虛擬ip繫結至主節點,一旦主節點掛掉後,由keepalived重新繫結在新主節點上。

優點:應用端連線方面不用改變。

缺點:不能進行讀寫分離,主節點壓力還是很大

修改點:客戶端不需要修改。

方案二(主從+sentinel叢集)

image.png 適用場景:在系統對redis請求併發高的情況下,方案1場景中主節點負載壓力過高。

此時需要主從讀寫分離來減輕主節點壓力,並增加快取服務的高併發。客戶端通過連線

Sentinel獲取主從節點資訊,並將自己的讀寫請求分別傳送至主從節點進行請求分流,減輕主節點壓力。

Sentinel哨兵:哨兵是一個執行在特殊模式下的 Redis 程序,哨兵主要負責的就是三個任務:監控、選主和通知。哨兵執行過程中週期性向所有主從節點發送PING命令,主從節點會給哨兵回覆PONG命令。若主節點未在規定時間內回覆哨兵,則哨兵標記該主節點為主觀下線,之後會通知其它哨兵節點對該主節點進行檢測。如果超過一半哨兵都判定為主觀下線,則該主節點會被標記為客觀下線。隨後從該主節點的從節點中選出新主節點。之後會通知其餘從節點進行replicaof命令和新主節點建立聯絡,通知客戶端讓他們把操作命令發到新的主節點上。

讀寫分離:在該模式下為分擔master節點的請求壓力,可在客戶端上增加讀寫分離的邏輯,之後讀請求走從節點,寫請求走主節點。

增加從節點

啟動新的節點並在新節點上執行如下命令即可

slaveof IP PORT(IP和PORT是需要關聯的主節點ip和埠)

優點:高可用並能有效減少master上的請求壓力

缺點:修改東西較多,如果寫請求多,主節點依然有壓力大的風險。

修改點

1、 客戶端連線方式得改為sentinel模式,

2、 要實現讀寫分離得修改Jedis連線相關的邏輯

方案三(cluster叢集)

image.png 適用場景:當系統對redis的請求負載持續升高時,方案2場景中單個主節點最終因負載過高而崩潰。此時將redis升級為叢集模式,該模式下通過分槽機制將請求分散至各master節點,大大減輕單個master節點壓力,而且各master節點都有自己的從節點,在主節點掛掉時,其對應的從節點會及時補充為新主節點。該方案適用於系統對redis請求壓力高,並對redis有高併發高可用的需求場景。

叢集模式:redis cluster叢集將16384個Slot(槽位)分給叢集主節點。之後客戶端請求過來時候會先計算key的雜湊值並跟16384取模得到對應槽位。之後根據槽位跟主節點對應關係將該請求傳送至相應主節點。每個叢集節點均維護一份節點跟槽位的對映關係。 如果在一個節點上操作另外一個節點上的key,會返回去相應節點操作的提示資訊。 Master節點內部集成了Sentinel, 故不需單獨起Sentinel叢集,當有主節點掛掉時,其他Master節點會感知到並從其從節點中選出新主節點。

增加節點:當需要擴充套件記憶體增加叢集節點時,連線任一主節點並依次執行如下命令:\ redis-cli -a 密碼 --cluster add-node  新節點IP:埠  已存在節點IP:埠(增加叢集節點) 執行成功後再執行下面命令 redis-cli -a 密碼 --cluster reshard 已存在節點IP:埠(給新節點分配槽數) 根據提示分配指定槽數,分配成功後表示新主節點增加成功。再次執行增加節點命令給叢集增加從節點。然後再登入新增從節點,執行如下命令,對剛增加的新主從進行關聯。 首先登入進新從節點redis-cli -a  -c -h 新從節點IP -p 從節點埠 然後執行cluster replicate 2728a594a0498e98e4b83a537e19f9a0a3790f38 這樣便在叢集中新增了一對主從節點。

優點:支援高可用、高併發

缺點:佔用資源大

修改點

1、 客戶端連線方式得改為叢集模式

部署步驟

方案1部署步驟

1、 Redis主從安裝(記得在從節點配置檔案加一行slaveof 主節點ip 埠)

mkdir /opt/software –p

cd /opt/software

wget http://download.redis.io/releases/redis-5.0.8.tar.gz

yum –y install gcc gcc-c++

tar –zxvf redis-5.0.8.tar.gz

mv redis-5.0.8 /usr/local/src

cd /usr/local/src/reids-5.0.8/

make

make install PREFIX=/usr/local/redis

vi /usr/local/src/reids-5.0.8/redis.conf(編輯配置檔案)\ 修改bind 127.0.0.1 為 bind 0.0.0.0

修改 protected-mode yes 為protected-mode no

若為從節點需要在配置檔案最後增加一句 slaveof 主節點IP 主節點埠

2、 keepalived軟體安裝(主從節點均要安裝)

yum安裝即可:yum –y install keepalived

3、 登入進入redis主節點,編輯/etc/keepalikved/keepalived.conf

global_defs {

router_id redis_master

}

vrrp_script chk_redis

{

script "/etc/keepalived/scripts/redis_check.sh 127.0.0.1 6379"

interval 2

timeout 2

fall 3

weight -20

}

vrrp_instance redis {

state MASTER

interface 網絡卡名稱 

virtual_router_id 100

priority  100      

#nopreempt # no seize,must add

advert_int 1

authentication {   #all node must same

auth_type PASS

auth_pass 1111

}  

unicast_src_ip 主節點IP

unicast_peer {

從節點IP

}   

virtual_ipaddress { 

VIP地址

}

track_script {

chk_redis

}

notify_master "/etc/keepalived/scripts/redis_master.sh 127.0.0.1  從節點IP  從節點埠"

notify_backup "/etc/keepalived/scripts/redis_backup.sh 127.0.0.1  從節點IP  從節點埠"

notify_fault /etc/keepalived/scripts/redis_fault.sh

notify_stop /etc/keepalived/scripts/redis_stop.sh }

4、 登入從節點編輯/etc/keepalived/keepalived.conf內容如下:

global_defs {

router_id redis1

script_user root

enable_script_security

} vrrp_script chk_redis

{

script "/etc/keepalived/scripts/redis_check.sh 127.0.0.1 6379"

interval 2

timeout 2

fall 3

weight -20

} vrrp_instance redis {

state BACKUP

interface eth0 

virtual_router_id 100

priority  90      

#nopreempt # no seize,must add

advert_int 1

authentication {   #all node must same

auth_type PASS

auth_pass 1111

}  

unicast_src_ip 從節點IP

unicast_peer {

主節點IP   

}

virtual_ipaddress { 

VIP

}

track_script {

chk_redis

}

notify_master "/etc/keepalived/scripts/redis_master.sh 127.0.0.1  主節點IP  主節點埠"

notify_backup "/etc/keepalived/scripts/redis_backup.sh 127.0.0.1  主節點IP  主節點埠"

notify_fault /etc/keepalived/scripts/redis_fault.sh

notify_stop /etc/keepalived/scripts/redis_stop.sh

}

5、 建立存放keepalived所用指令碼的目錄

make /etc/keepalived/scripts –p

6、 在步驟4中建立的目錄下建立以下指令碼:

redis_backup.sh

!/bin/bash

REDISCLI="/usr/local/bin/redis-cli -h $1 -p $3"

LOGFILE="/etc/keepalived/log/keepalived-redis-state.log"

echo "[backup]" >> $LOGFILE

date >> $LOGFILE

echo "Run SLAVEOF cmd ..." >> $LOGFILE

$REDISCLI SLAVEOF $2 $3 >> $LOGFILE 2>&1

sleep 15

redis_check.sh

!/bin/bash

ALIVE=/usr/local/bin/redis-cli -h $1 -p $2 PING

LOGFILE="/etc/keepalived/log/keepalived-redis-check.log"

echo "[CHECK]" >> $LOGFILE

date >> $LOGFILE

if [[ $ALIVE == "PONG"  ]]; then :

echo "SUCCESS:reidis-cli -h $1 -p $2 PING $ALIVE" >> $LOGFILE 2>&1

exit 0

else

echo "FAILED:redis-cli -h $1 -p $2 PING $ALIVE" >> $LOGFILE 2>&1

exit 1

fi

redis_fault.sh

!/bin/bash

LOGFILE=/etc/keepalived/log/keepalived-redis-state.log

echo "[fault]" >> $LOGFILE

date >> $LOGFILE

redis_master.sh

!/bin/bash

REDISCLI="/usr/local/bin/redis-cli -h $1 -p $3"

LOGFILE="/etc/keepalived/log/keepalived-redis-state.log"

echo "[master]" >> $LOGFILE

date >> $LOGFILE

echo "Being master...." >> $LOGFILE 2>&1 

echo "Run MASTER cmd ..." >> $LOGFILE 2>&1

\$REDISCLI SLAVEOF $2 $3 >> $LOGFILE 

sleep 10

delay 10 s wait data async cancel sync

echo "Run SLAVEOF NO ONE cmd ..." >> $LOGFILE

\$REDISCLI SLAVEOF NO ONE >> $LOGFILE 2>&1

redis_stop.sh

!/bin/bash

LOGFILE=/etc/keepalived/log/keepalived-redis-state.log

echo "[stop]" >> $LOGFILE

date >> $LOGFILE

這些指令碼從節點也需要複製過來一份

給這些指令碼賦予執行許可權

chmod a+x /etc/keepalived/scripts/*.sh

7、 啟動redis跟keepalived軟體

方案2部署步驟

1、 參考方案1部署步驟1,安裝redis一主兩從並啟動

2、 sentinel配置(主從節點均需配置)

首先建立一個放置sentinel配置檔案的目錄

mkdir –p /etc/sentinel

然後將redis安裝目錄中的sentinel配置檔案複製至/etc/sentinel下

cp /usr/local/src/reids-5.0.8/sentinel.conf  /etc/sentinel/

編輯sentinel.conf如下:

監聽埠

port 26379

設定daemonize為yes,否則不會採用守護程序啟動,啟動命令會阻塞

daemonize yes

pidfile 加上埠

pidfile "/var/run/redis-sentinel_26379.pid"

自定義logfile檔案的位置

logfile "/opt/redis/logs/sentinel_26379.log"

dir "/tmp"

sentinel都指向redis叢集的主節點

sentinel monitor mymaster 主節點IP 主節點埠 2

acllog-max-len 128

sentinel deny-scripts-reconfig yes

sentinel resolve-hostnames no

protected-mode no

sentinel config-epoch mymaster 0

sentinel leader-epoch mymaster 0

3、 啟動主從節點上的sentinel

nohup  redis-sentinel  /etc/sentinel/sentinel.conf &

方案3部署步驟

該步驟以三主三從為例,想搭建更多節點叢集同理

1、 參照方案1部署步驟1,在三臺機器上分別安裝redis

2、 分別在三臺機器上建立存放叢集節點配置檔案的資料夾

mkdir –p /etc/redis-cluster

mkdir /etc/redis-cluster/6379 /etc/redis-cluster/6380

3、 從redis安裝目錄中複製redis.conf至上面的6379跟6380中

cp /usr/local/src/reids-5.0.8/redis.conf  /etc/redis-cluster/6379

4、 修改配置檔案內容如下:

(1)daemonize yes

(2)port 6379(根據目錄名代表的埠號進行修改)

(3)pidfile /var/run/redis_6379.pid  # 把pid程序號寫入pidfile配置的檔案

(4)dir /usr/local/redis-cluster/6379/(指定資料檔案存放位置,必須要指定不同的目錄位置,不然會丟失資料)

(5)cluster-enabled yes(啟動叢集模式)

(6)cluster-config-file nodes-6379.conf(叢集節點資訊檔案,這裡800x最好和port對應上)

(7)cluster-node-timeout 10000

(8)# bind 127.0.0.1(bind繫結的是自己機器網絡卡的ip,如果有多塊網絡卡可以配多個ip,代表允許客戶端通過機器的哪些網絡卡ip去訪問,內網一般可以不配置bind,註釋掉即可)

(9)protected-mode  no(關閉保護模式)

(10)appendonly yes

如果要設定密碼需要增加如下配置:

(11)requirepass 密碼 (設定redis訪問密碼)

(12)masterauth 密碼 (設定叢集節點間訪問密碼,跟上面一致)

5、將上面修改的配置檔案,複製到6380,修改第2、3、4、6項的埠號,可進行批量替換:%s/源字串/目的字串/g

6、另外兩臺機器也需做上面幾步

7、分別啟動6個redis例項

Redis-server /etc/redis-cluster/6379/redis.conf

8、建立redis叢集

Redis-cli –a 密碼 --cluster create –cluster-replicas 1 節點1IP:6379 節點1IP:6380 節點2IP:6379 節點2IP:6380 節點3IP:6379 節點2IP:6380

「其他文章」