1. 程式人生 > >Linux系統——Keepalived高可用叢集

Linux系統——Keepalived高可用叢集

#### keepalived服務的三個重要功能
1. 管理LVS負載均衡軟體
Keepalived可以通過讀取自身的配置檔案,實現通過更底層的介面直接管理LVS的配置以及控制服務的啟動,停止功能,這使得LVS的應用更加簡單方便。
2. 實現對LVS叢集節點健康檢查功能(healthcheck)
Keepalived可以通過在自身的Keepalived.conf檔案裡配置LVS的節點IP和相關引數實現對LVS的直接管理;除此之外,當LVS叢集中的某一個甚至是幾個節點伺服器同時發生故障無法提供服務時,Keepalived服務會自動將失效的節點伺服器從LVS的正常轉發佇列中清除出去,並將請求排程到別的正常節點伺服器上,從而保證終端使用者的訪問不受影響;當故障的節點伺服器被修復以後,Keepalived服務又會自動地把它們加入到正常轉發佇列中,對客戶提供服務。
3. 作為系統網路服務的高可用功能(failover)
(1)Keepalived可以實現任意兩臺主機之間,例如Master和Backup主機之間的故障轉移和自動切換,這個主機可以是普通的不能停機的業務伺服器,也可以是LVS負載均衡,Nginx反向代理這樣的伺服器。
(2)Keepalived高可用功能實現的簡單原理為,兩臺主機同時安裝好Keepalived軟體並啟動服務,開始正常工作時,由角色為Master的主機獲得所有資源並對使用者提供服務,角色為Backup的主機作為Master主機的熱備;當角色為Master的主機失效或出現故障時,角色為Backup的主機將自動接管Master主機的所有工作,包括接管VIP資源及相應資源服務;而當角色為Master的主機故障修復後,又會自動接管回它原來處理的工作,角色為Backup的主機則同時釋放Master主機失效時它接管的工作,此時,兩臺主機將恢復到最初啟動時各自的原始角色及工作狀態。
#### Keepalived高可用故障切換轉移原理
Keepalived高可用服務之間的故障切換轉移,是通過VRRP(Virtual Router Redundancy Protocol,虛擬路由器冗餘協議)來實現的。
在Keepalived服務正常工作時,主Master節點會不斷地向備節點發送(多播的方式)心跳訊息,用以告訴備Backup節點自己還活著,當主Master節點發生故障時,就無法傳送心跳訊息,備節點也就因此無法繼續檢測到來自主Master節點的心跳了,於是呼叫自身的接管程式,接管主Master節點的IP資源及服務。而當主Master節點恢復時,備Backup節點又會釋放主節點故障時自身接管的IP資源及服務,恢復到原來的備用角色。
那麼,什麼是VRRP呢?
VRRP,全稱Virtual Router Redundancy Protocol,中文名為虛擬路由冗餘協議,VRRP的出現就是為了解決靜態路由的單點故障問題,VRRP是通過一種競選機制來將路由的任務交給某臺VRRP路由器的。
VRRP早期是用來解決交換機,路由器等裝置單點故障的,下面是交換,路由的Master和Backup切換原理描述,同樣適用於Keepalived的工作原理。
在一組VRRP路由器叢集中,有多臺物理VRRP路由器,但是這多臺物理的機器並不是同時工作的,而是由一臺稱為Master的機器負責路由工作,其他的機器都是Backup。Master角色並非一成不變的,VRRP會讓每個VRRP路由參與競選,最終獲勝的就是Master。獲勝的Master有一些特權,比如擁有虛擬路由器的IP地址等,擁有系統資源的Master負責轉發傳送給閘道器地址的包和響應ARP請求。
VRRP通過競選機制來實現虛擬路由器的功能,所有的協議報文都是通過IP多播(Multicast)包(預設的多播地址224.0.0.18)形式傳送的。虛擬路由器由VRID(範圍0-225)和一組IP地址組成,對外表現為一個周知的MAC地址:00-00-5E-00-01-{VRID}。所以,在一個虛擬路由器中,不管誰是Master,對外都是相同的MAC和IP(稱之為VIP)。客戶端主機並不需要因Master的改變而修改自己的路由配置。對他們來說,這種切換是透明的。
在一組虛擬路由器中,只有作為Master的VRRP路由器會一直髮送VRRP廣播包(VRRP Advertisement messages),此時Backup不會搶佔Master。當Master不可用時,Backup就收不到來自Master的廣播包了,此時多臺Backup中優先順序最高的路由器會搶佔為Master。這種搶佔是非常快速的(可能只有1秒甚至更少),以保證服務的連續性。出於安全性考慮,VRRP資料包使用了加密協議進行了加密。
Keepalived高可用之間是通過VRRP通訊的,因此,我從VRRP開始給您講起:

