split-brain 腦裂問題(Keepalived)

腦裂(split-brain)
指在一個高可用(HA)系統中,當聯繫着的兩個節點斷開聯繫時,原本爲一個總體的系統,分裂爲兩個獨立節點,這時兩個節點開始爭搶共享資源,結果會致使系統混亂,數據損壞。
對於無狀態服務的HA,無所謂腦裂不腦裂;但對有狀態服務(好比MySQL)的HA,必需要嚴格防止腦裂。(但有些生產環境下的系統按照無狀態服務HA的那一套去配置有狀態服務,結果可想而知...)sql

如何防止HA集羣腦裂
通常採用2個方法
1)仲裁
當兩個節點出現分歧時,由第3方的仲裁者決定聽誰的。這個仲裁者,多是一個鎖服務,一個共享盤或者其它什麼東西。數據庫

2)fencing
當不能肯定某個節點的狀態時,經過fencing把對方幹掉,確保共享資源被徹底釋放,前提是必需要有可靠的fence設備。vim

理想的狀況下,以上二者一個都不能少。
可是,若是節點沒有使用共享資源,好比基於主從複製的數據庫HA,也能夠安全的省掉fence設備,只保留仲裁。並且不少時候咱們的環境裏也沒有可用的fence設備,好比在雲主機裏。安全

那麼可不能夠省掉仲裁,只留fence設備呢?
不能夠。由於,當兩個節點互相失去聯絡時會同時fencing對方。若是fencing的方式是reboot,那麼兩臺機器就會不停的重啓。若是fencing的方式是power off,那麼結局有多是2個節點玉石俱焚,也有可能活下來一個。可是若是兩個節點互相失去聯絡的緣由是其中一個節點的網卡故障,而活下來的正好又是那個有故障的節點,那麼結局同樣是悲劇。
因此,單純的雙節點,不管如何也防止不了腦裂。bash

如何實現上面的策略
能夠本身徹底從頭開始實現一套符合上述邏輯的腳本。推薦使用基於成熟的集羣軟件去搭建,好比Pacemaker+Corosync+合適的資源Agent。Keepalived不太適合用於有狀態服務的HA,即便把仲裁和fence那些東西都加到方案裏,總以爲彆扭。服務器

使用Pacemaker+Corosync的方案也有一些注意事項
1)瞭解資源Agent的功能和原理
瞭解資源Agent的功能和原理,才能知道它適用的場景。好比pgsql的資源Agent是比較完善的,支持同步和異步流複製,而且能夠在二者以前自動切換,而且能夠保證同步複製下數據不會丟失。但目前MySQL的資源Agent就很弱了,沒有使用GTID又沒有日誌補償,很容易丟數據,仍是不要用的好,繼續用MHA吧(可是,部署MHA時務必要防範腦裂)。網絡

2)確保法定票數(quorum)
quorum能夠認爲是Pacemkaer自帶的仲裁機制,集羣的全部節點中的多數選出一個協調者,集羣的全部指令都由這個協調者發出,能夠完美的杜絕腦裂問題。爲了使這套機制有效運轉,集羣中至少有3個節點,而且把no-quorum-policy設置成stop,這也是默認值。(不少教程爲了方便演示,都把no-quorum-policy設置成ignore,生產環境若是也這麼搞,又沒有其它仲裁機制,是很危險的!)架構

可是,若是隻有2個節點該怎麼辦?異步

  • 一是拉一個機子借用一下湊足3個節點,再設置location限制,不讓資源分配到那個節點上。
  • 二是把多個不知足quorum小集羣拉到一塊兒,組成一個大的集羣,一樣適用location限制控制資源的分配的位置。

