參考文獻:
https://blog.csdn.net/liuguanghui1988/article/details/77098143
1 Redis高可用的可選方案
Redis的高可用方案目前主要5種方式。
1) Redis Master-Slave + Keepalived + VIP。
這是很經典的db架構,也可以用與mysql的主從切換。基本原理是:Keepalive通過腳本檢測master的存活,然後通過漂移VIP(Virtual IP)完成主從切換。
2) Redis Master-Slave + DNS Service + Sentinel。
基本原理是Sentinel集羣進行Redis的存活檢測和Redis M-S狀態切換。完成切換之後,sentinel調用notification-script參數制定的配置文件,通知DNS Server更改DNS配置,master dns解析執行新的master。
3) Redis Master-Slave + Configure Center(Zookeeper) + Sentinel.
基本原理和第三種方案相似,只是notification-script通知的是配置中心完成redis連接配置的修改,比如Zookeeper實現的配置中心。
4) Redis Master-Slave + Sentinel + Twemproxy + Lvs.
這種方案層次比較多,sentinel通知twemproxy進行redis m-s的配置更改。
5)Redis Cluster,redis3.0發佈了該功能,穩定性還待市場檢驗。
本文演示第一種方案:Redis Master-Slave + Keepalived + VIP.
1. 基本構建與原理
1)Keepalived + VIP : 在redis master-slave上部署keepalived、redis instance存活檢測腳本、以及告警通知腳本。
2)當redis master失效的時候,VIP從master上漂移到slave上,完成m-s角色和配置更改。3)客戶端連接redis的參數中host設置的是VIP,整個切換過程對客戶端透明。
2. 優缺點與適用場景。
優點:實現簡單,成本低,整個切換過程對客戶端透明。
缺點:整個集羣的最大吞吐量受限於redis單實例的處理能力,除非一個應用使用多套這種Keepalived+VIP方案。因而擴展能力較差,而且不適合目前單機部署多個redis實例的部署場景。
適合場景:併發請求不是很高的應用。
2 安裝keepalived
1. tar zxf keepalived-1.3.5.tar.gz 2. cd keepalived-1.3.5 3. ./configure --prefix=/usr/local/keepalived/ 4. make 5. make install 拷貝需要的文件: $ cp /usr/local/src/keepalived-1.3.5/keepalived/etc/init.d/keepalived /etc/init.d/keepalived $ cp /usr/local/keepalived/sbin/keepalived /usr/sbin/ $ cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/ $ mkdir -p /etc/keepalived/ $ cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf是默認的配置文件
第一步,安裝基礎庫
yum -y install openssl-devel libnl3-devel ipset-devel iptables-devel libnfnetlink-devel net-snmp-devel
第二步,源碼安裝keepalived
3 keepalived + Redis主從部署
3.1 部署拓補圖
基於如下的拓撲圖:
3.2 Redis主從配置
3.2.1 Redis安裝
步驟1: 首先從官網(http://download.redis.io/releases/)下載redis正式版的壓縮包redis-2.8.19.tar.gz 步驟2:編譯源碼安裝: cd /usr/local/src/ tar zxvf redis-2.8.19.tar.gz cd redis-2.8.19 make make install
3.2.2 修改redis配置文件
cd redis-2.8.19 vim redis.conf 修改相關配置項,這裏僅做DOME演示,其他配置項默認。 修改redis master的redis.conf daemonize yes logfile /var/log/redis.log 修改redis backup的redis.conf daemonize yes logfile /var/log/redis.log slaveof 172.30.1.22 6379
3.2.3 啓動Redis
分別啓動主從redis-server:
cd redis-2.8.19
./src/redis-server ./redis.conf
3.2.3 測試主從功能
在主機器上執行set key value:
[root@localhost redis-2.8.19]# ./src/redis-cli -p 6379
127.0.0.1:6379> set nosql redis
OK
127.0.0.1:6379>
在從機器上執行get key:
[root@localhost redis-2.8.19]# ./src/redis-cli -p 6379
127.0.0.1:6379> get nosql
"redis"
127.0.0.1:6379>
OK,測試正常。
3.2 主從公共腳本
3.2.1 Redis監控腳本
該腳本檢測redis的運行狀態,並在nginx進程不存在時嘗試重新啓動ngnix,如果啓動失敗則停止keepalived,準備讓其它機器接管。
/etc/keepalived/scripts/check_redis.sh:
#!/bin/bash
CHECK=`/usr/local/bin/redis-cli PING`
if [ "$CHECK" == "PONG" ] ;then
echo $CHECK
exit 0
else
echo $CHECK
service keepalived stop #可確保讓出MASTER
exit 1
fi
keepalived根據監控腳本的返回碼調整優先級:
☉如果腳本返回碼爲0,並且weight配置的值大於0,則優先級相應的增加;
☉如果腳本返回碼爲非0,並且weight配置的值小於0,則優先級相應的減少;
☉其他情況,原本配置的優先級不變,即配置文件中priority對應的值。
提示:
優先級不會不斷的提高或者降低;
可以編寫多個檢測腳本併爲每個檢測腳本設置不同的weight(在配置中列出就行);
不管提高優先級還是降低優先級,最終優先級的範圍是在[1,254],不會出現優先級小於等於0或者優先級大於等於255的情況;
在MASTER節點的 vrrp_instance 中 配置 nopreempt ,當它異常恢復後,即使它 prio 更高也不會搶佔,這樣可以避免正常情況下做無謂的切換。
以上可以做到利用腳本檢測業務進程的狀態,並動態調整優先級從而實現主備切換。
3.2.2 redis_fault.sh
vim /etc/keepalived/scripts/redis_fault.sh
# !/bin/bash
LOGFILE=/usr/local/src/redis-2.8.19/keepalived-redis-state.log
echo "[fault]" >> $LOGFILE
date >> $LOGFILE
3.2.3 redis_stop.sh
# !/bin/bash
LOGFILE=/usr/local/src/redis-2.8.19/keepalived-redis-state.log
echo "[stop]" >> $LOGFILE
date >> $LOGFILE
vim /etc/keepalived/scripts/redis_stop.sh
# !/bin/bash
LOGFILE=/usr/local/src/redis-2.8.19/keepalived-redis-state.log
echo "[stop]" >> $LOGFILE
date >> $LOGFILE
3.3 keepalived scripts for redis
爲redis配置keepalived所需要的腳本。
3.3.1 Redis Master scripts
在redis master配置:
vim/etc/keepalived/scripts/redis_master.sh
#!/bin/bash
REDISCLI="/usr/local/bin/redis-cli"
LOGFILE="/usr/local/src/redis-2.8.19/keepalived-redis-state.log"
echo "[master]" >> $LOGFILE
date >> $LOGFILE
echo "Being master...." >> $LOGFILE 2>&1
echo "Run SLAVEOF cmd ..." >> $LOGFILE
$REDISCLI SLAVEOF 172.30.1.23 6379 >> $LOGFILE 2>&1
sleep 10 #延遲10秒以後待數據同步完成後再取消同步狀態
echo "Run SLAVEOF NO ONE cmd ..." >> $LOGFILE
$REDISCLI SLAVEOF NO ONE >> $LOGFILE 2>&1
vim /etc/keepalived/scripts/redis_backup.sh
#!/bin/bash
REDISCLI="/usr/local/bin/redis-cli"
LOGFILE="/usr/local/src/redis-2.8.19/keepalived-redis-state.log"
echo "[backup]" >> $LOGFILE
date >> $LOGFILE
echo "Being slave...." >> $LOGFILE 2>&1
sleep 15 #延遲15秒待數據被對方同步完成之後再切換主從角色
echo "Run SLAVEOF cmd ..." >> $LOGFILE
$REDISCLI SLAVEOF 172.30.1.23 6379 >> $LOGFILE 2>&1
3.3.2 Redis Backup scripts
和3.3.1節的配置基本一樣,只是腳本中redis的IP爲原master主機的IP。
在redis backup配置:
vim/etc/keepalived/scripts/redis_master.sh
#!/bin/bash
REDISCLI="/usr/local/bin/redis-cli"
LOGFILE="/usr/local/src/redis-2.8.19/keepalived-redis-state.log"
echo "[master]" >> $LOGFILE
date >> $LOGFILE
echo "Being master...." >> $LOGFILE 2>&1
echo "Run SLAVEOF cmd ..." >> $LOGFILE
$REDISCLI SLAVEOF 172.30.1.22 6379 >> $LOGFILE 2>&1
sleep 10 #延遲10秒以後待數據同步完成後再取消同步狀態
echo "Run SLAVEOF NO ONE cmd ..." >> $LOGFILE
$REDISCLI SLAVEOF NO ONE >> $LOGFILE 2>&1
vim /etc/keepalived/scripts/redis_backup.sh
#!/bin/bash
REDISCLI="/usr/local/bin/redis-cli"
LOGFILE="/usr/local/src/redis-2.8.19/keepalived-redis-state.log"
echo "[backup]" >> $LOGFILE
date >> $LOGFILE
echo "Being slave...." >> $LOGFILE 2>&1
sleep 15 #延遲15秒待數據被對方同步完成之後再切換主從角色
echo "Run SLAVEOF cmd ..." >> $LOGFILE
$REDISCLI SLAVEOF 172.30.1.22 6379 >> $LOGFILE 2>&1
3.4 配置keepalived.conf
keepalived.conf樣例
global_defs {
router_id redis
}
vrrp_script chk_redis {
script "/etc/keepalived/scripts/check_redis.sh"
interval 4
weight -5
fall 3
rise 2
}
vrrp_instance VI_REDIS {
state MASTER
interface eth1
virtual_router_id 51
priority 100
advert_int 1
nopreempt
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
172.30.1.15
}
track_script {
chk_redis
}
notify_master /etc/keepalived/scripts/redis_master.sh
notify_backup /etc/keepalived/scripts/redis_backup.sh
notify_fault /etc/keepalived/scripts/redis_fault.sh
notify_stop /etc/keepalived/scripts/redsi_stop.sh
}
注意,在同一個網段內的,若爲不同的應用做高可用,不同應用使用不同的VIP,那麼vrrp_instance的名字(這裏是VI_REDIS)、virtual_router_id在不同的高可用實例必須設置不同的值區分開。否則keepalived會報如下錯誤:
Aug 11 11:28:36 localhostKeepalived_vrrp[16958]: (VI_1): received an invalid ip number count 1, expected2!
Aug 11 11:28:36 localhostKeepalived_vrrp[16958]: bogus VRRP packet received on eth1 !!!
Aug 11 11:28:36 localhostKeepalived_vrrp[16958]: VRRP_Instance(VI_1) Dropping received VRRP packet...
以上是keepalived MASTER節點配置文件/etc/keepalived/keepalived.conf的配置信息。在BACKUP節點,只需把vrrp_instance->state改爲BACKUP,vrrp_instance->priority改爲99即可。
在默認的keepalive.conf裏面還有 virtual_server,real_server 這樣的配置,我們這用不到,它是爲lvs準備的。 notify 可以定義在切換成MASTER或BACKUP時執行的腳本,如有需求請自行google。
配置選項說明
global_defs
☉notification_email: keepalived在發生諸如切換操作時需要發送email通知地址,後面的 smtp_server 相比也都知道是郵件服務器地址。也可以通過其它方式報警,畢竟郵件不是實時通知的。
☉router_id: 機器標識,通常可設爲hostname。故障發生時,郵件通知會用到
vrrp_instance
☉state : 指定instance(Initial)的初始狀態,就是說在配置好後,這臺服務器的初始狀態就是這裏指定的,但這裏指定的不算,還是得要通過競選通過優先級來確定。如果這裏設置爲MASTER,但如若他的優先級不及另外一臺,那麼這臺在發送通告時,會發送自己的優先級,另外一臺發現優先級不如自己的高,那麼他會就回搶佔爲MASTER
☉interface: 實例綁定的網卡,因爲在配置虛擬IP的時候必須是在已有的網卡上添加的,可以用ifconfig命令查看網卡。
☉mcast_src_ip: 發送多播數據包時的源IP地址,這裏注意了,這裏實際上就是在那個地址上發送VRRP通告,這個非常重要,一定要選擇穩定的網卡端口來發送,這裏相當於heartbeat的心跳端口,如果沒有設置那麼就用默認的綁定的網卡的IP,也就是interface指定的IP地址
☉virtual_router_id: 這裏設置VRID,這裏非常重要,相同的VRID爲一個組,他將決定多播的MAC地址
☉priority: 設置本節點的優先級,優先級高的爲master
☉advert_int: 檢查間隔,默認爲1秒。這就是VRRP的定時器,MASTER每隔這樣一個時間間隔,就會發送一個advertisement報文以通知組內其他路由器自己工作正常
☉authentication: 定義認證方式和密碼,主從必須一樣,樣例用的是密碼方式。
☉virtual_ipaddress: 這裏設置的就是VIP,也就是虛擬IP地址,他隨着state的變化而增加刪除,當state爲master的時候就添加,當state爲backup的時候刪除,這裏主要是有優先級來決定的,和state設置的值沒有多大關係。這裏可以設置多個虛擬IP地址,類似於一個域名可以解析對應多個IP地址。
☉track_script: 引用VRRP腳本,即在 vrrp_script 部分指定的名字。每隔vrrp_script->interval時間運行腳本,如果監控服務有異常則改變優先級,並最終引發主備切換。
vrrp_script
告訴 keepalived 在什麼情況下切換,所以尤爲重要。可以有多個 vrrp_script
☉script : 自己寫的檢測腳本。也可以是一行命令如killall-0 nginx
☉interval4 : 每4s檢測一次,這裏要大於監控腳本執行的時間,監控腳本會執行超時,☉keepalived會發送SIGTERM信號結束監控腳本的執行。
☉weight-5 : 檢測失敗(腳本返回非0)則優先級 -5
☉fall 2: 檢測連續 2 次失敗纔算確定是真失敗。會用weight減少優先級(1-255之間)
☉rise 1: 檢測 1 次成功就算成功。但不修改優先級
4.1啓動keepalived
在Redis Master和Redis Backup上將keepalived啓動
啓動keepalived:
service keepalived start
或者
/etc/init.d/keepalived start
或者
/usr/local/keepalived/sbin/keepalived -f/etc/keepalived/keepalived.conf -D
查看進程,正常會有三個進程
[root@localhost ~]# ps -ef | grepkeepalived
root 3870 1 0 14:46 ? 00:00:00 keepalived -D
root 3872 3870 0 14:46 ? 00:00:00 keepalived -D
root 3873 3870 0 14:46 ? 00:00:00 keepalived -D
root 3887 18774 0 14:46 pts/1 00:00:00 grep keepalived
[root@localhost ~]#
用ip命令查看VIP,ifconfig命令不能查看虛擬IP。
[root@localhost ~]# ip a | grep eth1
2: eth1:<BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen1000
inet 172.30.1.22/24 brd 172.30.1.255scope global eth1
inet 172.30.1.15/32 scope global eth1
[root@localhost ~]#
可以看到現在是172.30.1.22接管着VIP。
至此,Keppalived+Redis主從高可用環境已經搭建完成。客戶端訪問Redis使用VIP,或者將redis的域名解析指向VIP。
4 測試
測試時可以用命令tail -f /var/log/messages查看keepalived的日誌,查看主從機器狀態的變化,VIP的漂移等。
4.1 客戶端用VIP訪問Redis
在另一臺客戶端機器,比如172.30.1.20,用VIP登錄redis,並使用get命令獲取之前設置的[key,value].
[root@localhost redis-2.8.19]# redis-cli -h 172.30.1.15 -p 6379
172.30.1.15:6379> get nosql
"redis"
172.30.1.15:6379>
再設置一個新的[key,value].
172.30.1.15:6379> set movie ZhanLang2
OK
172.30.1.15:6379> get movie
"ZhanLang2"
172.30.1.15:6379>
測試結果正常。
4.2 測試VIP漂移
測試之前,先看下那臺機器接管這VIP
在172.30.1.22機器查看
[root@localhost ~]# ip a | grep eth1
2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
inet 172.30.1.22/24 brd 172.30.1.255 scope global eth1
inet 172.30.1.15/32 scope global eth1
[root@localhost ~]#
在172.30.1.23查看
[root@localhost ~]# ip a | grep eth1
2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
inet 172.30.1.23/24 brd 172.30.1.255 scope global eth1
[root@localhost ~]#
可見,VIP被172.30.1.22機器接管着。
現在,把172.30.1.22機器上的redis-server幹掉,再查看VIP是否還接管着:
[root@localhost ~]# pkill redis-server
[root@localhost ~]# ps -ef | grep redis-server | grep -v grep
root 7372 30964 0 13:57 pts/0 00:00:00 grep redis-server
[root@localhost ~]# ip a | grep eth1
2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
inet 172.30.1.22/24 brd 172.30.1.255 scope global eth1
[root@localhost ~]#
可見,172.30.1.22已經沒有接管VIP了。
在172.30.1.23查看下是否接管了VIP:
[root@localhost ~]# ip a | grep eth1
2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
inet 172.30.1.23/24 brd 172.30.1.255 scope global eth1
inet 172.30.1.15/32 scope global eth1
[root@localhost ~]#
可見172.30.1.23已經接管了VIP,進入MASTER狀態了。
繼續測試在VIP下的redis讀寫:
還是在客戶端172.30.1.20下執行
172.30.1.15:6379> get movie
"ZhanLang2"
172.30.1.15:6379> set director WuJing
OK
172.30.1.15:6379>
測試正常,注意,剛剛設置了一個新的[key,value],待會把172.30.1.22上的redis-server起來後,再查詢這個新的[key,value]——[director,WuJing].
現在把172.30.1.22上的redis-server啓動,keepalived也需要啓動,以爲檢測腳本check_redis.sh檢測到redis-server不在時,把keepalived也退出了,確保MASTER角色的讓出。
[root@localhost redis-2.8.19]# cd /usr/local/src/redis-2.8.19
[root@localhost redis-2.8.19]# ./src/redis-server redis.conf
[root@localhost redis-2.8.19]# ps -ef | grep redis-server | grep -v grep
root 7841 1 0 14:25 ? 00:00:00 ./src/redis-server *:6379
[root@localhost redis-2.8.19]# service keepalived start
Starting keepalived: [ OK ]
[root@localhost redis-2.8.19]# ip a | grep eth1
2: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
inet 172.30.1.22/24 brd 172.30.1.255 scope global eth1
inet 172.30.1.15/32 scope global eth1
[root@localhost redis-2.8.19]#
可見,啓動redis-server和keepalived後,172.30.1.22又重新接管了VIP,因爲172.30.1.22設置的優先級是100比172.30.1.23的優先級99要高。
在客戶端172.30.1.20下繼續測試redis的讀寫
先查詢剛剛設置的[director,WuJing]
172.30.1.15:6379> get director
"WuJing"
172.30.1.15:6379>
可以查詢到,說明數據已經同步過來了
再測試下寫數據
172.30.1.15:6379> set piaofang 4billion
OK
172.30.1.15:6379>
可見,寫redis也是正常的。
OK,現在高可用的基本功能測試已經完成。
http://www.keepalived.org/
https://github.com/acassen/keepalived
http://redisdoc.com/topic/sentinel.html
http://blog.csdn.net/l1028386804/article/details/52578080
http://mdba.cn/2015/03/06/redis%E9%AB%98%E5%8F%AF%E7%94%A8%E6%9E%B6%E6%9E%84-keepalivevip/