keepalived實現服務高可用

環境說明

    系統: centos 7.4
    軟件: keepalived: 1.3.5  nginx: 1.10.2  tcpdump工具
    主機:192.168.9.222  192.168.9.223 
    vip地址: 192.168.9.151

keepalived說明

  Keepalived軟件主要是通過VRRP協議實現高可用功能的。VRRP是Virtual Router RedundancyProtocol(虛擬路由器冗餘協議)的縮寫,VRRP出現的目的就是爲了解決靜態路由單點故障問題的,它能夠保證當個別節點宕機時,整個網絡可以不間斷地運行。

1、keepalived服務的三個重要功能

  管理LVS負載均衡軟件
  實現LVS集羣節點的健康檢查中
  作爲系統網絡服務的高可用性(failover)

1.2、Keepalived高可用故障轉移原理

  keepalived高可用服務對主機之間的故障切換轉移是通過vrrp (虛擬路由冗餘協議)來實現的, 當keepalived主正常工作時,主節點會不停的備節點發送(多播)心跳信息證明還存活,當主web發送故障就無法發送心跳信息,這裏keeplaived會將資源vip切換到備節點,但當主節點又活過來之後,備節點會釋放自己的資源給主節點,恢復原來的角色。

1.3、keepalived工作原理

keepalived是通過vrrp協議進行通信的,我們首先需要先了解一下vrrp協議的信息
    1)vrrp 虛擬路由冗餘協議,vrrp最早是爲了解決路由單機故障而出現;
    2)vrrp是通過一種竟選協議機制來將路由任務交給某臺vrrp rs的;
    3)vrrp是通過多播的方式實現高可用對之間通信;
    4)備節點可以有多個通過優先級競選,但一般keepalived系統運維工作都是一對;避免競爭產生的問題;
    5)vrrp使用了加密協議加密數據,但keepalived官方目前還是推薦用明文的方式配置認證類型和密碼

2、安裝及配置

2.1、keepalived安裝

# 安裝keepalived   這裏兩臺機器都需要安裝   
# 實驗基於 keepalived+nginx
Host# yum -y install keepalived libnl3-devel ipset-devel nginx 

# 查看安裝的相關包
Host# rpm -ql keepalived
/etc/keepalived
/etc/keepalived/keepalived.conf
/etc/sysconfig/keepalived
/usr/bin/genhash
/usr/lib/systemd/system/keepalived.service
/usr/libexec/keepalived
/usr/sbin/keepalived

默認配置說明

Host # cat keepalived.conf 
! Configuration File for keepalived

global_defs {
   notification_email {
     [email protected]
     [email protected]
     [email protected]
   }
   notification_email_from [email protected]
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   # 從這往上是配置郵件信息的

   router_id LVS_DEVEL          # 用於標識本節點的名稱
   vrrp_skip_check_adv_addr 默認是不跳過檢查。檢查收到的VRRP通告中的所有地址可能會比較耗時,設置此命令的意思是,如果通告與接收的上一個通告來自相同的master路由器,則不執行檢查(跳過檢查)。   
   vrrp_strict              #嚴格執行VRRP協議規範,此模式不支持節點單播
   vrrp_garp_interval 0     # 接口發送ARP之間的延遲
   vrrp_gna_interval 0      # 
}

vrrp_instance VI_1 {
    state MASTER            # 狀態有兩個 MASTER 主 | BACKUP 從  
    interface eth0          # 對外的網卡接口,ifconfig 或者ip addr show可查看
    virtual_router_id 51    # 虛擬路由id,每個節點設置必須一樣,相同的ID爲一組
    priority 100            # 優先級
    advert_int 1            # 主往從發送多播消息的間隔時長
    authentication {        # 認證信息
        auth_type PASS
        auth_pass 1111
    }
    virtual_ipaddress {     # 虛擬ip 可以多個,但建議一個就OK了
        192.168.200.16
        192.168.200.17
        192.168.200.18
    }
}

