天天看點

Galera Cluster:一種新型的高一緻性MySQL叢集架構

Galera Cluster:一種新型的高一緻性MySQL叢集架構

1. 何謂galera cluster

何謂galera cluster?就是內建了galera插件的mysql叢集,是一種新型的,資料不共享的,高度備援的高可用方案,目前galera cluster有兩個版本,分别是percona xtradb cluster及mariadb cluster,都是基于galera的,是以這裡都統稱為galera cluster了,因為galera本身是具有多主特性的,是以galera cluster也就是multi-master的叢集架構,如圖1所示:

Galera Cluster:一種新型的高一緻性MySQL叢集架構

圖1 galera cluster架構

圖1中有三個執行個體,組成了一個叢集,而這三個節點與普通的主從架構不同,它們都可以作為主節點,三個節點是對等的,這種一般稱為multi-master架構,當有用戶端要寫入或者讀取資料時,随便連接配接哪個執行個體都是一樣的,讀到的資料是相同的,寫入某一個節點之後,叢集自己會将新資料同步到其它節點上面,這種架構不共享任何資料,是一種高備援架構。

一般的使用方法是,在這個叢集上面,再搭建一個中間層,這個中間層的功能包括建立連接配接、管理連接配接池,負責使三個執行個體的負載基本平衡,負責在用戶端與執行個體的連接配接斷開之後重連,也可以負責讀寫分離(在機器性能不同的情況下可以做這樣的優化)等等,使用這個中間層之後,由于這三個執行個體的架構在用戶端方面是透明的,用戶端隻需要指定這個叢集的資料源位址,連接配接到中間層即可,中間層會負責用戶端與伺服器執行個體連接配接的傳遞工作,由于這個架構支援多點寫入,是以完全避免了主從複制經常出現的資料不一緻的問題,進而可以做到主從讀寫切換的高度優雅,在不影響使用者的情況下,離線維護等工作,mysql的高可用,從此開始,非常完美。

2. 為什麼需要galera cluster

mysql在網際網路時代,可謂是深受世人矚目的。給社會創造了無限價值,随之而來的是,在mysql基礎之上,産生了形形色色的使用方法、架構及周邊産品。本文所關注的是架構,在這方面,已經有很多成熟的被人熟知的産品,比如mha、mmm等傳統組織架構,而這些架構是每個需要資料庫高可用服務方案的入門必備選型。

不幸的是,傳統架構的使用,一直被人們所诟病,因為mysql的主從模式,天生的不能完全保證資料一緻,很多大公司會花很大人力物力去解決這個問題,而效果卻一般,可以說,隻能是通過犧牲性能,來獲得資料一緻性,但也隻是在降低資料不一緻性的可能性而已。是以現在就急需一種新型架構,從根本上解決這樣的問題,天生的擺脫掉主從複制模式這樣的“美中不足”之處了。

幸運的是,mysql的福音來了,galera cluster就是我們需要的——從此變得完美的架構。

相比傳統的主從複制架構,galera cluster解決的最核心問題是,在三個執行個體(節點)之間,它們的關系是對等的,multi-master架構的,在多節點同時寫入的時候,能夠保證整個叢集資料的一緻性,完整性與正确性。

在傳統mysql的使用過程中,也不難實作一種multi-master架構,但是一般需要上層應用來配合,比如先要約定每個表必須要有自增列,并且如果是2個節點的情況下,一個節點隻能寫偶數的值,而另一個節點隻能寫奇數的值,同時2個節點之間互相做複制,因為2個節點寫入的東西不同,是以複制不會沖突,在這種約定之下,可以基本實作多master的架構,也可以保證資料的完整性與一緻性。但這種方式使用起來還是有限制,同時還會出現複制延遲,并且不具有擴充性,不是真正意義上的叢集。

3. galera cluster如何解決問題

3.1 galera的引入現在已經知道,galera cluster是mysql封裝了具有高一緻性,支援多點寫入的同步通信子產品galera而做的,它是建立在mysql同步基礎之上的,使用galera cluster時,應用程式可以直接讀、寫某個節點的最新資料,并且可以在不影響應用程式讀寫的情況下,下線某個節點,因為支援多點寫入,使得failover變得非常簡單。

所有的galera cluster,都是對galera所提供的接口api做了封裝,這些api為上層提供了豐富的狀态資訊及回調函數,通過這些回調函數,做到了真正的多主叢集,多點寫入及同步複制,這些api被稱作是write-set replication api,簡稱為wsrep api。

