深度解析Keepalived高可用技術:打造高效、穩定的服務架構

Keepalive詳解


工作原理

Keepalived本質就是為ipvs服務的,它也不需要共享儲存。IPVS其實就是一些規則,Keepalived主要的任務就是去呼叫ipvsadm命令,來生成規則,並自動實現將使用者需要訪問的地址轉移到可用LVS節點實現。所以keepalive的高可用是屬於具有很強針對性的高可用,它和corosync這種通用性HA方案不同。
Keepalived的主要目的就是它自身啟動為一個服務,它工作在多個LVS主機節點上,當前活動的節點叫做Master備用節點叫做Backup,Master會不停的向Backup節點通告自己的心跳,這種通告是基於VRRP協議的。Backup節點一旦接收不到Master的通告資訊,它就會把LVS的VIP拿過來,並且把ipvs的規則也拿過來,在自己身上生效,從而替代Master節點
Keepalived除了可以監控和轉移LVS資源之外,它還可以直接配置LVS而不需要直接使用ipvsadm命令,因為它可以呼叫,也就是說在LVS+KEEPALIVED模型中,你所有的工作在Keepalived中配置就可以了,而且它還有對後端應用伺服器健康檢查的功能。
直接一句話Keepalived就是VRRP協議的實現,該協議是虛擬冗餘路由協議。

VRRP工作原理簡述

那麼這個VRRP協議是幹嘛用呢?傳統上來說我們透過一個路由器上網,如果故障那就不能用了,如果使用2個路由器,有一個故障你就需要手動的設定客戶端切換到另外的路由器上,或者使用ARP客戶端也可以實現,但總之部署比較麻煩不利於管理,就像下圖:
有沒有一種辦法可以自動轉移而省去手動配置呢?我們就可以透過VRRP協議來實現路由器的故障轉移。如下圖:
這裡有個問題,VRRP提供一個VIP,它可以來設定那個路由器是活動節點,然後出現故障進行切換,VIP也隨之對應到新的路由器上,但是內網是用過MAC地址來定址的,雖然VIP對應到了新的路由器上,可是MAC變了,客戶端的ARP表也沒有更新,所以還是用不了,為了解決這個問題VRRP不但提供VIP還提供VMAC地址,這個VMAC地址是VRRP單獨申請的,大家都可以正常使用。
故障切換的時候雖然改變了後端路由器,但是由於客戶端使用的是VIP和VMAC地址,這樣就不會有任何影響了。
所以Keepalived就是在Linux系統上提供了VRRP功能,當然還提供了服務監控功能,比如監控後端伺服器的健康檢查、LVS服務可用性檢查。
VRRP的工作過程是這樣的:
  1. 虛擬路由器中的路由器根據優先順序選舉出Master,Master路由器透過傳送免費ARP報文,將自己的虛擬MAC地址通告給與它連線的裝置。
  2. Master路由器週期性傳送VRRP報文,以公佈自己的配置資訊(優先順序等)和工作狀態
  3. 如果Master故障,虛擬路由器中的Backup路由器將根據優先順序重新選舉新的Master
  4. 虛擬路由器狀態切換時,Master路由器由一臺裝置切換會另外一臺裝置,新的Master路由器只是簡單的傳送一個攜帶虛擬MAC地址和虛擬IP的免費ARP報文,這樣就可以更新其他裝置中快取的ARP資訊
  5. Backup路由器的優先順序高於Master時,由Backup的工作方式(搶佔式或者非搶佔式)決定是否重新選舉Master。
VRRP還支援認證,就是為了防止隨意一個VRRP裝置加入到當前的虛擬路由組離來,它提供無認證、簡單8位字串認證和MD5認證(該認證方式Keepalive不支援)。

Keepalive軟體結構

