所謂集群的一致性就是指集群中每個成員能夠了解其他成員的狀態,而且每個成員獲得的集群中其他節點的狀態和集群中其他節點成員列表信息(Node Membership)是一致的,這也是集群最基本的要求。Oracle集群管理軟件是通過以下一些機制來實現集群一致性的:
機制1:確定節點和節點間的連通性(心跳),以便節點之間能夠了解彼此的狀態。
機制2:用一(幾)個共享的位置來保存節點之間連通性信息,以便在集群需要進行重新配置(節點數量發生改變)時,能夠做出正確的決定並記錄集群最新的狀態。
機制3:本地節點自我監控機制,以便當本地節點出現問題時能夠主動離開集群,避免不一致的產生。
網絡心跳
(Network HeartBeat,簡稱NHB)
首先是確定集群節點之間的連通性,以便節點之間能夠了解彼此的狀態,而對於Oracle集群,這是通過節點間的網絡心跳來實現的。對於Oracle集群,ocssd.bin守護進程每秒鍾向集群的其他節點發送網絡心跳(當然是通過集群的私網)。例如:一個4節點的集群,集群的每一個節點每一秒鍾都會向集群中的其他三個節點發送網絡心跳信息,這也意味着每個節點每一秒鍾也會接收到集群中的其他三個節點發送網絡心跳。既然節點間互相發送網絡心跳,就需要一種機制來確定節點之間的連通性,以及網絡心跳出現問題時的處理機制。
網絡心跳主要通過以下的 ocssd.bin線程實現:
發送進程(clssnmSendingThread):該線程每秒鍾向集群中所有的節點發送網絡心跳信息。
分析線程(clssnmPollingThread):該線程會分析接收到的網絡心跳信息並進行處理,如果發現集群中的某一個(些)節點持續丟失網絡心跳(超過misscount設置),就會通知集群進行重新配置。
集群重新配置線程(clssnmRcfgMgrThread):當clssnmPollingThread發現集群需要進行重新配置時,該進程負責對集群進行重新配置。
派遣進程(clssnmClusterListener):該線程負責接收從遠程節點傳遞過來的信息,之后,根據信息的種類發送給相關的線程進行處理。
可以使用 pstack <ocssd.bin pid> 命令獲得ocssd.bin的各個線程的名稱。
發送線程負責每秒鍾發送網絡心跳到其他遠程節點。派遣線程負責接收從遠程節點發送過來的網絡心跳信息(當然,這個線程也負責接收其他信息),並分發收到的信息給其他相關的線程。分析線程會處理由派遣線程接收大心跳信息,確認節點之間的連通性,當分析線程發現某些節點的連通性出現問題時,例如:連續一段時間內沒有發現某一(幾)個節點的網絡心跳,集群就會進行重新配置(Reconfiguration)。而重新配置的結果往往就是某一(幾)個節點離開集群,也就是經常提到的節點驅逐。
集群的重新配置是指集群中的節點成員數量發生了改變以后,為了更新集群節點列表和維持集群一致性而進行的一系列操作。有可能是某一(幾)個節點加入集群,也有可能是某一(幾)個節點離開集群。因此節點驅逐只是集群重新配置的一種情況。
由丟失網絡心跳導致的從新配置實際上就是集群之間某些節點之間失去了私網的連通,這並不一定代表着某一個(些)節點真的出了問題。然而,節點間的通信問題的確會破壞集群的一致性,所以是需要處理的,而處理的結果就是某一(幾)個節點離開集群。對於10g、11gR1和11.2.0.1版本的集群,這意味着節點重啟。而從11.2.0.2開始,由於新特性rebootless restart的引入,對於丟失網絡心跳導致的重新配置,只會發生GI重啟。
由於丟失網絡心跳導致的重新配置步驟:
1,當集群的某一個節點連續一段時間(超過集群misscount)丟失網絡心跳之后,分析線程決定發起集群重新配置。
2,集群的重新配置管理節點(Reconfiguration Master,以下簡稱RM節點,這個節點通常是集群中節點號最小的節點)向集群中的所有節點發送重新配置消息。所有收到此消息的節點會回復該消息,並通知RM節點自己的狀態。
3,接下來,RM節點基於每個節點的狀態進行投票並檢查是否有腦裂會發生。
4,對於檢查腦裂,RM會查看網絡心跳無法訪問的節點的磁盤心跳信息,以便確認這個(些)節點的狀態。如果發現無法訪問的節點狀態也是正常的,那么就可能發生腦裂,需要避免。
5,RM節點向表決盤的kill block中寫入了”有毒(Poison Package)“的信息,需要重啟的節點在訪問表決盤時讀取到”有毒“信息,完成對本節點的重啟。如果RM節點發現某些節點以及離開集群,那么也會進行重新配置。
6,RM節點修改集群節點列表(主要是在表決盤中),重新配置完成。
對Oracle集群,腦裂是指集群的某些節點間的網絡心跳丟失,但是節點間的磁盤心跳是正常的情況,當腦裂出現后,集群會分裂成為某干個子集群(Corhort)。對於這種情況的出現,集群需要進行重新配置,基本原則是:節點數多的子集群存活,如果子集群包含的節點數相同,那么包含最小編號節點的子集群存活。
磁盤心跳(Disk HeartBeat,DHB)
磁盤心跳的主要目的就是當集群腦裂時幫助制定腦裂的解決方案。Oracle集群的每一個節點每秒鍾都會向集群的所有表決盤注冊本地節點的磁盤心跳信息(也就是說,所有VF中的信息是相同的),同時也會將自己能夠聯系到的集群中其他節點的信息,或者說本節點認為集群中的成員列表信息寫入到表決盤中。一旦發生腦裂,CSS的重新配置線程就可以通過表決盤中的信息了解集群中節點之間的連通性,從而決定集群會分裂成幾個子集群,以及每個子集群包含的節點情況和每個節點的狀態。
磁盤心跳主要通過以下的ocssd.bin線程實現:
磁盤心跳線程(clssnmvDiskPingThread):該線程負責向集群的表決盤中發送磁盤心跳信息。同時,該線程也負責讀取表決盤中的kill block信息,以確定本地節點是否需要重新啟動。
磁盤心跳監控線程(clssvmnDiskPingMonitorThread):該線程用於確定磁盤心跳線程是否能夠正確地發送磁盤心跳,並且能夠正確地發送磁盤心跳,並且能夠正確地讀取kill block中的信息。
kill block線程(clssnmvKillBlockThread):該線程負責監控VF的kill block信息。
Oracle規定,如果某個節點在short I/O timeout時間內一直無法訪問某一個VF的話,對應的VF會被離線掉,而當大多數的VF([VF數量/2]+1)被離線掉時,該節點會被重新啟動。因此配置奇數個VF要好一些,這也是Oracle推薦的配置方法。舉個例子:如果配置了3塊VF,那么代表需要[3/2]+1=2塊VF能夠正常工作。如果配置了4塊VF,那么代表着需要[4/2]+1=3塊VF能夠正常工作。因此,我們看到在配置4塊VF的情況下浪費了一塊盤。Oracle制定這種規定的目的就是為了確保在出現需要通過VF的信息決定節點去留的情況下,至少有一個VF能被集群所有節點訪問到。例如:一個兩節點的集群(node1和node2)配置了3塊VF(VF1、VF2和VF3),node1無法訪問VF1,node2無法訪問VF2,這意味着兩個節點仍然同時能夠訪問VF3。而當集群中某一個節點無法訪問大多數VF時,就意味着當需要通過VF中的信息決定去留的時候,可能會出現沒有任何一個VF可被集群中的全部節點訪問到的情況,這也意味着無法決定節點去留的時候,可能會出現沒有任何一個VF可被集群中的全部節點訪問的情況,這也意味着無法決定哪些節點應該離開集群,哪些節點應該被保留。例如:一個兩個節點的集群(node1和node2)配置了3塊VF(VF1、VF2和VF3),node1無法訪問VF1和VF2,node2無法訪問VF3,這意味着當出現網絡問題時,集群無法通過VF的信息獲得一致的所有節點的狀態,也就無法完成集群的重新配置。
本地心跳(Local HeartBeat,簡稱LHB)
這種心跳機制是在11gR2版本中被引入的。這種心跳的作用是監控ocssd.bin進程以及本地節點的狀態。在10g版本中,Oracle通過oclsomon和oprocd來實現。守護進程oclsomon.bin監控ocssd.bin進程的狀態,oprocd.bin進程監控本節點是否出現了性能問題(例如,hang住)。從11.2.0.1版本開始,新的集群cssdagent和cssdmonitor被引入,它們的功能就是監控本地節點的ocssd.bin進程狀態和本地節點的狀態(是否hang住)。對於ocssd.bin進程的監控,GI是通過本地心跳來實現的,Oracle會在每一秒鍾,在發送網絡心跳的同時(同一個線程)向cssdagent和cssdmonitor發送本地ocssd.bin進程的狀態(也就是本地心跳),如果本地心跳(到底misscount的時間),ocssdagent就會認為本地節點的ocssd.bin進程持續丟失本地心跳(到達misscount的時間),ocssdagent就會認為本地節點的ocssd.bin出現了問題,並重啟該節點。oprocd進程同樣也被整合到了cssdagent和cssdmonitor中,變成了其中的一個線程,而且監控節點是否hang住的方式也發生了改變,也就是說,對於版本11.2.0.1及以上版本的集群,修改節點的時間基本上不會再導致節點直接重啟了,但是,仍然不建議在集群運行時大幅度(修改的幅度不要超過misscount)地修改系統時間。
對於10g版本,實際上並沒有明確本地心跳的概念,但是實際上oprocd.bin進程從某種意義上來說承擔了本地心跳的工作。這個進程存在於10.2.0.4+和11gR1版本中。而且沒有安裝在第三方集群管理軟件的系統上。由於絕大部分的第三方集群管理軟件都具有類似oprocd的功能,Oracle也就沒有必要的再做重復的工作了。這個進程的目的是監控本地節點是否出現了hang住的情況,所以他由root用戶啟動,而且優先級級別為實時。該進程每秒鍾都會被調用一次,而且設置了500ms的margin time 。換句話說,Oracle在默認情況下要求oprocd進程在1.5s之內被返回。而oprocd進程所做的事情只是返回以下系統時間。如果一個由root用戶啟動,而且優先級為實時的進程在1.5s之內無法返回系統時間的話,Oracle就會認為本地節點有嚴重的問題,並重啟該節點。也正是以為oprocd進程會返回系統時間並進行相應的驗證,Oracle一直推薦客戶使用NTP的slew方式來微調系統時間,另外,在修改系統時間(理論上來說大於0.5s)之前,需要首先停止該節點上的CRS軟件。
另外,在10g版本中還存在着一個oclsomon.bin進程,這個進程的作用是監控ocssd.bin進程的健康性,但是在絕大多數情況下,這個進程對集群的運行並不起多大作用。