可是若是你有不少雙節點集羣,找不到那麼多用於湊數的節點,又不想把這些雙節點集羣拉到一塊兒湊成一個大的集羣(好比以爲不方便管理)。那麼能夠考慮第三種方法。
第三種方法是配置一個搶佔資源,以及服務和這個搶佔資源的colocation約束,誰搶到搶佔資源誰提供服務。這個搶佔資源能夠是某個鎖服務,好比基於zookeeper包裝一個,或者乾脆本身從頭作一個,就像下面這個例子。這個例子是基於http協議的短鏈接,更細緻的作法是使用長鏈接心跳檢測,這樣服務端能夠及時檢出鏈接斷開而釋放鎖)可是,必定要同時確保這個搶佔資源的高可用,能夠把提供搶佔資源的服務作成lingyig高可用的,也能夠簡單點,部署3個服務,雙節點上個部署一個,第三個部署在另一個專門的仲裁節點上,至少獲取3個鎖中的2個才視爲取得了鎖。這個仲裁節點能夠爲不少集羣提供仲裁服務(由於一個機器只能部署一個Pacemaker實例,不然能夠用部署了N個Pacemaker實例的仲裁節點作一樣的事情。可是,如非無可奈何,儘可能仍是採用前面的方法,即知足Pacemaker法定票數,這種方法更簡單,可靠。tcp

--------------------------------------------------------------keepalived的腦裂問題-------------------------------------------------------------------
1)解決keepalived腦裂問題
檢測思路:正常狀況下keepalived的VIP地址是在主節點上的,若是在從節點發現了VIP,就設置報警信息。腳本(在從節點上)以下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

[root@slave-ha ~]# vim split-brainc_check.sh

#!/bin/bash

# 檢查腦裂的腳本,在備節點上進行部署

LB01_VIP=192.168.1.229

LB01_IP=192.168.1.129

LB02_IP=192.168.1.130

while true

do

  ping -c 2 -W 3 $LB01_VIP &>/dev/null

    if [ $? -eq 0 -a `ip add|grep "$LB01_VIP"|wc -l` -eq 1 ];then

        echo "ha is brain."

    else

        echo "ha is ok"

    fi

    sleep 5

done

 

執行結果以下:

[root@slave-ha ~]# bash check_split_brain.sh

ha is ok

ha is ok

ha is ok

ha is ok

當發現異常時候的執行結果:

[root@slave-ha ~]# bash check_split_brain.sh

ha is ok

ha is ok

ha is ok

ha is ok

ha is brain.

ha is brain.

2)曾經碰到的一個keepalived腦裂的問題(若是啓用了iptables,不設置"系統接收VRRP協議"的規則,就會出現腦裂)
曾經在作keepalived+Nginx主備架構的環境時,當重啓了備用機器後,發現兩臺機器都拿到了VIP。這也就是意味着出現了keepalived的腦裂現象,檢查了兩臺主機的網絡連通狀態,發現網絡是好的。而後在備機上抓包:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

[root@localhost ~]#  tcpdump -i eth0|grep VRRP 

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode 

listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes 

22:10:17.146322 IP 192.168.1.54 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 160, authtype simple, intvl 1s, length 20 

22:10:17.146577 IP 192.168.1.96 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 50, authtype simple, intvl 1s, length 20 

22:10:17.146972 IP 192.168.1.54 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 160, authtype simple, intvl 1s, length 20 

22:10:18.147136 IP 192.168.1.96 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 50, authtype simple, intvl 1s, length 20 

22:10:18.147576 IP 192.168.1.54 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 160, authtype simple, intvl 1s, length 20 

22:10:25.151399 IP 192.168.1.96 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 50, authtype simple, intvl 1s, length 20 

22:10:25.151942 IP 192.168.1.54 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 160, authtype simple, intvl 1s, length 20 

22:10:26.151703 IP 192.168.1.96 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 50, authtype simple, intvl 1s, length 20 

22:10:26.152623 IP 192.168.1.54 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 160, authtype simple, intvl 1s, length 20 

22:10:27.152456 IP 192.168.1.96 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 50, authtype simple, intvl 1s, length 20 