VRRP也就是虛擬路由冗餘協議,它的出現就是為了解決靜態路由的單點故障。
VRRP是通過一種競選協議機制來將路由任務交給某臺VRRP路由器的。
VRRP用IP多播的方式(預設多播地址(224.0.0.18))實現高可用之間通訊。
工作時主節點發包,備節點接包,當備節點接收不到主節點發的資料包的時候,就啟動接管程式接管主節點的資源。備節點可以有多個,通過優先順序競選,但一般Keepalived系統運維工作中都是一對。
VRRP使用了加密協議加密資料,但Keepalived官方目前還是推薦用明文的方式配置認證型別和密碼。
介紹完了VRRP,接下來我再介紹一下Keepalived服務的工作原理:

Keepalived高可用之間是通過VRRP進行通訊的,VRRP是通過競選機制來確定主備的,主的優先順序高於備,因此,工作時主會優先獲得所有的資源,備節點處於等待狀態,當主掛了的時候,備節點就會接管主節點的資源,然後頂替主節點對外提供服務。
在Keepalived服務之間,只有作為主的伺服器會一直髮送VRRP廣播包,告訴備它還活著,此時備不會搶佔主,當主不可用時,即備監聽不到主傳送的廣播包時,就會啟動相關服務接管資源,保證業務的連續性。接管速度最快可以小於1秒。
#### Keepalived高可用服務搭建準備
環境部署
nginx_master 192.168.239.129 keepalived主伺服器(主負載均衡)
nginx_slave 192.168.239.128 keepalived備伺服器(備負載均衡)
web01 192.168.239.130 web01伺服器
web02 192.168.239.131 web02伺服器

在兩臺負載均衡伺服器上先新增一塊網絡卡eth1(僅主機NAT1模式)

```

[[email protected] ~]# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:f9:ab:90 brd ff:ff:ff:ff:ff:ff
3: eth1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
link/ether 00:0c:29:f9:ab:9a brd ff:ff:ff:ff:ff:ff
[

[email protected] ~]# cd /etc/sysconfig/network-scripts/
[[email protected] network-scripts]# ls
ifcfg-eth0 ifdown-post ifup-eth ifup-routes
ifcfg-lo ifdown-ppp ifup-ippp ifup-sit
ifdown ifdown-routes ifup-ipv6 ifup-tunnel
ifdown-bnep ifdown-sit ifup-isdn ifup-wireless
ifdown-eth ifdown-tunnel ifup-plip init.ipv6-global
ifdown-ippp ifup ifup-plusb net.hotplug
ifdown-ipv6 ifup-aliases ifup-post network-functions
ifdown-isdn ifup-bnep ifup-ppp network-functions-ipv6
[[email protected] network-scripts]# cp ifcfg-eth0 ifcfg-eth1
[[email protected] network-scripts]# vim ifcfg-eth1
DEVICE=eth1
TYPE=Ethernet
ONBOOT=yes
NM_CONTROLLED=yes
BOOTPROTO=dhcp
[[email protected] network-scripts]# ifup eth1

Determining IP information for eth1... done.
#兩臺nginx伺服器都啟動網絡卡eth1後進行測試
[[email protected] network-scripts]# ping 192.168.239.128
PING 192.168.239.128 (192.168.239.128) 56(84) bytes of data.
64 bytes from 192.168.239.128: icmp_seq=1 ttl=64 time=0.459 ms
64 bytes from 192.168.239.128: icmp_seq=2 ttl=64 time=0.483 ms
64 bytes from 192.168.239.128: icmp_seq=3 ttl=64 time=0.206 ms
```

1. 安裝keepalived軟體
在nginx_master和nginx_slave伺服器上同時安裝
```
[[email protected] ~]# mount /dev/sr0 /media/cdrom
mount: block device /dev/sr0 is write-protected, mounting read-only
[[email protected] ~]# yum -y install keepalived

```
2. 啟動keepalived服務並檢查

```
[[email protected] ~]# /etc/init.d/keepalived start
Starting keepalived: [ OK ]
[[email protected] ~]# ps -ef | grep keep | grep -v grep
root 1381 1 0 21:46 ? 00:00:00 /usr/sbin/keepalived -D
root 1383 1381 0 21:46 ? 00:00:00 /usr/sbin/keepalived -D
root 1384 1381 0 21:46 ? 00:00:00 /usr/sbin/keepalived -D
[[email protected] ~]# ip add | grep 192.168
inet 192.168.239.129/24 brd 192.168.239.255 scope global eth0
inet 192.168.200.16/32 scope global eth0
inet 192.168.200.17/32 scope global eth0
inet 192.168.200.18/32 scope global eth0
[[email protected] ~]# /etc/init.d/keepalived stop
Stopping keepalived: [ OK ]

```
3. Keepalived配置檔案說明