virtual_server 192.168.200.100 443 {    # 虛擬服務器地址 IP 對外提供服務的端口
    delay_loop 6        # 健康檢查時長 單位秒
    lb_algo rr          # 負載均衡算法 一般是 rr但 wlc 
    lb_kind NAT         # 負載均衡轉發規則,一般用dr,nat調度器會有瓶頸問題
    persistence_timeout 50  # http服務會話時長 單位秒
    protocol TCP        # 協議 tcp

    real_server 192.168.201.100 443 {   # 真實的對外提供服務的地址跟IP
        weight 1    # 權重 權重越高轉發優先級越高
        SSL_GET {        # HTTP_GET | SSL_GET | TCP_CHECK
            url {
                path /index.html
                digest e93e7f6cfbc7c343707f21e2f681dd31
            }
            connect_timeout 3   # 服務連接端口
            nb_get_retry 3      # 服務連接失敗重試次數
            delay_before_retry 3    # 重試連接間隔 單位 秒
        }
    }
}

相關拓展:關於HTTP_GET | SSL_GET | TCP_CHECK 用法

2.2、配置

真實使用配置 
! Configuration File for keepalived

global_defs {
   notification_email {
     [email protected]
     [email protected]
     [email protected]
   }
   notification_email_from [email protected]
   smtp_server 192.168.200.1
   smtp_connect_timeout 30
   router_id keepalived
   vrrp_skip_check_adv_addr
   vrrp_strict
   vrrp_garp_interval 0
   vrrp_gna_interval 0
}

vrrp_instance VI_1 {
    state MASTER
    interface ens160
    virtual_router_id 222
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 123456
    }
    virtual_ipaddress {
        192.168.9.151
    }
}

virtual_server 192.168.9.151 80 {
    delay_loop 60
    lb_algo rr
    lb_kind DR
    persistence_timeout 50
    protocol TCP

    real_server 192.168.9.222 8080 {       兩臺真實主機
        weight 1
        HTTP_GET {
            url {
              path /
              digest 0b03c354bbc6af44b42712a6f6497dc8
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }
    real_server 192.168.9.223 8080 {
        weight 1
        HTTP_GET {
            url {
              path /
              digest 78d47efe7fe7916ee20e034bfe24c5b7
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }
}

keepalived]# genhash -s 192.168.9.222 -p 8080 -u /index.html
MD5SUM = 0b03c354bbc6af44b42712a6f6497dc8

將這個獲取到的值填到 digest xxxxxxxxxxxxxx中

Host# scp keepalived.conf [email protected]:/etc/keepalived/
備節點保需要更改一下接口地址、優先級、狀態爲BACKUP備節點 其它跟主節點保持一致
vrrp_instance VI_1 {
    state BACKUP
    interface ens160
    virtual_router_id 222
    priority 90

兩邊都啓動nginx跟keepalived   systemctl start keepalive  systemctl start nginx

啓動Keepalived 查看接口地址
keepalived]# ip addr show | grep en
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
    inet 192.168.9.222/24 brd 192.168.9.255 scope global ens160
    inet 192.168.9.151/32 scope global ens160

2.3、檢查

此時這裏可以看到主通過Http-get獲取這個地址是否有效,
Host# tcpdump -i ens160 dst 192.168.9.223 and port 8080

keepalived實現服務高可用

此時我們在查看 nginx的日誌,發現這裏每秒也有一條記錄在查詢。
keepalived實現服務高可用

這裏delay_loop 6 太短了 我們修改一下改成60秒一次
keepalived實現服務高可用

此時通過tcpdump可以抓取到主一直在往這個組播地址 每次一秒發送一個包

Host# tcpdump -i ens160 dst 224.0.0.18

keepalived實現服務高可用

3、腦裂問題

  當兩臺主機互相無法感知對方的存在,那麼就會認爲主已經掛掉, 此時通過自身的調用機制會將vip等資源都弄過來,這樣當兩個主機都同時認爲自己是主,那麼有可能會在某一時刻同時寫給數據庫會造成死鎖的現象,也有可能會產生其它的資源爭用,更主要的是兩個一樣的ip在同一個局域網內它們兩都可能上不了網無法提供服務。

3.1、腦裂產生的原因

1)心跳線壞了
2)IP設置問題
3)心跳線之間的設備故障 (正常來說,兩個keepalived是用網線直連的方式)
4)仲裁的機器出問題了
5)iptables的設置問題,端口沒有放出來
6)心跳網卡設置的不對,軟件bug等
7)同一個keepalived的 virtual_route_id兩端設置參數不一樣也會有腦裂問題的發生

