nginx(四) nginx+keepalived 實現主備+雙主熱備模型的高可用負載均衡代理服務

nginx(四) nginx+keepalived 實現主備+雙主熱備模型的高可用負載均衡代理服務

       在前面《nginx配置:反向代理 負載均衡 後端健康檢查 緩存》等幾篇文章中,我們配置了nginx的反向代理負載均衡WEB集羣,而在《keepalived 及 keepalived配置LVS高可用集羣》進行keepalived配置LVS高可用集羣。下面將在前文的一些基礎上,用keepalived分別實現主備模型和雙主模型的nginx反向代理服務器的高可用。

1、配置環境準備

1-1、模擬環境

1、各服務器主機系統:CentOS 6.4 x86_64

2、反向代理服務器:

node1: IP:192.168.18.241 (host name:node1.tjiyu.com);

node2: IP:192.168.18.242 (host name:node2.tjiyu.com);

VIP1:192.168.18.240;(主備模型只使用VIP1)

VIP2:192.168.18.250;

service:nginx 1.10.2 提供反向代理、負載均衡服務;

keepalived 爲nginx(VIP)提供高可用服務;

3、後端兩臺realserver:

realserver1: IP:192.168.18.251 (host name:realserver1.tjiyu,com);

realserver2: IP:192.168.18.252 (host name:realserver2.tjiyu.com);

service:nginx 1.10.2 提供WEB服務

1-2、配置前所需要的準備

      各主機需要做以下準備:

1、配置IP、關閉防火牆/SELINUX;

2、時間同步;

3、配置節點名稱(不是必須的,最好配置上,方便操作)

      在前面heartbeat v2 haresource 配置可用集羣說到的高可用集羣已有詳細介紹,這裏就不再給出了。

2、nginx和keepalived相關準備說明

       nginx可以參考《nginx配置:反向代理 負載均衡 後端健康檢查 緩存》文章,先在配置好兩臺代理服務器,使得它們都可以實現反向代理和負載均衡(注意。不用配置緩存,影響測試),分別訪問它們的IP測試正常,如下:

      Nginx根據前文配置好後,下面就不會去配置nginx了,主要是對keepalived進行配置,以及相關測試。

       Keepalived相關的原理、配置說明,可以參考《keepalived 及 keepalived配置LVS高可用集羣》;首先需要在兩臺代理服務器分別下載安裝,yum install -y keepalived就可以了。下面我們用到它裏面的一些配置,不過會重新給出並作出說明。

3、配置nginx+keepalived主備模型

      我們先來說明配置的一些細節,後面再給出完整的配置文件。一個是對nignx狀態進行監測,一個是對nginx進行管理。

3-1、配置keepalived對nignx進行監測

      配置/etc/keepalived/keepalived.conf文件使得keepalived可以對nignx進行監測,如下:

        [root@node1 ~]# cd /etc/keepalived/

        [root@node1 keepalived]# cp keepalived.conf keepalived.conf.bak

        [root@node1 keepalived]# vim keepalived.conf 

      在配置文中增加vrrp_script chk_nginx_health { script "killall -0 nginx"… }塊,定義nginx服務狀態跟蹤腳本,腳本中可以檢查nginx的狀態,如下:

      這裏我們直接用"killall -0 nginx"命令,它不會殺死nginx,只會在nginx啓動正常時返回0,停止時返回1,如下:

      然後在vrrp_instance VI_1 {track_script {… }}中調用上面定義的服務狀態跟蹤腳本,如下:

3-2、配置keepalived狀態轉換通知,以及轉換時對nignx進行管理

      自定義keepalived狀態轉換狀態變化腳本notify.sh,放到/etc/keepalived目錄下,如下:

      該腳本可以在keepalived狀態轉換時,發出郵件通知;還可以對nginx服務進行管理,如keepalived成功主節點時,啓動nginx,成爲備節點時停止nginx(主備時)或重啓nginx(雙主時),配置到vrrp_instance VI_1 {}塊中,如下:

      注意,配置的發件人用戶得是系統用戶,不存在用戶發不出郵件,得先在兩節點上添加用戶,過程如下:

[root@node1 keepalived]# useradd root_keepalived