```
[[email protected] ~]# ls -l /etc/keepalived/keepalived.conf
-rw-r--r--. 1 root root 3562 Mar 19 2015 /etc/keepalived/keepalived.conf

```
這裡的具備高可用功能的Keepalived.conf配置檔案包含了兩個重要區塊,下面會分別說明

(1)全域性定義(Global Definitions)部分

這部分主要用來設定Keepalived的故障通知機制和Router ID標識。示例程式碼如下:

```
[[email protected] ~]# head -13 /etc/keepalived/keepalived.conf | cat -n
1 ! Configuration File for keepalived
2
3 global_defs {
4 notification_email {
5 [email protected] #郵箱
6 [email protected]
7 [email protected]
8 }
9 notification_email_from [email protected] #發件人郵箱地址
10 smtp_server 192.168.239.1 #郵件伺服器的IP地址
11 smtp_connect_timeout 30
12 router_id LVS_DEVEL #真實路由地址,要求主備的路由地址不能一樣
13 }
#基礎引數說明:

第1行是註釋,!開頭和#號開發一樣,都是註釋。
第2行是空行。
第3~8行是定義服務故障報警的Email地址。作用是當服務發生切換或RS節點等有故障時,發報警郵件。這幾行是可選配置,notification_email指定在Keepalived發生事件時,需要傳送的Email地址,可以有多個,每行一個。
第9行是指定傳送郵件的傳送人,即發件人地址,也是可選的配置。
第10行smtp_server指定傳送郵件的smtp伺服器,如果本機開啟了sendmail或postfix,就可以使用上面預設配置實現郵件傳送,也是可選配置。
第11行smtp_connect_timeout是連線smtp的超時時間,也是可選配置。
第4~11行所有和郵件報警相關的引數均可以不配,在實際工作中會將監控的任務交給更加擅長監控報警的Nagios或Zabbix軟體。
第12行是Keepalived伺服器的路由標識(router_id).在一個區域網內,這個標識(router_id)應該是唯一的。
大括號“{}”。用來分隔區塊,要成對出現。如果漏寫了半個大括號,Keepalived執行時,不會報錯,但也不會得到預期的結果。另外,由於區塊間存在多層巢狀關係,因此很容易遺漏區塊結尾處的大括號,要特別注意。
```
(2)VRRP例項定義區塊(VRRP instance(s))部分

