Keepalived——保持存活,在網絡裏的含義就是保持在線。Keepalived提供高可用和熱備的功能,用來防止單點故障的發生。redis
Keepalived實現的基礎是VRRP協議,咱們將會在這一節中簡要介紹VRRP協議的基本原理。算法
VRRP協議是爲消除在靜態缺省路由環境下的缺省路由器單點故障引發的網絡失效而設計的主備模式的協議,使得在發生故障而進行設備功能切換時能夠不影響內外數據通訊,不須要再修改內部網絡的網絡參數。VRRP協議具備IP地址備份,優先路由選擇,減小沒必要要的路由器間通訊等功能。數據庫
VRRP協議將兩臺或多臺路由器設備虛擬成一個設備,對外提供虛擬路由器IP(一個或多個),而在路由器組內部,若是實際擁有這個對外IP的路由器可以工做正常的話就是MASTER, MASTER實現針對虛擬路由器IP的各類網絡功能,如ARP請求,ICMP,以及數據的轉發等;其餘設備不擁有該IP,狀態是BACKUP,除了接收MASTER的VRRP狀態通告信息外,不執行對外的網絡功能。當主機失效時,BACKUP將接管原先MASTER的網絡功能。bash
配置VRRP協議時須要配置每一個路由器的虛擬路由器ID(VRID)和優先權值,使用VRID將路由器進行分組,具備相同VRID值的路由器爲同一個組,VRID是一個0~255的正整數;同一組中的路由器經過使用優先權值來選舉MASTER,優先權大者爲MASTER,優先權也是一個0~255的正整數。服務器
VRRP協議使用多播數據來傳輸VRRP數據,VRRP數據使用特殊的虛擬源MAC地址發送數據而不是自身網卡的MAC地址,VRRP運行時只有MASTER路由器定時發送VRRP通告信息,表示MASTER工做正常以及虛擬路由器IP(組),BACKUP只接收VRRP數據,不發送數據,若是必定時間內沒有接收到MASTER的通告信息,各BACKUP將宣告本身成爲MASTER,發送通告信息,從新進行MASTER選舉狀態。網絡
若是對外的虛擬路由器IP就是路由器自己配置的IP地址的話,該路由器始終都是MASTER;不然若是不具有虛擬IP的話,將進行MASTER選舉,各路由器都宣告本身是MASTER,發送VRRP通告信息;若是收到其餘機器的發來的通告信息的優先級比本身高,將轉回BACKUP狀態;若是優先級相等的話,將比較路由器的實際IP,IP值較大的優先權高;不過若是對外的虛擬路由器IP就是路由器自己的IP的話,該路由器始終將是MASTER,這時的優先級值爲255。負載均衡
keepalived是模塊化設計,不一樣模塊負責不一樣的功能。tcp
core:keepalived的核心,負責主進程的啓動和維護,全局配置文件的加載解析等;模塊化
check:負責healthchecker(健康檢查),包括了各類健康檢查方式,以及對應的配置文件的解析;oop
vrrp:VRRPD子進程,用來實現VRRP協議;
libipfwc:iptables(ipchains)庫,配置LVS;
libipvs*:配置LVS;
keepalived啓動後會有三個進程:
父進程:內存管理,子進程管理等等
子進程:VRRP子進程
子進程:healthchecker子進程
兩個子進程都被系統WatchDog看管,兩個子進程各自負責本身的事,healthchecker子進程負責檢查各自服務器的健康程度,若是healthchecker子進程檢查到MASTER上服務不可用了,就會通知本機上的兄弟VRRP子進程,讓他刪除通告,而且去掉虛擬IP,轉換爲BACKUP狀態。
wget http://www.keepalived.org/software/keepalived-1.2.6.tar.gz
tar zxvf keepalived-1.2.6.tar.gz
cd keepalived-1.2.6
./configure
make
make install
cp /usr/local/etc/rc.d/init.d/keepalived /etc/rc.d/init.d/
cp /usr/local/etc/sysconfig/keepalived /etc/sysconfig/
cp /usr/local/sbin/keepalived /usr/sbin/
mkdir /etc/keepalived
vi /etc/keepalived/keepalived.conf
咱們將會在下一節對Keepalived配置文件——keepalived.conf進行詳細介紹。
service keepalived start
一個功能比較完整的keepalived的配置文件,其配置文件keepalived.conf能夠包含三個文本塊:全局定義塊、VRRP實例定義塊及虛擬服務器定義塊。
有故障,發郵件報警。
在一個網絡內,它應該是惟一的。
用來分隔定義塊,所以必須成對出現。若是寫漏了,keepalived運行時,不會獲得預期的結果。因爲定義塊內存在嵌套關係,所以很容易遺漏結尾處的花括號,這點要特別注意。
指定發件人。
smtp服務器地址,能夠配置爲localhost。
指定smtp鏈接超時時間。
運行keepalived機器的一個標識。
肯定失敗切換(FailOver)包含的路由實例個數。即在有2個負載均衡器的場景,一旦某個負載均衡器失效,須要自動切換到另一個負載均衡器的實例是哪些。
至少包含一個vrrp實例。
實例名出自實例組group所包含的那些名字。
(1)實例狀態state只有MASTER和BACKUP兩種狀態,而且須要大寫這些單詞。其中MASTER爲工做狀態,BACKUP爲備用狀態。當MASTER所在的服務器失效時,BACKUP所在的系統會自動把它的狀態有BACKUP變換成MASTER;當失效的MASTER所在的系統恢復時,BACKUP從MASTER恢復到BACKUP狀態。
(2)通訊接口interface。對外提供服務的網絡接口,如eth0,eth1。當前主流的服務器都有2個或2個以上的接口,在選擇服務接口時,必定要覈實清楚。
(3)lvs_sync_daemon_inteface。負載均衡器之間的監控接口,相似於HA HeartBeat的心跳線。但它的機制優於Heartbeat,由於它沒有「裂腦」這個問題,它是以優先級這個機制來規避這個麻煩的。【腦裂:在「雙機熱備」高可用(HA)系統中,當聯繫2個節點的「心跳線」斷開時,原本爲一總體、動做協調的HA系統,就分裂成爲2個獨立的個體。因爲相互失去了聯繫,都覺得是對方出了故障,2個節點上的HA軟件像「裂腦人」同樣,「本能」地爭搶「共享資源」、爭起「應用服務」,就會發生嚴重後果:或者共享資源被瓜分、2邊「服務」都起不來了;或者2邊「服務」都起來了,但同時讀寫「共享存儲」,致使數據損壞(常見如數據庫輪詢着的聯機日誌出錯)。】
(4) 虛擬路由標識virtual_router_id。這個標識是一個數字,而且同一個vrrp實例使用惟一的標識。即同一個vrrp_stance,MASTER和BACKUP的virtual_router_id是一致的,同時在整個vrrp內是惟一的。
(5)優先級priority。這是一個數字,數值愈大,優先級越高。在同一個vrrp_instance裏,MASTER 的優先級高於BACKUP。
(6) 同步通知間隔 advert_int。MASTER與BACKUP負載均衡器之間同步檢查的時間間隔,單位爲秒。
(7) 驗證authentication。包含驗證類型和驗證密碼。類型主要有PASS、AH兩種,一般使用的類型爲PASS。驗證密碼爲明文,同一vrrp實例MASTER與BACKUP 使用相同的密碼才能正常通訊。
能夠有多個地址,每一個地址佔一行,不須要指定子網掩碼。注意:這個ip必須與咱們在lvs客戶端設定的vip相一致。(開啓Keepalived服務後,能夠經過命令:ip a 來查看虛擬IP是否綁定到本機)
這個ip來自於vrrp定義塊的第「4」步,後面一個空格,而後加上端口號。定義一個vip,能夠實現多個tcp端口的負載均衡功能。
(1)delay_loop:健康檢查時間間隔,單位是秒。
(2)lb_algo:負載均衡調度算法,互聯網應用常使用wlc或rr。
(3)lb_kind:負載均衡轉發規則。通常包括DR,NAT,TUN3種。
(4)persistence_timeout:會話保持時間,單位是秒。
(5)protocol:轉發協議,通常有tcp和udp兩種。
Real_server的值包括ip地址和端口號。多個連續的真實ip,轉發的端口相同。
(1)權重weight。權重值是一個數字,數值越大,權重越高。使用不一樣的權重值的目的在於爲不一樣性能的機器分配不一樣的負載,性能較好的機器,負載分擔大些;反之,性能差的機器,則分擔較少的負載,這樣就能夠合理的利用不一樣性能的機器資源。
(2)Tcp檢查 tcp_check。
global_defs { router_id LVS_DEVEL } vrrp_script Monitor_Redis { script "/home/plat/laizy/redis/redis/script/redis_keepalive.sh" interval 1 #重複執行間隔1秒 weight -2 #當健康檢查腳本失敗後,主機權重將會-2 }
vrrp_instance VI_1 { state BACKUP #主備機狀態均設爲BASKUP,這樣才能夠作到在主機宕掉以後,其他#備機爭搶主機身份 interface em1 #綁定網卡名稱 virtual_router_id 52 priority 100 #優先級,其他備機應設置比100小的值 advert_int 1 nopreempt authentication { auth_type PASS auth_pass 1111 } notify_master /home/plat/laizy/redis/redis/script/redis_master.sh notify_backup /home/plat/laizy/redis/redis/script/redis_backup.sh track_script { Monitor_Redis #健康檢查腳本 } virtual_ipaddress { 10.0.63.251 #虛擬IP地址,能夠設置多個 } } |
#!/bin/bash time=$(date '+%Y-%m-%d %H:%M:%S' ) redispath=/home/plat/laizy/redis/redis rediscli=$redispath/redis-cli logfile=$redispath/logs/redis-state.log oldfile=$logfile'.'$(date +%Y-%m-%d --date='30 days ago') yesterdayfile=$logfile'.'$(date +%Y-%m-%d --date='1 days ago') if [ -f $yesterdayfile ] then echo "OK" else mv $logfile $yesterdayfile >> $logfile 2>&1 echo "$time [$yesterdayfile] Move yesterdayfile Success!" >> $logfile fi if [ -f $oldfile ] then rm -f $oldfile >> $logfile 2>&1 echo "$time [$oldfile] Delete Old File Success!" >> $logfile else echo "no old file" fi status=`$rediscli -h 127.0.0.1 -p 6379 info|grep role|awk -F ":" '{print $2}'` $rediscli -h 127.0.0.1 -p 6379 info > /dev/null if [ $? -eq 0 ] then echo "$time redis server is OK" >>$logfile echo The status is:$status >>$logfile else echo "$time no redis service found!" >>$logfile sleep 1 # try to found it again $rediscli -h 127.0.0.1 -p 6379 info > /dev/null if [ $? -eq 0 ] then echo "$time redis server is OK" >>$logfile echo The status is:$status >>$logfile #exit 0 else echo "$time redis server error" >>$logfile #stop keepalived /etc/init.d/keepalived stop echo "$time stop keepalived" >>$logfile fi fi |
#!/bin/sh localip=127.0.0.1 backip=10.0.63.246 port="6379"
time=$(date '+%Y-%m-%d %H:%M:%S' ) redispath=/home/plat/laizy/redis/redis rediscli=$redispath/redis-cli logfile=$redispath/logs/redis-state.log for p in $port do { echo "$time redis $p is the master port" >>$logfile #以主機身份配置Redis服務,注意,Redis支持熱配置,即在不重啓Redis的狀況 #下完成主備機身份的轉換 $rediscli -h $localip -p $p slaveof no one >>$logfile 2>&1 } done |
#!/bin/sh localip=127.0.0.1 backip=10.0.63.246 port="6379"
time=$(date '+%Y-%m-%d %H:%M:%S' ) redispath=/home/plat/laizy/redis/redis rediscli=$redispath/redis-cli logfile=$redispath/logs/redis-state.log for p in $port do { echo "$time redis $p change to $backip port" >>$logfile $rediscli -h $localip -p $p slaveof $backip $p >>$logfile 2>&1 } done |