3.2、腦裂解決辦法

1)同時使用串行電纜和網線連接,同時使用兩個心跳線路(這種方式最廉價,也是最有效的)
2)使用stonith,feyce設備檢測當有設備腦裂時強制重啓機器,或者斷電(需要採購設備成本)
3)做好腦裂的解決,發現問題第一時間介入仲裁,但如果使用人工干預的方式的話 會造成一定的損失,如果可容忍那就可以採用這種方式(可以寫腳本,但人工干預會很慢,比如凌晨4點半。)

3.3、腦裂解決方案

3.3.1、使用zabbix監控

  此處略過..待更新

3.3.2、腦裂腳本

先附上腳本 
 Host# vim check_nginx.sh 
#!/bin/bash
#
count=`ps -C nginx --no-heading | wc -l`
time=`date "+%Y-%m-%d %H-%M"`

if [ ${count} == 0 ];then

        echo "${time} -  keepalived fail " > /tmp/keepalive_status.txt
        /usr/bin/systemctl stop keepalived
else
        echo "${time} - keepalive ok" > /tmp/keepalive_status.txt
fi

# 這裏是主節點 在vrrp_instance前面增加 有這個vrrp_script 那一定就會有 執行 track_script

vrrp_script chk_http_port {
        script "/etc/keepalived/check_nginx.sh"
        interval 1
        weight -15
        fall 3
}

vrrp_instance VI_1 {
    state MASTER
    interface ens160
    virtual_router_id 222
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 123456
    }
    virtual_ipaddress {
        192.168.9.151
    }

    track_script {
        chk_http_port
    }
}

#這裏是從節點 配置信息一致

vrrp_script chk_http_port {
    script "/etc/keepalived/check_nginx.sh"
        interval 2
    weight -15
}

vrrp_instance VI_1 {
    state BACKUP
    interface ens160
    virtual_router_id 222
    priority 90
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass 123456
    }
    virtual_ipaddress {
        192.168.9.151
    }
    track_script {
        chk_http_port
    }

重啓服務,檢查日誌 tail -f /var/log/messages
keepalived實現服務高可用

測試關閉 systemctl stop nginx
keepalived實現服務高可用

從節點,查看IP地址就自動切換過來了。
keepalived實現服務高可用

附一個V2版本腳本 
keepalived]# cat check_nginx.sh 
#!/bin/bash
#
# 檢查nginx是否正常,如果不正常,先重啓兩次,最後還是不行就直接幹掉keepalived
counts(){
    count=`ps -C nginx --no-heading | wc -l`
    for i in {1..2};do
        if [ ${count} == 0 ];then
            systemctl restart nginx
            sleep 2
        fi
    done 
}

counts
if [ counts == 0 ];then
    /usr/bin/systemctl stop keepalived
fi

3.3.3、郵件提醒

notify_master 當切換成主時發送郵件
notify_backup 切換成備時也發送郵件
notify_fault 失敗時

notify腳本

#!/bin/bash
# 
# description: An example of notify script
# 
vip=172.16.100.1
contact='root@localhost'
notify() {
  mailsubject="`hostname` to be $1: $vip floating"
  mailbody="`date '+%F %H:%M:%S'`: vrrp transition, `hostname` changed to be $1"
  echo $mailbody | mail -s "$mailsubject" $contact
}
case "$1" in
  master)
    notify master
    /etc/rc.d/init.d/nginx start
    exit 0
  ;;
  backup)
    notify backup
    /etc/rc.d/init.d/nginx stop
    exit 0
  ;;
  fault)
    notify fault
    /etc/rc.d/init.d/nginx stop
    exit 0
  ;;
  *)
    echo 'Usage: `basename $0` {master|backup|fault}'
    exit 1
  ;;
esac

將這個加到 track_script 下邊如
    track_script {
        chk_http_port
    }

  notify_master "/etc/keepalived/notify.sh master"  
  notify_backup "/etc/keepalived/notify.sh backup"  
  notify_fault "/etc/keepalived/notify.sh fault"  

FAQ

缺少這個組件: https://bugzilla.redhat.com/show_bug.cgi?id=1477572
libipset.so.3: cannot open shared object file: No such file or directory
解決: yum -y install libnl3-devel ipset-devel

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章