```
[[email protected] ~]# sed -n '15,30{=;p}' /etc/keepalived/keepalived.conf | xargs -L2
15 vrrp_instance VI_1 { #VI_1為虛擬例項的名字(主備一致)
16 state MASTER #當前配置檔案是主,備用為backup
17 interface eth1 #廣播包從哪個網絡卡介面發出
18 virtual_router_id 51 #虛擬路由id,主備一致
19 priority 100 #主優先順序高(150),備優先順序低(100)
20 advert_int 1 #每隔一秒傳送一次心跳包
21 authentication { #許可權:賬號及密碼
22 auth_type PASS
23 auth_pass 1111
24 }
25 virtual_ipaddress { #虛擬IP地址(VIP)
26 192.168.239.128
27 192.168.239.127
28 192.168.239.133
29 }
30 }
#引數說明:

第15行表示定義一個vrrp_instance例項,名字是VI_1,每個vrrp_instance例項可以認為是Keepalived服務的一個例項或者作為一個業務服務,在Keepalived服務配置中,這樣的vrrp_instance例項可以有多個。注意,存在於主節點中的vrrp_instance例項在備節點中也要存在,這樣才能實現故障切換接管。

第16行state MASTER表示當前例項VI_1的角色狀態,當前角色為MASTER,這個狀態只能有MASTER和BACKUP兩種狀態,並且需要大寫這些字元。其中MASTER為正式工作的狀態,BACKUP為備用的狀態。當MASTER所在的伺服器故障或失效時,BACKUP所在的伺服器會接管故障的MASTER繼續提供服務。

第17行interface為網路通訊介面。為對外提供服務的網路介面,如eth0,eth1。當前主流的伺服器都有2~4個網路介面,在選擇服務介面時,要搞清楚了。

第18行virtual_router_id為虛擬路由ID標識,這個標識最好是一個數字,並且要在一個keepalived.conf配置中是唯一的。但是MASTER和BACKUP配置中相同例項的virtual_router_id又必須是一致的,否則將出現腦裂問題。

第19行priority為優先順序,其後面的數值也是一個數字,數字越大,表示例項優先順序越高。在同一個vrrp_instance例項裡,MASTER的優先順序配置要高於BACKUP的。若MASTER的priority值為150,那麼BACKUP的priority必須小於150,一般建議間隔50以上為佳,例如:設定BACKUP的priority為100或更小的數值。

第20行advert_int為同步通知間隔。MASTER與BACKUP之間通訊檢查的時間間隔,單位為秒,預設為1.

第21~24行authentication為許可權認證配置。包含認證型別(auth_type)和認證密碼(auth_pass)。認證型別有PASS(Simple Passwd(suggested)),AH(IPSEC(not recommended))兩種,官方推薦使用的型別為PASS。驗證密碼為明文方式,最好長度不要超過8個字元,建議用4位數字,同一vrrp例項的MASTER與BACKUP使用相同的密碼才能正常通訊。

第25 ~ 29 行virtual_ipaddress為虛擬IP地址。可以配置多個IP地址,每個地址佔一行,配置時最好明確指定子網掩碼以及虛擬IP繫結的網路介面。否則,子網掩碼預設是32位,繫結的介面和前面的interface引數配置的一致。注意,這裡的虛擬IP就是在工作中需要和域名繫結的IP,即和配置的高可用服務監聽的IP要保持一致!
```
#### Keepalived高可用服務單例項實戰
1. 配置Keepalived實現單例項單IP自動漂移接管
(1)事實上,網路服務的高可用功能基本原理都很簡單,就是把手動的操作自動化執行而已。當沒有配置高可用服務時,如果伺服器宕機了怎麼解決呢?無非就是找一個新伺服器,配好域名解析的那個原IP,然後搭好相應的網路服務罷了,只不過手工去實現這個過程會比較漫長,相比而言,自動化切換效率更高,效果更好,而且還可以有更多的功能,例如:傳送ARP廣播,觸發執行相關指令碼動作等。
(2)實際上也可以將高可用對的兩臺機器應用服務同時開啟,但是隻讓有VIP一端的伺服器提供服務,若主的伺服器宕機,VIP會自動漂移到備用伺服器上,此時使用者的請求直接傳送到備用伺服器上,而無需臨時啟動對應服務(事先開啟應用服務)。
##### 實戰配置Keepalived主伺服器lb01 MASTER
首先,配置lb01 MASTER的keepalived.conf配置檔案,操作步驟如下:

```
[[email protected] network-scripts]# cd /etc/keepalived/
[[email protected] keepalived]# vim keepalived.conf
#刪掉已有的所有預設配置,加入經過修改好的如下配置:
! Configuration File for keepalived

global_defs {
notification_email {
[email protected] #郵箱隨便寫
}
notification_email_from [email protected]
smtp_server 127.0.0.1 #郵件伺服器IP
smtp_connect_timeout 30
router_id lb01 #id為lb1,不能和其他Keepalived節點相同(全域性唯一)
}

vrrp_instance VI_1 { #例項名字為VI_1,相同例項的備節點名字要和這個相同
state MASTER #狀態為MASTER,備節點狀態需要為BACKUP
interface eth1 #通訊(心跳)介面為eth1,此引數備節點設定和主節點相同
virtual_router_id 51 #例項ID為51,要和備節點相同
priority 150 #優先順序為150,備節點的優先順序必須比此數字低
advert_int 1 #通訊檢查間隔時間1秒
authentication {
auth_type PASS #PASS認證型別,此引數備節點設定和主節點相同
auth_pass 1111 #密碼1111,此引數備節點設定和主節點相同
}
virtual_ipaddress {
192.168.239.120/24 dev eth0 label eth0:1 #虛擬IP,即VIP為192.168.239.120,子網掩碼為24位,繫結介面為eth0,別名為eth0:1,此引數備節點設定和主節點相同
}
}
# 主備nginx伺服器keepalived配置檔案相反
[[email protected] keepalived]# /etc/init.d/keepalived start
Starting keepalived: [ OK ]
[[email protected] keepalived]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:F9:AB:90
inet addr:192.168.239.129 Bcast:192.168.239.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fef9:ab90/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1578 errors:0 dropped:0 overruns:0 frame:0
TX packets:1067 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:137179 (133.9 KiB) TX bytes:135999 (132.8 KiB)

eth0:1 Link encap:Ethernet HWaddr 00:0C:29:F9:AB:90
inet addr:192.168.239.120 Bcast:0.0.0.0 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1

eth1 Link encap:Ethernet HWaddr 00:0C:29:F9:AB:9A
inet addr:192.168.159.128 Bcast:192.168.159.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fef9:ab9a/64 Scope:Link

檢視是否有虛擬IP 192.168.239.0

```
備用伺服器配置檔案