通過這些api,galera cluster提供了基于驗證的複制,是一種樂觀的同步複制機制,一個将要被複制的事務(稱為寫集),不僅包括被修改的資料庫行,還包括了這個事務産生的所有binlog,每一個節點在複制事務時,都會拿這些寫集與正在apply隊列的寫集做比對,如果沒有沖突的話,這個事務就可以繼續送出,或者是apply,這個時候,這個事務就被認為是送出了,然後在資料庫層面,還需要繼續做事務上的送出操作。

這種方式的複制,也被稱為是虛拟同步複制,實際上是一種邏輯上的同步,因為每個節點的寫入和送出操作還是獨立的,更準确的說是異步的,galera cluster是建立在一種樂觀複制的基礎上的,假設叢集中的每個節點都是同步的,那麼加上在寫入時,都會做驗證,那麼理論上是不會出現不一緻的,當然也不能這麼樂觀,如果出現不一緻了,比如主庫(相對)插入成功,而從庫則出現主鍵沖突,那說明此時資料庫已經不一緻,這種時候galera cluster采取的方式是将出現不一緻資料的節點踢出叢集,其實是自己shutdown了。

而通過使用galera,它在裡面通過判斷鍵值的沖突方式實作了真正意義上的multi-master,galera cluster在mysql生态中,在高可用方面實作了非常重要的提升,目前galera cluster具備的功能包括如下幾個方面:

多主架構:真正的多點讀寫的叢集,在任何時候讀寫資料,都是最新的。

同步複制:叢集不同節點之間資料同步,沒有延遲,在資料庫挂掉之後,資料不會丢失。

并發複制:從節點在apply資料時,支援并行執行,有更好的性能表現。

故障切換:在出現資料庫故障時,因為支援多點寫入,切的非常容易。

熱插拔:在服務期間,如果資料庫挂了,隻要監控程式發現的夠快,不可服務時間就會非常少。在節點故障期間,節點本身對叢集的影響非常小。

自動節點克隆:在新增節點,或者停機維護時,增量資料或者基礎資料不需要人工手動備份提供,galera cluster會自動拉取線上節點資料,最終叢集會變為一緻。

對應用透明:叢集的維護,對應用程式是透明的,幾乎感覺不到。 以上幾點,足以說明galera cluster是一個既穩健,又在資料一緻性、完整性及高性能方面有出色表現的高可用解決方案。

不過在運維過程中,有些技術特點還是需要注意的,這樣才能做到知此知彼,百戰百勝,因為現在mysql主從結構的叢集已經都是被大家所熟知的了,而galera cluster是一個新的技術,是一個在不斷成熟的技術,是以很多想了解這個技術的同學,能夠得到的資料很少,除了官方的手冊之外,基本沒有一些講得深入的,用來傳道授業解惑的運維資料,這無疑為很多同學設定了不低的門檻,最終有很多人因為一些特性,導緻最終放棄了galera cluster的選擇。

目前熟知的一些特性,或者在運維中需要注意的一些特性,有以下幾個方面:

galera cluster寫集内容:galera cluster複制的方式,還是基于binlog的,這個問題,也是一直被人糾結的,因為目前percona xtradb cluster所實作的版本中,在将binlog關掉之後,還是可以使用的,這誤導了很多人,其實關掉之後,隻是不落地了,表象上看上去是沒有使用binlog了,實際上在内部還是悄悄的打開了的。除此之外,寫集中還包括了事務影響的所有行的主鍵,所有主鍵組成了寫集的key,而binlog組成了寫集的data,這樣一個key-data就是寫集。key和data分别具有不同的作用的,key是用來驗證的,驗證與其它事務沒有沖突,而data是用來在驗證通過之後,做apply的。

galera cluster的并發控制:現在都已經知道,galera cluster可以實作叢集中,資料的高度一緻性,并且在每個節點上,生成的binlog順序都是一樣的,這與galera内部,實作的并發控制機制是分不開的。所有的上層到下層的同步、複制、執行、送出都是通過并發控制機制來管理的。這樣才能保證上層的邏輯性,下層資料的完整性等。

Galera Cluster:一種新型的高一緻性MySQL叢集架構

圖2 galera原理圖

圖2是從官方手冊中截取的,從圖中可以大概看出,從事務執行開始,到本地執行,再到寫集發送,再到寫集驗證,再到寫集送出的整個過程,以及從節點(相對)收到寫集之後,所做的寫集驗證、寫集apply及寫集送出操作,通過對比這個圖,可以很好的了解每一個階段的意義及性能等,下面就每一個階段以及其并發控制行為做一個簡單的介紹:

a. 本地執行:這個階段,是事務執行的最初階段,可以說,這個階段的執行過程,與單點mysql執行沒什麼差別,并發控制當然就是資料庫的并發控制了,而不是galera cluster的并發控制了。