3-3、node1上的keepalived配置

      配置node1成主節點,優先級較高(搶佔式),配置如下:

        ! Configuration File for keepalived

        global_defs { #全局配置,這裏額外的靜態路由並未添加因爲它是非必要的,除非我們在當前或特定的主機上生成特殊的靜態路由等

            notification_email { #realserver故障時通知郵件的收件人地址,可以多個

                root@localhost

            }

            notification_email_from root_keepalived #發件人信息(可以隨意僞裝,因爲郵件系統不會驗證處理髮件人信息)

            smtp_server 127.0.0.1 #發郵件的服務器(一定不可爲外部地址)

            smtp_connect_timeout 30 #連接超時時間

            router_id LVS_DEVEL #路由器的標識(可以隨便改動)

        }

         

        vrrp_script chk_nginx_health { # 定義服務狀態跟蹤腳本,腳本中可以檢查高可用服務的狀態,返回狀態碼0表示服務正常;配置調用則在vrrp_instance中的track_script段;這裏chk_nginx是定義腳本的名稱,可隨意取

            script "killall -0 nginx" #判斷命令/自己定義好的腳本路徑;#這裏killall -0 nginx不會殺死nginx,只會在nginx啓動正常時返回0,停止時返回1,返回1就會在vrrp實例定義的優先級減去下面的weight值,就表示期望這個節點爲備用狀態。

            interval 1 #每隔1秒鐘執行一次

            weight -2 #上面的命令腳本執行失敗,優先級降低2;這個值的絕對值必須大於MASTER減BACKUP定義的優先級

            fall 2 #命令/腳本執行失敗多少次纔算真的失敗

            rise 1 #命令/腳本執行成功多少次纔算真的成功

        }

         

        vrrp_instance VI_1 { #配置虛擬路由器的實例,VI_1是自定義的實例名稱

            state MASTER #初始狀態,MASTER|BACKUP,當state指定的instance的初始化狀態,在兩臺服務器都啓動以後,馬上發生競選,優先級高的成爲MASTER,所以這裏的MASTER並不是表示此臺服務器一直是MASTER

            interface eth0 #通告選舉所用端口

            virtual_router_id 51 #虛擬路由的ID號(一般不可大於255)

            priority 101 #優先級信息            #備必須更低

            advert_int 1 #VRRP通告間隔,秒

            authentication {

            auth_type PASS #認證機制

            auth_pass 5344 #密碼(儘量使用隨機)

            }

            virtual_ipaddress { #虛擬地址(VIP地址)

                192.168.18.240 

            }

            track_script {          #調用上面定義的服務狀態跟蹤腳本

                chk_nginx_health

            }

             

            #nopreempt #設置不搶佔,這裏只能設置在state爲BACKUP的節點上,而且這個節點的優先級必須別另外的高

            #preempt delay 300 #搶佔延遲,和nopreempt一樣只能用在BACKUP上,但不能和nopreempt同時使用

             

            notify_master "/etc/keepalived/notify.sh -m mb -n master -s nginx -a 192.168.18.240" #轉換爲master狀態時使用此腳本通知

            notify_backup "/etc/keepalived/notify.sh -m mb -n backup -s nginx -a 192.168.18.240" #轉換爲backup狀態時使用此腳本通知

            notify_fault "/etc/keepalived/notify.sh -m mb -n fault -s nginx -a 192.168.18.240" #轉換爲fault狀態時使用此腳本通知,如果腳本帶有參數也就是有空格必須使用引號

        }