Keepalived啟動後以後會有一個主程序Master,它會生成還有2個子程序,一個是VRRP Stack負責VRRP(也就是VRRP協議的實現)、一個是Checkers負責IPVS的後端的應用伺服器的健康檢查,當檢測失敗就會呼叫IPVS規則刪除後端伺服器的IP地址,檢測成功了再加回來。當檢測後端有失敗的情況可以使用SMTP通知管理員。另外VRRP如果檢測到另外一個Keepalive失敗也可以透過SMTP通知管理員。
Control Plane:這個就是主程序,主程序的功能是分析配置檔案,讀取、配置和生效配置檔案,指揮那2個子程序工作。
WatchDog:看門狗,這個是Linux系統核心的一個模組,它的作用是幫助主程序盯著那2個子程序,因為主程序並不負責具體工作,具體工作都是子程序完成的。如果子程序掛了,那Keepalived就不完整了,所以那2個子程序會定期的向主程序開啟的一個內部Unix Socket檔案寫心跳資訊。如果有某個子程序不寫資訊了,它就會重啟子程序,主程序就是讓WatchDog來監控子程序的。下面我們就使用Keepalive來做LVS的高可用講解。關於後端伺服器上的設定我這裡就不說了請看另外一篇博文。

Keepalive安裝和配置

伺服器 IP地址 角色
Srv01
172.16.42.100

VIP: 172.16.42.111
LVS+Keepalive
Srv02
172.16.42.101

VIP: 192.168.100.1
LVS+Keepalive
Srv03
172.16.42.102

VIP: 172.16.42.111
Nginx
Srv04
172.16.42.103

VIP: 172.16.42.111
Nginx

先決條件

  1. 停用SElinux、清除iptables規則、關閉防火牆。就算因某種原因不能清除iptables規則,那麼你需要增加一條規則放行多播
  2. 各個節點時間同步,啟用時間同步服務systemctl start chronyd
  3. 確保Keepalive使用的網絡卡開啟了多播,如下圖:
如果沒有開啟,可以使用該命令開啟ip link set multicast on dev ens33,ens33是網絡卡名稱。

安裝keepalive

之間透過yum安裝即可yum install -y keepalived。我這裡使用的是阿里雲的源,它預設就在裡面,如下圖:
在2個節點都安裝。
檔案 說明
/usr/sbin/keepalived 二進位制程式
/etc/keepalived/keepalived.conf 配置檔案
/usr/lib/systemd/system/keepalived.service 服務檔案

Keepalive配置檔案說明


# 全域性配置

global_defs {

# 郵件通知資訊

notification_email {

# 定義收件人

}

# 定義發件人

notification_email_from [email protected]

# SMTP伺服器地址

smtp_server 192.168.200.1

smtp_connect_timeout 30

# 路由器標識,一般不用改,也可以寫成每個主機自己的主機名

router_id LVS_DEVEL

# VRRP的ipv4和ipv6的廣播地址,配置了VIP的網絡卡向這個地址廣播來宣告自己的配置資訊,下面是預設值

vrrp_mcast_group4 224.0.0.18

vrrp_mcast_group6 ff02::12

}

# 定義用於例項執行的指令碼內容,比如可以線上降低優先順序,用於強制切換

vrrp_script SCRIPT_NAME {
}

# 一個vrrp_instance就是定義一個虛擬路由器的,例項名稱

vrrp_instance VI_1 {

# 定義初始狀態,可以是MASTER或者BACKUP

state MASTER

# 工作介面,通告選舉使用哪個介面進行

interface ens33

# 虛擬路由ID,如果是一組虛擬路由就定義一個ID,如果是多組就要定義多個,而且這個虛擬
# ID還是虛擬MAC最後一段地址的資訊,取值範圍0-255

virtual_router_id 51

# 使用哪個虛擬MAC地址

use_vmac XX:XX:XX:XX:XX

# 監控本機上的哪個網絡卡,網絡卡一旦故障則需要把VIP轉移出去

track_interface {

eth0

ens33

}

# 如果你上面定義了MASTER,這裡的優先順序就需要定義的比其他的高

priority 100

# 通告頻率,單位為秒

advert_int 1

# 通訊認證機制,這裡是明文認證還有一種是加密認證

authentication {

auth_type PASS

auth_pass 1111

}

# 設定虛擬VIP地址,一般就設定一個,在LVS中這個就是為LVS主機設定VIP的,這樣你就不用自己手動設定了

virtual_ipaddress {

# IP/掩碼 dev 配置在哪個網絡卡

192.168.200.16/24 dev eth1

# IP/掩碼 dev 配置在哪個網絡卡的哪個別名上

192.168.200.17/24 dev label eth1:1

}

# 虛擬路由,在需要的情況下可以設定lvs主機 資料包在哪個網絡卡進來從哪個網絡卡出去

virtual_routes {

192.168.110.0/24 dev eth2

}

# 工作模式,nopreempt表示工作在非搶佔模式,預設是搶佔模式 preempt

nopreempt|preempt

# 如果是搶佔預設則可以設定等多久再搶佔,預設5分鐘

preempt delay 300

# 追蹤指令碼,通常用於去執行上面的vrrp_script定義的指令碼內容

track_script {
}

# 三個指令,如果主機狀態變成Master|Backup|Fault之後會去執行的通知指令碼,指令碼要自己寫

notify_master

""

notify_backup

""

notify_fault

""

}