b. 寫集發送:在執行完之後,就到了送出階段,送出之前首先将産生的寫集廣播出去,而為了保證全局資料的一緻性,在寫集發送時,需要串行,這個就屬于galera cluster并發控制的一部分了。

c. 寫集驗證:這個階段,就是我們通常說的galera cluster的驗證了,驗證是将目前的事務,與本地寫集驗證緩存集來做驗證,通過比對寫集中被影響的資料庫keys,來發現有沒有相同的,來确定是不是可以驗證通過,那麼這個過程,也是串行的。

d. 寫集送出:這個階段,是一個事務執行時的最後一個階段了,驗證完成之後,就可以進入送出階段了,因為些時已經執行完了的,而送出操作的并發控制,是可以通過參數來控制其行為的,即參數repl.commit_order,如果設定為3,表示送出就是串行的了,而這也是本人所推薦的(預設值)的一種設定,因為這樣的結果是,叢集中不同節點産生的binlog是完全一樣的,運維中帶來了不少好處和友善。其它值的解釋,以後有機會再做講解。

e. 寫集apply:這個階段,與上面的幾個在流程上不太一樣,這個階段是從節點做的事情,從節點隻包括兩個階段,即寫集驗證和寫集apply,寫集apply的并發控制,是與參數wsrep_slave_threads有關系的,本身在驗證之後,确定了互相的依賴關系之後,如果确定沒有關系的,就可以并行了,而并行度,就是參數wsrep_slave_threads的事情了。wsrep_slave_threads可以參照參數wsrep_cert_deps_distance來設定。

3.2 流量控制在pxc中,有一個參數叫fc_limit,它的全名其實是叫flow control limit,顧名思義,是流量控制大小限制的意思,它的作用是什麼呢?

如果一套叢集中,某個節點,或者某幾個節點的硬體資源比較差,或者由于節點壓力大,導緻複制效率低下,等等各種原因,導緻的結果是,從節點apply時,非常慢,也就是說,主庫在一秒鐘之内做的操作,從庫有可能會用2秒才能完成,那麼這種情況下,就會導緻從節點執行任務的堆積,接收隊列的堆積。

假設從節點真的堆積了,那麼galera會讓它一直堆積下去麼?這樣延遲會越來越嚴重,這樣galera cluster就變成一個主從架構的叢集了,已經失去了強一緻狀态的屬性了,那麼很明顯,galera是不會讓這種事情發生的,那麼此時,就說回到開頭提到的參數了,gcs.fc_limit,這個參數是在mysql參數wsrep_provider_options中來配置的,這個參數是galera的一個參數集合,有關于flow control的,還包括gcs.fc_factor,這兩個參數的意義是,當從節點堆積的事務數量超過gcs.fc_limit的值時,從節點就發起一個flow control,而當從節點堆積的事務數小于gcs.fc_limit * gcs.fc_factor時,發起flow control的從節點再發起一個解除的消息,讓整個叢集再恢複。

但我們一般所關心的,就是如何解決,下面有幾個一般所采用的方法:

發送fc消息的節點,硬體有可能出現問題了,比如io寫不進去,很慢,cpu異常高等

發送fc消息的節點,本身資料庫壓力太高,比如目前節點承載太多的讀,導緻機器load高,io壓力大等等。

發送fc消息的節點,硬體壓力都沒有太大問題,但做得比較慢,一般原因是主庫并發高,但從節點的并發跟不上主庫,那麼此時可能需要觀察這兩個節點的并發度大小,可以參考狀态參數wsrep_cert_deps_distance的值,來調整從節點的wsrep_slave_threads,此時應該是可以解決或者緩解的,這個問題可以這樣去了解,假設叢集每個節點的硬體資源都是相當的,那麼主庫可以執行完,從庫為什麼做不過來?那麼一般思路就是像處理主從複制的延遲問題一樣。

檢查存不存在沒有主鍵的表,因為galera的複制是行模式的,是以如果存在這樣的表時,主節點是通過語句來修改的,比如一個更新語句,更新了全表,而從節點收到之後,就會針對每一行的binlog做一次全表掃描,這樣導緻這個事務在從節點執行,比在主節點執行慢十倍,或者百倍,進而導緻從節點堆積進而産生fc。

可以看出,其實這些方法,都是用來解決主從複制延遲的方法,沒什麼兩樣,在了解flow control的情況下,解決它并不是難事兒。

3.3 有很多坑?有很多同學,在使用過galera cluster之後,發現很多問題,最大的比如ddl的執行,大事務等,進而導緻服務的不友好,這也是導緻很多人放棄的原因。