```
[[email protected] network-scripts]# vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
notification_email {
[email protected]
}
[email protected]
smtp_server 127.0.0.1 #郵件伺服器IP
smtp_connect_timeout 30
router_id lb02 #id為lb2,不能和其他Keepalived節點相同(全域性唯一)
}

vrrp_instance VI_1 { #例項名字為VI_1,相同例項的備節點名字要和這個相同
state SLAVE #狀態為SLAVE
interface eth1 #通訊(心跳)介面為eth1,此引數備節點設定和主節點相同
virtual_router_id 51 #例項ID為51,要和備節點相同
priority 100 #優先順序為100,備節點的優先順序必須比此數字低
advert_int 1 #通訊檢查間隔時間1秒
authentication {
auth_type PASS #PASS認證型別,此引數備節點設定和主節點相同
auth_pass 1111 #密碼1111,此引數備節點設定和主節點相同
}
virtual_ipaddress {
192.168.239.120/24 dev eth0 label eth0:1

}
[[email protected] network-scripts]# /etc/init.d/keepalived start
Starting keepalived: [ OK ]
[[email protected] network-scripts]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:6A:E0:E0
inet addr:192.168.239.128 Bcast:192.168.239.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe6a:e0e0/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1472 errors:0 dropped:0 overruns:0 frame:0
TX packets:979 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:130254 (127.2 KiB) TX bytes:128791 (125.7 KiB)

eth1 Link encap:Ethernet HWaddr 00:0C:29:6A:E0:EA
inet addr:192.168.159.129 Bcast:192.168.159.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe6a:e0ea/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
#這裡沒有eth0:1,因為lb02為BACKUP,當主節點活著的時候,它不會接管VIP 192.168.0.240
```
#### Keepalived高可用伺服器的“裂腦”問題
1. 什麼是裂腦

由於某些原因,導致兩臺高可用伺服器對在指定時間內,無法檢測到對方的心跳訊息,各自取得資源及服務的所有權,而此時的兩臺高可用伺服器對都還活著並在正常執行,這樣就會導致同一個IP或服務在兩端同時存在而發生衝突,最嚴重的是兩臺主機佔用同一個VIP地址,當用戶寫入資料時可能會分別寫入到兩端,這可能會導致伺服器兩端的資料不一致或造成資料丟失,這種情況就被稱為裂腦。
2. 導致裂腦發生的原因

一般來說,裂腦的發生,有以下幾種原因:

高可用伺服器對之間心跳線鏈路發生故障,導致無法正常通訊。
心跳線壞了(包括斷了,老化)
網絡卡及相關驅動壞了,IP配置及衝突問題(網絡卡直連)。
心跳線間連線的裝置故障(網絡卡及交換機)
仲裁的機器出問題(採用仲裁的方案)
高可用伺服器上開啟了iptables防火牆阻擋了心跳訊息傳輸
高可用伺服器上心跳網絡卡地址等資訊配置不正確,導致傳送心跳失敗。
其他服務配置不當等原因,如心跳方式不同,心跳廣播衝突,軟體BUG等。
Keepalived配置裡同一VRRP例項如果virtual_router_id兩端引數配置不一致,也會導致裂腦問題發生。
3. 解決裂腦的常見方案

在實際生產環境中,我們可以從以下幾個方面來防止裂腦問題的發生:

同時使用序列電纜和乙太網電纜連線,同時用兩條心跳線路,這樣一條線路壞了,另一個還是好的,依然能傳送心跳訊息。
當檢測到裂腦時強行關閉一個心跳節點(這個功能需特殊裝置支援,如Stonith,fence)。相當於備節點接收不到心跳訊息,通過單獨的線路傳送關機命令關閉主節點的電源。
做好對裂腦的監控報警(如郵件及手機簡訊等或值班),在問題發生時人為第一時間介入仲裁,降低損失。例如,百度的監控報警簡訊就有上行和下行的區別。報警資訊傳送到管理員手機上,管理員可以通過手機回覆對應數字或簡單的字串操作返回給伺服器,讓伺服器根據指令自動處理相應故障,這樣解決故障的時間更短。
當然,在實施高可用方案時,要根據業務實際需求確定是否能容忍這樣的損失。對於一般的網站常規業務,這個損失是可容忍的。
4. 解決Keepalived裂腦的常見方案

作為網際網路應用伺服器的高可用,特別是前端Web負載均衡器的高可用,裂腦的問題對普通業務的影響是可以忍受的,如果是資料庫或者儲存的業務,一般出現裂腦問題就非常嚴重了。因此,可以通過增加冗餘心跳線路來避免裂腦問題的發生,同時加強對系統的監控,以便裂腦發生時人為快速介入解決問題。