# 定義LVS叢集服務,可以是IP+PORT;也可以是fwmark 數字,也就是防火牆規則
# 所以透過這裡就可以看出來keepalive天生就是為ipvs而設計的

virtual_server 10.10.10.2 1358 {

delay_loop 6

# 演算法

lb_algo rr|wrr|lc|wlc|lblc|sh|dh

# LVS的模式

lb_kind NAT|DR|TUN

# 子網掩碼,這個掩碼是VIP的掩碼

nat_mask 255.255.255.0

# 持久連線超時時間

persistence_timeout 50

# 定義協議

protocol TCP

# 如果後端應用伺服器都不可用,就會定向到那個伺服器上

sorry_server 192.168.200.200 1358

# 後端應用伺服器 IP PORT

real_server 192.168.200.2 1358 {

# 權重

weight 1

# MSIC_CHECK|SMTP_CHEKC|TCP_CHECK|SSL_GET|HTTP_GET這些都是
# 針對應用伺服器做健康檢查的方法

MISC_CHECK {}

# 用於檢查SMTP伺服器的

SMTP_CHEKC {}

# 如果應用伺服器不是WEB伺服器,就用TCP_CHECK檢查

TCP_CHECK {

# 向哪一個埠檢查,如果不指定預設使用上面定義的埠

connect_port <PORT>

# 向哪一個IP檢測,如果不指定預設使用上面定義的IP地址

bindto <IP>

# 連線超時時間

connect_timeout 3

}

# 如果對方是HTTPS伺服器就用SSL_GET方法去檢查,裡面配置的內容和HTTP_GET一樣

SSL_GET {}

# 應用伺服器UP或者DOWN,就執行那個指令碼

notify_up

"這裡寫的是路徑,如果指令碼後有引數,整體路徑+引數引起來"

notify_down

"/PATH/SCRIPTS.sh 引數"

# 使用HTTP_GET方法去檢查

HTTP_GET {

# 檢測URL

url {

# 具體檢測哪一個URL

path /testurl/test.jsp

# 檢測內容的雜湊值

digest 640205b7b0fc66c1ea91c463fac6334d

# 除了檢測雜湊值還可以檢測狀態碼,比如HTTP的200 表示正常,兩種方法二選一即可

status_code 200

}

url {

path /testurl2/test.jsp

digest 640205b7b0fc66c1ea91c463fac6334d

}

url {

path /testurl3/test.jsp

digest 640205b7b0fc66c1ea91c463fac6334d

}

# 向哪一個埠檢查,如果不指定預設使用上面定義的埠

connect_port <PORT>

# 向哪一個IP檢測,如果不指定預設使用上面定義的IP地址

bindto <IP>

# 連線超時時間

connect_timeout 3

# 嘗試次數

nb_get_retry 3

# 每次嘗試之間間隔幾秒

delay_before_retry 3

}

}
real_server 192.168.200.3 1358 {

weight 1

HTTP_GET {

url {

path /testurl/test.jsp

digest 640205b7b0fc66c1ea91c463fac6334c

}

url {

path /testurl2/test.jsp

digest 640205b7b0fc66c1ea91c463fac6334c

}

connect_timeout 3

nb_get_retry 3

delay_before_retry 3

}

}

}

配置Srv01和Srv02

配置VRRP部分

Srv01上的keepalived.conf

global_defs {

notification_email {

}

notification_email_from [email protected]

smtp_server 127.0.0.1

smtp_connect_timeout 30

router_id srv01

}

vrrp_instance VI_1 {

state MASTER

interface ens33

virtual_router_id 51

priority 100

advert_int 1

authentication {

auth_type PASS

auth_pass 1111

}
virtual_ipaddress {

172.16.42.111/24 brd 172.16.42.111 dev ens33 label ens33:0

}

preempt delay 60

}

