在mysql中,腦裂是指在一個高可用(HA)系統中,當聯系著的兩個節點斷開聯系時,本來為一個整體的系統,分裂為兩個獨立節點,這時兩個節點開始爭搶共享資源,結果會導致系統混亂,數據損壞。 對于無狀態服務的HA系統,無所謂腦裂不腦裂;但對有狀態服務(比如MySQL)的HA,必須要嚴格防止腦裂。
本教程操作環境:windows7系統、mysql8版本、Dell G3電腦。
腦裂(split-brain)
指在一個高可用(HA)系統中,當聯系著的兩個節點斷開聯系時,本來為一個整體的系統,分裂為兩個獨立節點,這時兩個節點開始爭搶共享資源,結果會導致系統混亂,數據損壞。?
在一個高可用性集群環境中有一個活動節點和一個或多個備用節點,當活動節點發生故障或停止響應時,它們將接管服務。
在考慮節點之間的網絡層之前,這聽起來像是一個合理的假設。 如果節點之間的網絡路徑出現故障怎么辦?
任何一個節點現在都不能與另一個節點通信,在這種情況下,備用服務器可能會在它認為活動節點發生故障的基礎上將自己提升為活動服務器。 這導致兩個節點都變得“活躍”,因為每個節點都會認為另一個節點已經死了。 結果,數據完整性和一致性受到損害,因為兩個節點上的數據都會發生變化。 這被稱為“裂腦”?.
對于無狀態服務的HA,無所謂腦裂不腦裂;但對有狀態服務(比如MySQL)的HA,必須要嚴格防止腦裂。(但有些生產環境下的系統按照無狀態服務HA的那一套去配置有狀態服務,結果可想而知…)
如何防止HA集群腦裂
一般采用2個方法 1)仲裁 當兩個節點出現分歧時,由第3方的仲裁者決定聽誰的。這個仲裁者,可能是一個鎖服務,一個共享盤或者其它什么東西。
2)fencing 當不能確定某個節點的狀態時,通過fencing把對方干掉,確保共享資源被完全釋放,前提是必須要有可靠的fence設備。
理想的情況下,以上兩者一個都不能少。 但是,如果節點沒有使用共享資源,比如基于主從復制的數據庫HA,也可以安全的省掉fence設備,只保留仲裁。而且很多時候我們的環境里也沒有可用的fence設備,比如在云主機里。
那么可不可以省掉仲裁,只留fence設備呢? 不可以。因為,當兩個節點互相失去聯絡時會同時fencing對方。如果fencing的方式是reboot,那么兩臺機器就會不停的重啟。如果fencing的方式是power off,那么結局有可能是2個節點同歸于盡,也有可能活下來一個。但是如果兩個節點互相失去聯絡的原因是其中一個節點的網卡故障,而活下來的正好又是那個有故障的節點,那么結局一樣是悲劇。 所以,單純的雙節點,無論如何也防止不了腦裂。
如何實現上面的策略
可以自己完全從頭開始實現一套符合上述邏輯的腳本。推薦使用基于成熟的集群軟件去搭建,比如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法定票數,這種方法更簡單,可靠。
————————————————————–keepalived的腦裂問題———————————————-
1)解決keepalived腦裂問題
檢測思路:正常情況下keepalived的VIP地址是在主節點上的,如果在從節點發現了VIP,就設置報警信息。腳本(在從節點上)如下:
[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的腦裂現象,檢查了兩臺主機的網絡連通狀態,發現網絡是好的。然后在備機上抓包:
[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實現。如下所示:
#?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。
4)推薦自己寫腳本
寫一個while循環,每輪ping網關,累計連續失敗的次數,當連續失敗達到一定次數則運行service keepalived stop關閉keepalived服務。如果發現又能夠ping通網關,再重啟keepalived服務。最后在腳本開頭再加上腳本是否已經運行的判斷邏輯,將該腳本加到crontab里面。
【相關推薦:mysql視頻教程】