3-4、node2上的keepalived配置

      配置node2成爲備節點,和node1h配置主要差別有兩處,一是state BACKUP,二是priority 100優先級更低,這是在搶佔模式下的配置,後面我們再說非搶佔式配置,差別不大,本配置如下:    

    ! Configuration File for keepalived

    global_defs { #全局配置,這裏額外的靜態路由並未添加因爲它是非必要的,除非我們在當前或特定的主機上生成特殊的靜態路由等

        notification_email { #realserver故障時通知郵件的收件人地址,可以多個

            root@localhost

        }

        notification_email_from root_keepalived #發件人信息(可以隨意僞裝,因爲郵件系統不會驗證處理髮件人信息)

        smtp_server 127.0.0.1 #發郵件的服務器(一定不可爲外部地址)

        smtp_connect_timeout 30 #連接超時時間

        router_id LVS_DEVEL #路由器的標識(可以隨便改動)

    }

     

    vrrp_script chk_nginx_health { # 定義服務狀態跟蹤腳本,腳本中可以檢查高可用服務的狀態,返回狀態碼0表示服務正常;配置調用則在vrrp_instance中的track_script段;這裏chk_nginx是定義腳本的名稱,可隨意取

        script "killall -0 nginx" #判斷命令/自己定義好的腳本路徑;#這裏killall -0 nginx不會殺死nginx,只會在nginx啓動正常時返回0,停止時返回1,返回1就會在vrrp實例定義的優先級減去下面的weight值,就表示期望這個節點爲備用狀態。

        interval 1 #每隔1秒鐘執行一次

        weight -2 #上面的命令腳本執行失敗,優先級降低2;這個值的絕對值必須大於MASTER減BACKUP定義的優先級

        fall 2 #命令/腳本執行失敗多少次纔算真的失敗

        rise 1 #命令/腳本執行成功多少次纔算真的成功

    }

     

    vrrp_instance VI_1 { #配置虛擬路由器的實例,VI_1是自定義的實例名稱

        state BACKUP #初始狀態,MASTER|BACKUP,當state指定的instance的初始化狀態,在兩臺服務器都啓動以後,馬上發生競選,優先級高的成爲MASTER,所以這裏的MASTER並不是表示此臺服務器一直是MASTER

        interface eth0 #通告選舉所用端口

        virtual_router_id 51 #虛擬路由的ID號(一般不可大於255)

        priority 100 #優先級信息            #備必須更低

        advert_int 1 #VRRP通告間隔,秒

        authentication {

            auth_type PASS #認證機制

            auth_pass 5344 #密碼(儘量使用隨機)

        }

        virtual_ipaddress { #虛擬地址(VIP地址)

            192.168.18.240 

        }

        track_script {          #調用上面定義的服務狀態跟蹤腳本

            chk_nginx_health

        }

         

        #nopreempt #設置不搶佔,這裏只能設置在state爲BACKUP的節點上,而且這個節點的優先級必須別另外的高

        #preempt delay 300 #搶佔延遲,和nopreempt一樣只能用在BACKUP上,但不能和nopreempt同時使用

         

        notify_master "/etc/keepalived/notify.sh -m mb -n master -s nginx -a 192.168.18.240" #轉換爲master狀態時使用此腳本通知

        notify_backup "/etc/keepalived/notify.sh -m mb -n backup -s nginx -a 192.168.18.240" #轉換爲backup狀態時使用此腳本通知

        notify_fault "/etc/keepalived/notify.sh -m mb -n fault -s nginx -a 192.168.18.240" #轉換爲fault狀態時使用此腳本通知,如果腳本帶有參數也就是有空格必須使用引號

    }

3-5、狀態轉換通知腳本notify.sh

      前面我們說過,自定義keepalived狀態轉換狀態變化腳本notify.sh,放到/etc/keepalived目錄下,如下:

        #!/bin/bash

        # description: An example of notify script

        # Usage: notify.sh -m|--mode {mm|mb} -s|--service SERVICE1,... -a|--address VIP -n|--notify {master|backup|falut} -h|--help

        contact='root@localhost'

        helpflag=0

        serviceflag=0

        modeflag=0

        addressflag=0

        notifyflag=0

        Usage() {

            echo "Usage: notify.sh [-m|--mode {mm|mb}] [-s|--service SERVICE1,...] <-a|--address VIP> <-n|--notify {master|backup|falut}>"

            echo "Usage: notify.sh -h|--help" 

        }

        ParseOptions() {

            local I=1;

            if [ $# -gt 0 ]; then

                while [ $I -le $# ]; do

                    case $1 in

                        -s|--service)

                        [ $# -lt 2 ] && return 3

                        serviceflag=1

                        services=(`echo $2|awk -F"," '{for(i=1;i<=NF;i++) print $i}'`)

                        shift 2 ;;

                        -h|--help)

                        helpflag=1

                        return 0 

                        shift 

                    ;;

                    -a|--address)

                        [ $# -lt 2 ] && return 3

                        addressflag=1

                        vip=$2

                        shift 2 

                    ;;

                    -m|--mode)

                        [ $# -lt 2 ] && return 3

                        mode=$2

                        shift 2 

                    ;;

                    -n|--notify)

                        [ $# -lt 2 ] && return 3

                        notifyflag=1

                        notify=$2

                        shift 2 

                    ;;

                    *)

                        echo "Wrong options..."

                        Usage

                        return 7 

                    ;;

                    esac 

                done

                return 0 

            fi 

        }

        #workspace=$(dirname $0)

        RestartService() {

            if [ ${#@} -gt 0 ]; then

                for I in $@; do

                    if [ -x /etc/rc.d/init.d/$I ]; then

                        /etc/rc.d/init.d/$I restart 

                    else

                        echo "$I is not a valid service..." 

                    fi 

                done 

            fi 

        }

        StopService() {

            if [ ${#@} -gt 0 ]; then

                for I in $@; do

                    if [ -x /etc/rc.d/init.d/$I ]; then

                        /etc/rc.d/init.d/$I stop 

                    else

                        echo "$I is not a valid service..." 

                    fi 

                done 

            fi 

        }

        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 

        }

        # Main Function

        ParseOptions $@

        [ $? -ne 0 ] && Usage && exit 5

        [ $helpflag -eq 1 ] && Usage && exit 0

        if [ $addressflag -ne 1 -o $notifyflag -ne 1 ]; then

            Usage

            exit 2 

        fi

        mode=${mode:-mb}

        case $notify in

        'master')

            if [ $serviceflag -eq 1 ]; then

                RestartService ${services[*]} 

            fi

            Notify master 

        ;;

        'backup')

            if [ $serviceflag -eq 1 ]; then

                if [ "$mode" == 'mb' ]; then

                    StopService ${services[*]} 

                else

                    RestartService ${services[*]} 

                fi 

            fi

            Notify backup 

        ;;

        'fault')

            Notify fault 

        ;;

        *)

            Usage

            exit 4 

        ;;

        esac

        exit 0

