高可用的實現(Keepalived + 虛 IP)

爲了避免服務單點,也爲了負載均衡,我們會加一層 Nginx 層。這個 Nginx 層要有多於一臺機器,不然它自身也成爲一個單點。

最初加 Nginx 層會變成這樣:

                   schaepher.com
                       +
                       |
               +-------+
               |
               v
           +---+---+          +-------+
           |       |          |       |
           | Nginx |          | Nginx |
           |       |          |       |
           +--+----+          +---+---+
              |                   |
    +---------+---+-------------+-+-----------+
    |             |             |             |
    v             v             v             v
+---+----+    +---+----+    +---+----+    +---+----+
|        |    |        |    |        |    |        |
| Real   |    | Real   |    | Real   |    | Real   |
| Server |    | Server |    | Server |    | Server |
|        |    |        |    |        |    |        |
+--------+    +--------+    +--------+    +--------+

如果有一臺 Real Server 發生故障,則 Nginx 就不會轉發到故障的機器,保證服務正常進行。

但是如果主 Nginx 故障了呢?

故障切換的五種方式

  • 客戶端自己配置多個 Nginx IP,故障時自己切換。

    優點:

    • 後端不需要做調整

    缺點:

    • 客戶端要自己維護 IP 列表。
    • 客戶端要實現一套應對故障的邏輯。
    • 不能用於用戶和服務之間,只能用於服務與服務之間。
  • 單一服務的情況下,把另一臺 Nginx 服務器的 IP 發給用戶,讓用戶訪問這個 IP。

    優點:

    • 簡單

    缺點:

    • 只有內部系統用戶纔可能接受這種做法。面向外部用戶的時候,外部用戶不會接受。
  • 運維人員手動修改 DNS 解析,將域名解析到另一臺 Nginx 服務器。或者程序定期檢測,發現有問題就自動發起修改 DNS 解析的請求。

    解決了什麼問題?

    • 用戶需要手動修改 hosts 或者需要切換 URL 的問題。

    沒有解決什麼問題?

    • 在 DNS 解析生效之前,服務完全不可用。
    • 客戶端會緩存 DNS 解析,也要等客戶端緩存過期。
  • 將域名解析到所有 Nginx 服務器。程序定期做檢測,當發現有問題的時候發起請求,讓 DNS 將故障的 IP 移除掉。

    DNSPod 自帶這個功能

    解決了什麼問題?

    • 在 DNS 解析生效之前,服務完全不可用的問題。

    沒有解決什麼問題?

    • 仍然有部分用戶無法訪問服務。
  • 使用虛 IP(Virtual IP Address,以下稱爲 VIPA)。域名固定解析到這個 IP,當 VIPA 所在服務器故障時,讓 VIPA 自動漂移到另一臺服務器。

    解決了什麼問題?

    • 不需要修改 DNS 解析,秒級別的生效延遲。
    • 用戶無感知。

    帶來了什麼問題?

    • 多了一個故障點,即使得 VIPA 自動漂移的那個程序,如 Keepalived。
    • 需要額外申請一個 IP 作爲 VIPA 。
    • 涉及存儲的時候,由於切換速度很快,可能會導致數據不一致。

VIP 是什麼

全稱爲 VIPA(Virtual IP Address),虛擬 IP 地址。

通常一個 IP 只能綁定在某臺機器的一個網卡上。一旦這臺機器故障,根據 IP 找到這臺機器的請求就會得不到響應。

正常
     schaepher.com
     192.168.1.101
           +
           |
           |
           |
           v

    +---------------+        +---------------+
    |               |        |               |
    | 192.168.1.101 |        | 192.168.1.102 |
    |               |        |               |
    +---------------+        +---------------+

故障
     schaepher.com
     192.168.1.101
           +
           +
             +-+ 不通
           |
           v
          故障
    +---------------+        +---------------+
    |               |        |               |
    | 192.168.1.101 |        | 192.168.1.102 |
    |               |        |               |
    +---------------+        +---------------+

而 VIPA 雖然最終也會配置在一臺機器上,但一旦這臺機器故障,備用機器就會把這個 IP 搶過去配置到網卡上(VIPA 漂移到備機)。這樣可以在 IP 不變的情況下,讓請求轉移到正常的機器,減少服務故障時間。

正常
     schaepher.com
     192.168.1.100(VIPA)
           +
           |
           |
           |
           v

    +---------------+        +---------------+
    | 192.168.1.100 |        |               |
    | 192.168.1.101 |        | 192.168.1.102 |
    |               |        |               |
    +---------------+        +---------------+

故障
     schaepher.com
     192.168.1.100(VIPA)
           +
           |
           +-------------------------+
                                     |
                                     v
          故障
    +---------------+        +---------------+
    |               |        | 192.168.1.100 |
    | 192.168.1.101 |        | 192.168.1.102 |
    |               |        |               |
    +---------------+        +---------------+

而 Keepalive 則是實現 VIPA 漂移的一種工具。

另一種是比較複雜的 Heartbeat。

Keepalived

Keepalived 實現 VIPA 漂移的基礎是 VRRP 協議。

VRRP 最早用於路由器,將多臺路由器設備虛擬成一臺路由器。每臺設備都有一個角色。角色有兩種 Master 和 Backup。Master 會持有虛 IP。每臺設備都有一個權重,權重最高的正常設備會被選舉爲 Master。

現在 Keepalived 實現了 VRRP 協議,使得可以將其用在其他設備上。

將 Keepalived 安裝在一組設備上,它們之間會互相通信來檢測狀態。如果發現 Master 超過一定時間沒有反應,則重新選舉 Master。