22:10:27.153261 IP 192.168.1.54 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 160, authtype simple, intvl 1s, length 20 

22:10:28.152955 IP 192.168.1.96 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 50, authtype simple, intvl 1s, length 20 

22:10:28.153461 IP 192.168.1.54 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 160, authtype simple, intvl 1s, length 20 

22:10:29.153766 IP 192.168.1.96 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 50, authtype simple, intvl 1s, length 20 

22:10:29.155652 IP 192.168.1.54 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 160, authtype simple, intvl 1s, length 20 

22:10:30.154275 IP 192.168.1.96 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 50, authtype simple, intvl 1s, length 20 

22:10:30.154587 IP 192.168.1.54 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 160, authtype simple, intvl 1s, length 20 

22:10:31.155042 IP 192.168.1.96 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 50, authtype simple, intvl 1s, length 20 

22:10:31.155428 IP 192.168.1.54 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 160, authtype simple, intvl 1s, length 20 

22:10:32.155539 IP 192.168.1.96 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 50, authtype simple, intvl 1s, length 20 

22:10:32.155986 IP 192.168.1.54 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 160, authtype simple, intvl 1s, length 20 

22:10:33.156357 IP 192.168.1.96 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 50, authtype simple, intvl 1s, length 20 

22:10:33.156979 IP 192.168.1.54 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 160, authtype simple, intvl 1s, length 20 

22:10:34.156801 IP 192.168.1.96 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 50, authtype simple, intvl 1s, length 20 

22:10:34.156989 IP 192.168.1.54 > vrrp.mcast.net: VRRPv2, Advertisement, vrid 51, prio 160, authtype simple, intvl 1s, length 20 

 

備機能接收到master發過來的VRRP廣播,那爲何還會有腦裂現象?

接着發現重啓後iptables開啓着,檢查了防火牆配置。發現系統不接收VRRP協議。

因而修改iptables,添加容許系統接收VRRP協議的配置:

-A INPUT -i lo -j ACCEPT  

-----------------------------------------------------------------------------------------

我本身添加了下面的iptables規則:

-A INPUT -s 192.168.1.0/24 -d 224.0.0.18 -j ACCEPT       #容許組播地址通訊

-A INPUT -s 192.168.1.0/24 -p vrrp -j ACCEPT             #容許VRRP(虛擬路由器冗餘協)通訊

-----------------------------------------------------------------------------------------

 

最後重啓iptables,發現備機上的VIP沒了。

雖然問題解決了,但備機明明能抓到master發來的VRRP廣播包,卻沒法改變自身狀態。只能說明網卡接收到數據包是在iptables處理數據包以前發生的事情。

3)預防keepalived腦裂問題
     1)能夠採用第三方仲裁的方法。因爲keepalived體系中主備兩臺機器所處的狀態與對方有關。若是主備機器之間的通訊出了網題,就會發生腦裂,此時keepalived體系中會出現雙主的狀況,產生資源競爭。
     2)通常能夠引入仲裁來解決這個問題,即每一個節點必須判斷自身的狀態。最簡單的一種操做方法是,在主備的keepalived的配置文件中增長check配置,服務器週期性地ping一下網關,若是ping不通則認爲自身有問題 。
    3)最容易的是藉助keepalived提供的vrrp_script及track_script實現。以下所示:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

# vim /etc/keepalived/keepalived.conf

   ......

   vrrp_script check_local {

    script "/root/check_gateway.sh"

    interval 5

    }

   ......

 

   track_script {    

   check_local                  

   }

 

   腳本內容:

   # cat /root/check_gateway.sh

   #!/bin/sh

   VIP=$1

   GATEWAY=192.168.1.1

   /sbin/arping -I em1 -c 5 -s $VIP $GATEWAY &>/dev/null

 

   check_gateway.sh 就是咱們的仲裁邏輯,發現ping不通網關,則關閉keepalived service keepalived stop。

相關文章
相關標籤/搜索