4、測試主備模型

1、在node1和node2上分別啓動keepalived,可以看到VIP配置到了node1上,成爲了主節點,而訪問測試也正常,如下:

2、當我們killall nginx停止node1上的nginx時,可以看到VIP流轉到node2上,即node2成爲主節點,而訪問正常,如下:

3、而接着當我們killall nginx停止node2的nginx時,可以看到VIP流轉回了node1,也即node1重新成爲主節點,而訪問也正常;注意,我們並沒有手動啓動node1上前面kil掉的nginx,這是由notify.sh在node1成功主節點時完成的,如下:

4、當我們killall keepalived停止node1上的keepalived時,可以VIP再次流轉到node2,也即node2再次成爲主節點,而訪問也正常;注意,我們查看node1上的日誌可以看到node1上的VIP被移除了,如下:

5、接着,我們重啓node1上的keepalived,發現VIP流轉回node1,即node1成爲了主節點,而之前node2作爲主節點在正常運行的,這就是搶佔式了,node1配置優先級高,恢復正常後搶佔了node2的主節點資源,如下:

6、配置非搶佔式:在配置BACKUP的node2上配置,nopreempt並且優先級比MASTER的node1高,而後我們重啓node2上的keepalived,然後停止node1上的keepalived再次使node2成爲主節點,如下:

7、接着,如上面第5步重啓node1上的keepalived,VIP依然在node2,即node2還作爲主節點在正常運行,這就是非搶佔式,如下:

8、接着,我們停止node2上的keepalived,可以看到node1成爲主節點,但VIP在node1、node2上都有,即node2沒有撤除VIP,keepalived就停止了,不過這也沒關,因爲node1配置VIP時會自己自動發出ARP,這樣報文就能轉到node1了,如下:

 

9、接着,我們重啓node2上的keepalived,可以看到node2成爲備節點,node1依然還是主節點,也沒有被搶佔,如下:

5、配置nginx+keepalived雙主模型

      我們在《keepalived 及 keepalived配置LVS高可用集羣》中說過,Keepalived工作模型總是一主多備的,而這個雙主是指兩個VIP分別對應兩個VRRP實例(也就是兩個主備同時運行),如果兩個VIP對應同一個服務,可以在前面再加DNS輪循,對就兩條DNS的A記錄,這樣可以做到scale out 橫向擴展,並且充分利用資源。

      注意,雙主最好不要配置非搶佔模式,因爲一臺故障時另一臺運行兩個VIP,當恢復時需要把一個VIP搶佔流轉回來,這樣就才能平分流量。

5-1、修改主備配置

      我們就在上面主備模型的基礎上,增加一個VRRP實例對就VIP2(192.168.18.250),但需要稍微修改前面配置,如記錄得改回node2上的搶佔模式,還有狀態轉換通知的腳本配置改"-m mm",如下:

5-2、node1上增加的配置

      直接在配置文件後面加上加一個VRRP實例配置,這個實例node1爲備節點,如下:

        vrrp_instance VI_2 { #配置虛擬路由器的實例,VI_1是自定義的實例名稱

            state BACKUP #初始狀態,MASTER|BACKUP,當state指定的instance的初始化狀態,在兩臺服務器都啓動以後>,馬上發生競選,優先級高的成爲MASTER,所以這裏的MASTER並不是表示此臺服務器一直是MASTER

            interface eth0 #通告選舉所用端口

            virtual_router_id 55 #虛擬路由的ID號(一般不可大於255)

            priority 100 #優先級信息 #備必須更低

            advert_int 1 #VRRP通告間隔,秒

            authentication {

                auth_type PASS #認證機制

                auth_pass 6675 #密碼(儘量使用隨機)

            }

            virtual_ipaddress { #虛擬地址(VIP地址)

                192.168.18.250

            }

            track_script { #調用上面定義的服務狀態跟蹤腳本

                chk_nginx_health

            }

             

            #nopreempt #設置不搶佔,這裏只能設置在state爲BACKUP的節點上,而且這個節點的優先級必須別另外的高

            #preempt delay 300 #搶佔延遲,和nopreempt一樣只能用在BACKUP上,但不能和nopreempt同時使用

             

            notify_master "/etc/keepalived/notify.sh -m mm -n master -s nginx -a 192.168.18.250" #轉換爲master狀態時使用

            此腳本通知

            notify_backup "/etc/keepalived/notify.sh -m mm -n backup -s nginx -a 192.168.18.250" #轉換爲backup狀態時使用

            此腳本通知

            notify_fault "/etc/keepalived/notify.sh -m mm -n fault -s nginx -a 192.168.18.250" #轉換爲fault狀態時使用>此腳本通知,如果腳本帶有參數也就是有空格必須使用引號

        }

5-3、node2上增加的配置

      直接在配置文件後面加上加一個VRRP實例配置,這個實例node2爲主節點,如下:

        vrrp_instance VI_2 { #配置虛擬路由器的實例,VI_1是自定義的實例名稱

            state MASTER #初始狀態,MASTER|BACKUP,當state指定的instance的初始化狀態,在兩臺服務器都啓動以後,>馬上發生競選,優先級高的成爲MASTER,所以這裏的MASTER並不是表示此臺服務器一直是MASTER

            interface eth0 #通告選舉所用端口

            virtual_router_id 55 #虛擬路由的ID號(一般不可大於255)

            priority 101 #優先級信息 #備必須更低

            advert_int 1 #VRRP通告間隔,秒

            authentication {

                auth_type PASS #認證機制

                auth_pass 6675 #密碼(儘量使用隨機)

            }

            virtual_ipaddress { #虛擬地址(VIP地址)

                192.168.18.250

            }

            track_script { #調用上面定義的服務狀態跟蹤腳本

                chk_nginx_health

            }

             

            #nopreempt #設置不搶佔,這裏只能設置在state爲BACKUP的節點上,而且這個節點的優先級必須別另外的高

            #preempt delay 300 #搶佔延遲,和nopreempt一樣只能用在BACKUP上,但不能和nopreempt同時使用

             

            notify_master "/etc/keepalived/notify.sh -m mm -n master -s nginx -a 192.168.18.240" #轉換爲master狀態時使用此

            腳本通知

            notify_backup "/etc/keepalived/notify.sh -m mm -n backup -s nginx -a 192.168.18.240" #轉換爲backup狀態時使用此

            腳本通知

            notify_fault "/etc/keepalived/notify.sh -m mm -n fault -s nginx -a 192.168.18.240" #轉換爲fault狀態時使用此>腳本通知,如果腳本帶有參數也就是有空格必須使用引號

        }

6、測試nginx+keepalived雙主模型

      我們分別重啓兩個節點上keepalived,可以看到VIP1(192.168.18.240)配置到node1上,而VIP2(192.168.18.250)配置到node2上,說明node1成爲VRRP實例1的主節點,node2成爲VRRP實例2的主節點;而訪問VIP1和VIP2都能正常,如下

 

 

       到這裏,我們完成了用keepalived分別實現主備模型和雙主模型的nginx反向代理負載均衡服務器的高可用,後面有時間將會在本文件的基礎上進行nginx+tomcat的動靜分離配置……

 

 

【參考資料】

1、nginx官網文檔:http://nginx.org/en/docs/

2、keepalived官網文檔:http://www.keepalived.org/documentation.html

3、keepalived 及 keepalived配置LVS高可用集羣:http://blog.csdn.net/tjiyu/article/details/52891835

4、nginx詳解:http://blog.csdn.net/tjiyu/article/details/53027619

5、nginx配置:反向代理 負載均衡 後端健康檢查 緩存:http://blog.csdn.net/tjiyu/article/details/53028026

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