Master 可能直接故障沒有反應,也可能只是服務出現問題。如果是後一種情況,需要主動關閉 Keepalived 進程。

以下展示配置文件。

IP 所屬 角色
192.168.1.100 Master
192.168.1.101 主機 A Master
192.168.1.102 主機 B Backup

192.168.1.101 - 主機 A - Master

/etc/keepalived/keepalived.conf

! Configuration File for keepalived

global_defs {
    script_user root
    router_id LVS_DEVEL
    vrrp_skip_check_adv_addr
    vrrp_strict     # 嚴格模式使得無法使用 unicast_peer 配置,好處是無需指定其他機器的 IP
    vrrp_garp_interval 0
    vrrp_gna_interval 0
}

vrrp_script chk_http_port {
    script "/etc/keepalived/chk_nginx.sh"   # 檢測當前機器的服務是否故障,如果故障則關閉 keepalived
    interval 2
    weight -5
    fall 2
    rise 1
}

vrrp_instance VI_1 {
    state MASTER    # 主備配置不一致
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass aaaaaaa   # 主備該配置必須一樣
    }
    virtual_ipaddress {
        192.168.1.100
    }
    track_script {
        chk_http_port   # 在 vrrp_script 定義的名字
    }
    notify_master "/etc/keepalived/notify.sh 192.168.1.100 master"  # 當這臺機器成爲 Master 時發送通知
    notify_backup "/etc/keepalived/notify.sh 192.168.1.100 backup"
    notify_fault  "/etc/keepalived/notify.sh 192.168.1.100 fault"
}

192.168.1.102 - 主機 B - Backup

只需改兩個配置的值

/etc/keepalived/keepalived.conf

! Configuration File for keepalived

global_defs {
    script_user root
    router_id LVS_DEVEL
    vrrp_skip_check_adv_addr
    vrrp_strict
    vrrp_garp_interval 0
    vrrp_gna_interval 0
}

vrrp_script chk_http_port {
    script "/etc/keepalived/chk_nginx.sh"
    interval 2
    weight -5
    fall 2
    rise 1
}

vrrp_instance VI_1 {
    state BACKUP    # 主備配置不一致
    interface eth0
    virtual_router_id 51
    priority 90     # 備機權重比主機低
    advert_int 1
    nopreempt       # 防止爭搶 VIPA,只有 state 設置爲 BACKUP 才能使用該選項
    authentication {
        auth_type PASS
        auth_pass aaaaaaa
    }
    virtual_ipaddress {
        192.168.1.100
    }
    track_script {
        chk_http_port
    }
    notify_master "/etc/keepalived/notify.sh 192.168.1.100 master"  # 當這臺機器成爲 Master 時發送通知
    notify_backup "/etc/keepalived/notify.sh 192.168.1.100 backup"
    notify_fault  "/etc/keepalived/notify.sh 192.168.1.100 fault"
}

/etc/keepalived/chk_nginx.sh

#!/bin/bash
if [[ -z "$(ps aux | grep "nginx: master process" | grep -v grep)" ]]; then
    systemctl restart nginx # 嘗試重啓 nginx  
    sleep 5  

    if [[ -z "$(ps aux | grep "nginx: master process" | grep -v grep)" ]]; then
        # 啓動失敗則關閉 keepalived,觸發 VIPA 漂移
        systemctl stop keepalived
    fi
fi

/etc/keepalived/notify.sh

#!/bin/bash

# contact=xxx.schaepher.com

notify() {
    vip=$1
    role=$2
    mailSubject="$(hostname) to be ${role}: ${vip} floating"
    mailBody="$(date '+%F %H:%M:%S'): vrrp transition, $(hostname changed to be ${role})"
    # echo ${mailBody} | mail -s "${mailSubject}" "${contact}"
    echo ${mailSubject} >> /var/log/keepalived.mail
    echo ${mailBody} >> /var/log/keepalived.mail
    echo "" >> /var/log/keepalived.mail
}

notify $1 $2

擴展

  • 提高利用率 由於一個 VIPA 只能配置在一臺機器上,如果共有兩臺機器,則浪費了 50% 的資源。
    如果要提高資源的利用率,可以再申請一個 VIPA。把備機配置爲 Master,把主機配置爲 Backup。

  • VIPA 爭搶
    由於 nopreempt 只能配置在 BACKUP 上,如果 state 爲 MASTER 的機器故障並恢復,則會把 VIPA 搶過去。
    整個過程是:

    1. 主機 A 故障
    2. VIPA 漂移到主機 B
    3. 主機 A 恢復
    4. VIPA 漂移到主機 A

    這樣就會導致第四步多漂移了一次。而漂移可能會對服務有很短暫的影響。如果希望主機 A 恢復後,仍然讓主機 B 持有 VIPA,則要在主機的 Keepalived 啓動之前修改配置中的 state,改爲 BACKUP。

  • 避免丟包
    在 VIPA 漂移到備機之間,短暫的時間內數據包仍然會發送到主機。如果主機能夠連上,則可以使用防火牆將數據包轉發到備機。然後停止 Keepalived 。

    iptables -F
    iptables -t nat -I PREROUTING -i eth0 -j DNAT --to-destination 192.168.1.102
    iptables -t nat -I POSTROUTING -o eth0 -j MASQUERADE
    
  • 數據庫的問題
    數據庫如果使用雙主,在 VIPA 切換的時候,數據可能未同步完成,可能會造成自增 ID 衝突。
    可以配置 Keepalived 等一段時間後再發送 ARP 請求,以此等待同步完成。
    配置項是:vrrp_garp_master_delay 10 表示延遲 10 秒返送。

參考

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