如果開啟防火牆,一定要讓心跳訊息通過,一般通過允許IP段的形式解決。
可以拉一條乙太網網線或者串列埠線作為主被節點心跳線路的冗餘。
開發檢測程式通過監控軟體(例如Nagios)檢測裂腦。
下面是生產場景檢測裂腦故障的一些思路:

1)簡單判斷的思想:只要備節點出現VIP就報警,這個報警有兩種情況,一是主機宕機了備機接管了;二是主機沒宕,裂腦了。不管屬於哪個情況,都進行報警,然後由人工檢視判斷及解決。

2)比較嚴謹的判斷:備節點出現對應VIP,並且主節點及對應服務(如果能遠端連線主節點看是否有VIP就更好了)還活著,就說明發生裂腦了。
#### Keepalived雙例項雙主模式配置
多例項多業務雙向主備模式,即A業務在lb01上是主模式,在lb02上是備模式,而B業務在lb01上是備模式,在lb02上是主模式
(1)主nginx的keepalived配置檔案
```
[[email protected] keepalived]# vim keepalived.conf
! Configuration File for keepalived

global_defs {
notification_email {
[email protected]
}
[email protected]
smtp_server 127.0.0.1 #郵件伺服器IP
smtp_connect_timeout 30
router_id lb02 #id為lb2,不能和其他Keepalived節點相同(全域性唯一)
}

vrrp_instance VI_1 { #例項名字為VI_1,相同例項的備節點名字要和這個相同
state SLAVE #狀態為SLAVE
interface eth1 #通訊(心跳)介面為eth1,此引數備節點設定和主節點相同
virtual_router_id 51 #例項ID為51,要和備節點相同
priority 100 #優先順序為100,備節點的優先順序必須比此數字低
advert_int 1 #通訊檢查間隔時間1秒
authentication {
auth_type PASS #PASS認證型別,此引數備節點設定和主節點相同
auth_pass 1111 #密碼1111,此引數備節點設定和主節點相同
}
virtual_ipaddress {
192.168.239.120/24 dev eth0 label eth0:1

}
vrrp_instance VI_2 {
state SLAVE
interface eth1
virtual_router_id 56
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.239.140/24 dev eth0 label eth0:2
}
}
[[email protected] keepalived]# vim keepalived.conf
[[email protected] keepalived]# /etc/init.d/keepalived restart
Stopping keepalived: [ OK ]
Starting keepalived: [ OK ]
[[email protected] keepalived]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:F9:AB:90
inet addr:192.168.239.129 Bcast:192.168.239.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fef9:ab90/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:2526 errors:0 dropped:0 overruns:0 frame:0
TX packets:1728 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:224168 (218.9 KiB) TX bytes:223958 (218.7 KiB)

eth0:1 Link encap:Ethernet HWaddr 00:0C:29:F9:AB:90
inet addr:192.168.239.120 Bcast:0.0.0.0 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1

eth0:2 Link encap:Ethernet HWaddr 00:0C:29:F9:AB:90
inet addr:192.168.239.140 Bcast:0.0.0.0 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1

eth1 Link encap:Ethernet HWaddr 00:0C:29:F9:AB:9A
inet addr:192.168.159.128 Bcast:192.168.159.255 Mask:255.255.255.0

```
(2)備nginx的keepalived配置檔案