ddl執行卡死傳說:使用過的同學可能知道,在galera cluster中執行一個大的改表操作,會導緻整個叢集在一段時間内,是完全寫入不了任何事務的,都卡死在那裡,這個情況确實很嚴重,導緻線上完全不可服務了,原因還是并發控制,因為送出操作設定為串行的,ddl執行是一個送出的過程,那麼串行執行改表,當然執行多久,就卡多久,直到改表執行完,其它事務也就可以繼續操作了,這個問題現在沒辦法解決,但我們長期使用下來發現,小表可以這樣直接操作,大一點或者更大的,都是通過osc(pt-online-schema-change)來做,這樣就很好的避免了這個問題。

擋我者死:由于galera cluster在執行ddl時,是total ordered isolation(wsrep_osu_method=toi)的,是以必須要保證每個節點都是同時執行的,當然對于不是ddl的,也是total order的,因為每一個事務都具有同一個gtid值,ddl也不例外,而ddl涉及到的是表鎖,mdl鎖(meta data lock),隻要在執行過程中,遇到了mdl鎖的沖突,所有情況下,都是ddl優先,将所有的使用到這個對象的事務,統統殺死,不管是讀事務,還是寫事務,被殺的事務都會報出死鎖的異常,是以這也是一個galera cluster中,關于ddl的聞名遐迩的坑。不過這個現在确實沒有辦法解決,也沒辦法避免,不過這個的影響還算可以接受,先可以忍忍。

不死之身:繼上面的“擋我者死”,如果叢集真的被一個ddl卡死了,導緻整個叢集都動不了了,所有的寫請求都hang住了,那麼可能會有人想一個妙招,說趕緊殺死,直接在每個節點上面輸入kill connection_id,等等類似的操作,那麼此時,很不願意看到的資訊報了出來:you are not owner of thread connection_id。此時可能有些同學要哭了,不過這種情況下,确實沒有什麼好的解決方法(其實這個時候,一個故障已經發生了,一年的kpi也許已經沒有了,就看敢不敢下狠手了),要不就等ddl執行完成(所有這個資料庫上面的業務都處于不可服務狀态),要不就将資料庫直接kill掉,快速重新開機,趕緊恢複一個節點送出線上服務,然後再考慮叢集其它節點的資料增量的同步等,這個坑非常大,也是在galera cluster中,最大的一個坑,需要非常小心,避免出現這樣的問題。

4. 适用場景

現在對galera cluster已經有了足夠了解,但這樣的“完美”架構,在什麼場景下才可以使用呢?或者說,哪種場景又不适合使用這樣的架構呢?針對它的缺點,及優點,我們可以揚其長,避其短。可以通過下面幾個方面,來了解其适用場景。

資料強一緻性:因為galera cluster,可以保證資料強一緻性的,是以它更适合應用于對資料一緻性和完整性要求特别高的場景,比如交易,正是因為這個特性,我們去哪兒網才會成為使用galera cluster的第一大戶。

多點寫入:這裡要強調多點寫入的意思,不是要支援以多點寫入的方式提供服務,更重要的是,因為有了多點寫入,才會使得在dba正常維護資料庫叢集的時候,才會不影響到業務,做到真正的無感覺,因為隻要是主從複制,就不能出現多點寫入,進而導緻了在切換時,必然要将老節點的連接配接斷掉,然後齊刷刷的切到新節點,這是沒辦法避免的,而支援了多點寫入,在切換時刻允許有短暫的多點寫入,進而不會影響老的連接配接,隻需要将新連接配接都路由到新節點即可。這個特性,對于交易型的業務而言,也是非常渴求的。

性能:galera cluster,能支援到強一緻性,毫無疑問,也是以犧牲性能為代價,争取了資料一緻性,但要問:”性能犧牲了,會不會導緻性能太差,這樣的架構根本不能滿足需求呢?”這裡隻想說的是,這是一個權衡過程,有多少業務,qps大到galera cluster不能滿足的?我想是不多的(當然也是有的,可以自行做一些測試),在追求非常高的極緻性能情況下,也許單個的galera cluster叢集是不能滿足需求的,但畢竟是少數了,是以夠用就好,galera cluster必然是mysql方案中的佼佼者。

5. 總結

綜上所述,galera cluster是一個完全可依賴的,mysql資料一緻性的絕殺利器,使用中完全不需要擔心資料延遲,資料不一緻的問題,dba從此就從繁複的資料修複、解決複制延遲、維護時擔心影響業務的問題中徹底解脫了。可以說galera cluster是dba及業務系統的福音,也是mysql發展的大趨勢,我希望它會越來越好,也希望也有越來越多的人使用它,共同維護這個美好的大環境。

本文作者:王竹峰

來源:51cto