Srv02上的keepalived.conf,唯一不同的就是state、priority以及router_id。

global_defs {

notification_email {

}

notification_email_from [email protected]

smtp_server 127.0.0.1

smtp_connect_timeout 30

router_id srv02

}

vrrp_instance VI_1 {

state BACKUP

interface ens33

virtual_router_id 51

priority 90

advert_int 1

authentication {

auth_type PASS

auth_pass 1111

}
virtual_ipaddress {

172.16.42.111/24 brd 172.16.42.111 dev ens33 label ens33:0

}

preempt delay 60

}

啟動2個節點,啟動後會自動配置ens33:0這個子介面的虛擬IP
在主節點上你透過systemctl status keepalived看不到它到底是什麼角色,不過在BACKUP節點上你可以看到,但是你在主節點日誌中cat /var/log/message裡可以看到Srv01進入到MASTER狀態,如下圖:
檢視Srv02的狀態
那麼你透過停止Srv01上的keepalived服務就看到MASTER會被轉移到Srv02上。
使用該命令檢視VRRP通告tcpdum -i ens33 -nn host 224.0.0.18,你在2臺主機都會看到相同的資訊。
Srv01使用真實物理IP對該地址進行傳送通告,那麼Srv02也會收到,如果Srv01宕機,那麼Srv02就會使用自己的物理IP向該地址傳送通告,由於Srv01已經宕機那麼此時Srv02的優先順序就是最高的,所以Srv02就變成了MASTER。

配置LVS部分

這裡只是用了LVS來說明如何配置Keepalived,如果要看完整內容請移步使用Keepalived構建LVS高可用叢集
在keepalived.conf檔案中增加下面的內容,2臺伺服器增加的內容一致,所以這裡就寫一份。

virtual_server 172.16.42.111 80 {

delay_loop 6

lb_algo rr

lb_kind DR

nat_mask 255.255.255.0

persistence_timeout 0

protocol TCP
sorry_server 192.168.200.200 1358

# 後端應用伺服器 IP PORT

real_server 172.16.42.102 80 {

weight 1

# 應用伺服器UP或者DOWN,就執行那個指令碼

notify_up

"/usr/local/notify.sh up"

notify_down

"/usr/local/notify.sh down"

HTTP_GET {

# 檢測URL

url {

path /index.html

# 除了檢測雜湊值還可以檢測狀態碼,比如HTTP的200 表示正常,兩種方法二選一即可

status_code 200

}

connect_timeout 3

nb_get_retry 3

delay_before_retry 3

}

}
real_server 172.16.42.103 80 {

weight 1

# 應用伺服器UP或者DOWN,就執行那個指令碼

notify_up

"/usr/local/notify.sh up"

notify_down

"/usr/local/notify.sh down"

HTTP_GET {

# 檢測URL

url {

path /index.html

# 除了檢測雜湊值還可以檢測狀態碼,比如HTTP的200 表示正常,兩種方法二選一即可

status_code 200

}

connect_timeout 3

nb_get_retry 3

delay_before_retry 3

}

}

}

這裡的notify_up|down指令碼我寫的很簡單就是為了使用一下這個功能,內容如下:
#!/bin/bash

# 不同的是2個主機上的echo部分不一樣,因為主機名不同。
if

[

$1

==

"up"

];

then
echo"Srv02 is UP"

> /tmp/notify.txt

elif

[

$1

==

"down"

];

then
echo"Srv02 is DOWN"

> /tmp/notify.txt

fi

重啟Keepalived服務之後你就可以透過ipvsadm -Ln檢視ipvs規則了,這些規則在2臺伺服器上都會有,如下圖:
測試訪問
使用下面的命令快速訪問for i in {1..20}; do curl http://172.16.42.111/ | grep "Srv0" --color ; done
可以看到2臺伺服器交替,因為我們使用的rr排程演算法。

故障轉移測試

連續訪問VIP,然後停止Srv01上面的keepalived服務,這就意味著Srv01也就是失去了VIP,然後觀察請求情況以及是否觸發之前設定的指令碼。
在Srv01上檢視指令碼執行情況
檢視Srv02上面的日誌
連結:https://www.cnblogs.com/rexcheny/p/10778567.html
                                                              (版權歸原作者所有,侵刪)


相關文章