```
[[email protected] network-scripts]# vim /etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
notification_email {
[email protected]
}
[email protected]
smtp_server 127.0.0.1 #郵件伺服器IP
smtp_connect_timeout 30
router_id lb02 #id為lb2,不能和其他Keepalived節點相同(全域性唯一)
}

vrrp_instance VI_1 { #例項名字為VI_1,相同例項的備節點名字要和這個相同
state SLAVE #狀態為SLAVE
interface eth1 #通訊(心跳)介面為eth1,此引數備節點設定和主節點相同
virtual_router_id 51 #例項ID為51,要和備節點相同
priority 100 #優先順序為100,備節點的優先順序必須比此數字低
advert_int 1 #通訊檢查間隔時間1秒
authentication {
auth_type PASS #PASS認證型別,此引數備節點設定和主節點相同
auth_pass 1111 #密碼1111,此引數備節點設定和主節點相同
}
virtual_ipaddress {
192.168.239.120/24 dev eth0 label eth0:1

}
vrrp_instance VI_2 { #例項名字為VI_1,相同例項的備節點名字要和這個相同
state MASTER #狀態為SLAVE
interface eth1 #通訊(心跳)介面為eth1,此引數備節點設定和主節點相同
virtual_router_id 56 #例項ID為56,要和備節點相同
priority 150 #優先順序為100,備節點的優先順序必須比此數字低
advert_int 1 #通訊檢查間隔時間1秒
authentication {
auth_type PASS #PASS認證型別,此引數備節點設定和主節點相同
auth_pass 1111 #密碼1111,此引數備節點設定和主節點相同
}
virtual_ipaddress {
192.168.239.140/24 dev eth0 label eth0:2

}
[[email protected] network-scripts]# /etc/init.d/keepalived restart
Stopping keepalived: [ OK ]
Starting keepalived: [ OK ]
[[email protected] network-scripts]# ifconfig
eth0 Link encap:Ethernet HWaddr 00:0C:29:6A:E0:E0
inet addr:192.168.239.128 Bcast:192.168.239.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe6a:e0e0/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:2335 errors:0 dropped:0 overruns:0 frame:0
TX packets:1582 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:207675 (202.8 KiB) TX bytes:209531 (204.6 KiB)

eth0:1 Link encap:Ethernet HWaddr 00:0C:29:6A:E0:E0
inet addr:192.168.239.120 Bcast:0.0.0.0 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1

eth0:2 Link encap:Ethernet HWaddr 00:0C:29:6A:E0:E0
inet addr:192.168.239.140 Bcast:0.0.0.0 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1

eth1 Link encap:Ethernet HWaddr 00:0C:29:6A:E0:EA
inet addr:192.168.159.129 Bcast:192.168.159.255 Mask:255.255.255.0

```
==抓取資料包命令==

```
[[email protected] ~]# tcpdump -n -i eth1 vrrp # -i 指定抓取的網絡卡 -n禁止反向解析,加快監聽速度

```
#### 解決高可用服務只針對物理伺服器的問題
預設情況下Keepalived軟體僅僅在對方機器宕機或Keepalived停掉的時候才會接管業務。但在實際工作中,有業務服務停止而Keepalived服務還在工作的情況,這就會導致使用者訪問的VIP無法找到對應的服務,那麼,如何解決業務服務宕機可以將IP漂移到備節點使之接管提供服務呢?
第一個方法:可以寫守護程序指令碼來處理。當Nginx業務有問題時,就停掉本地的Keepalived服務,實現IP漂移到對端繼續提供服務。實際工作中部署及開發的示例指令碼如下:
在nginx_master上操作

```
[[email protected] scripts]# cat check_nginx.sh
#!/bin/sh

while true
do
if [ `netstat -antup | grep nginx | wc -l` -ne 1 ];then
/etc/init.d/keepalived stop
fi
sleep 5 #每5秒檢測一次
done

#此指令碼的基本思想是若沒有80埠存在,就停掉Keepalived服務實現釋放本地的VIP。在後臺執行上述指令碼並檢查:
[[email protected] scripts]# sh check_nginx.sh &
[1] 1521
[[email protected] scripts]# ps -ef | grep check | grep -v grep
root 1521 1195 0 10:49 pts/0 00:00:00 sh check_nginx.sh

#確認Nginx以及Keepalived服務是正常的
[[email protected] scripts]# netstat -antup | grep nginx
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 1492/nginx
[[email protected] scripts]# /etc/init.d/keepalived status
keepalived (pid 1512) is running...

#然後模擬Nginx服務掛掉,看IP是否發生切換。
[[email protected] scripts]# /usr/local/nginx/sbin/nginx -s stop
[[email protected] scripts]# Stopping keepalived: [ OK ]
[[email protected] scripts]# /etc/init.d/keepalived status
keepalived is stopped
[[email protected] scripts]# netstat -antup | grep nginx

#此時,備節點已接管:
[[email protected] ~]# ip a | grep 192.168.0.240
inet 192.168.0.240/24 scope global secondary eth0:1
```
第二個方法:可以使用Keepalived的配置檔案引數觸發寫好的監測服務指令碼。首先要開發檢測服務指令碼,注意這個指令碼與上一個指令碼的不同。

```
[[email protected] scripts]# cat chk_nginx_proxy.sh
#!/bin/bash

if [ `netstat -antup | grep nginx | wc -l` -ne 1 ];then
/etc/init.d/keepalived stop
fi

[[email protected] scripts]# chmod +x chk_nginx_proxy.sh
[[email protected] scripts]# ls -l chk_nginx_proxy.sh
-rwxr-xr-x. 1 root root 102 Jul 31 10:59 chk_nginx_proxy.sh
```
此時,Keepalived服務的完整配置為:

```
[[email protected] scripts]# cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
notification_email {
[email protected]
}
notification_email_from [email protected]
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id lb01
}

vrrp_script chk_nginx_proxy { #定義vrrp指令碼,檢測HTTP埠

script "/server/scripts/chk_nginx_proxy.sh" #執行指令碼,當Nginx服務有問題,就停掉Keepalived服務
interval 2 #間隔2秒
weight 2

}

vrrp_instance VI_1 {
state MASTER
interface eth1
virtual_router_id 55
priority 150
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.0.240/24 dev eth0 label eth0:1
}

track_script {

chk_nginx_proxy #觸發檢查

}
}
```
下面測試接管結果

```
#先殺掉之前的後臺程序指令碼的執行,之後進行如下操作
[[email protected] scripts]# /usr/local/nginx/sbin/nginx
[[email protected] scripts]# netstat -antup | grep nginx
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 3937/nginx
[[email protected] scripts]# /etc/init.d/keepalived start
Starting keepalived: [ OK ]
[[email protected] scripts]# /etc/init.d/keepalived status
keepalived (pid 3949) is running...
[[email protected] scripts]# ip a | grep 192.168.0.240
inet 192.168.0.240/24 scope global secondary eth0:1
[[email protected] scripts]# /usr/local/nginx/sbin/nginx -s stop
[[email protected] scripts]# ip a | grep 192.168.0.240
[[email protected] scripts]# /etc/init.d/keepalived status
keepalived is stopped

#當停掉Nginx的時候,Keepalived 2秒鐘內會被自動停掉,VIP被釋放,由對端接管,這樣就實現了即使服務宕機也會進行IP漂移,業務切換。
```
#### 解決多組Keepalived伺服器在一個區域網的衝突問題
當在同一個區域網內部署了多組Keepalived伺服器對,而又未使用專門的心跳線通訊時,可能會發生高可用接管的嚴重故障問題。之前已經講解過Keepalived高可用功能是通過VRRP協議實現的,VRRP協議預設通過IP多播的形式實現高可用對之間的通訊,如果同一個區域網記憶體在多組Keepalived伺服器對,就會造成IP多播地址衝突問題,導致接管錯亂,不同組的Keepalived都會使用預設的224.0.0.18作為多播地址。此時的解決辦法是,在同組的Keepalived伺服器所有的配置檔案裡指定獨一無二的多播地址,配置如下:

```
global_defs {

router_id LVS_19
vrrp_mcast_group4 224.0.0.19 #這個就是指定多播地址的配置

}

#提示:
1)不同例項的通訊認證密碼也最好不同,以確保接管正常。
2)另一款高可用軟體Heartbeat,如果採用多播方式實現主備通訊,同樣會有多播地址衝突問題。
```
#### 開發檢測Keepalived裂腦的指令碼
檢測思路:在備節點上執行指令碼,如果可以ping通主節點並且備節點有VIP就報警,讓人員介入檢查是否裂腦。

1)在lb02備節點開發指令碼並執行

```
[[email protected] scripts]# cat check_split_brain.sh
#!/bin/bash

lb01_vip=192.168.0.240
lb01_ip=192.168.0.221

while true
do
ping -c 2 -W 3 $lb01_ip &>/dev/null
if [ $? -eq 0 -a `ip a | grep "$lb01_vip" | wc -l` -eq 1 ];then
echo "ha is split brain.warning."
else
echo "ha is OK"
fi
sleep 5
done
[[email protected] scripts]# sh check_split_brain.sh
ha is OK
ha is OK
ha is OK

#正常情況下,主節點活著,VIP 192.168.0.221在主節點,因此不會報警,提示“ha is OK”
```
2)停止Keepalived服務看lb02指令碼執行情況。

lb01上:

```
[[email protected] scripts]# /etc/init.d/keepalived stop
Stopping keepalived: [ OK ]
[[email protected] scripts]# ip a | grep 192.168.0.240
[[email protected] scripts]#

#在lb02上觀察即可,此前指令碼已經執行。
[[email protected] scripts]# sh check_split_brain.sh
ha is OK
ha is OK
ha is OK
ha is split brain.warning.
ha is split brain.warning.
ha is split brain.warning.
```
3)關掉lb01伺服器,然後再觀察lb02指令碼的輸出。

```
[[email protected] scripts]# sh check_split_brain.sh
ha is OK
ha is OK
ha is OK
ha is split brain.warning.
ha is split brain.warning.
ha is split brain.warning.
ha is OK
ha is OK
ha is OK

#裂腦報警恢復了。
```
4)可以將此指令碼整合到Nagios或Zabbix監控服務裡,進行監控報警。

最大可能發生裂腦的狀態:備用能ping通主伺服器,說明物理伺服器是正常的情況下,VIP發生漂移;若這種情況下,還沒發生裂腦,應該是主伺服器的nginx服務宕了 ,觸發了指令碼。