MySQL高可用之GC-Galera Cluster for MySQL

lhrbest發表於2020-02-20



https://blog.csdn.net/wzy0623/article/details/102522268

https://blog.csdn.net/wzy0623/article/details/102607193

https://blog.csdn.net/wzy0623/article/details/102819470

https://blog.csdn.net/wzy0623/article/details/102840342




Galera Cluster for MySQL 詳解(一)——基本原理



一、同步複製


二、Galera複製架構


1. wsrep api


2. 全域性事務ID(global transaction id,GTID)


3. Galera複製外掛


4. 組通訊外掛


三、Galera複製工作原理


四、狀態轉移


1. 狀態快照傳輸


2. 增量狀態轉移


3. 寫集快取(gcache)


五、流控


1. 流控原理


2. 理解節點狀態


3. 節點狀態與流控


六、單節點故障與恢復


七、仲裁


1. 加權法定票數(Weighted Quorum)


2. 裂腦(Split-Brain)


3. 法定票數計算


4. 加權仲裁示例


參考:


        Galera Cluster是由Codership開發的MySQL多主叢集,包含在MariaDB中,同時支援Percona xtradb、MySQL,是一個易於使用的高可用解決方案,在資料完整性、可擴充套件性及高效能方面都有可接受的表現。圖1所示為一個三節點Galera 叢集,三個MySQL例項是對等的,互為主從,這被稱為多主(multi-master)架構。當客戶端讀寫資料時,可連線任一MySQL例項。對於讀操作,從每個節點讀取到的資料都是相同的。對於寫操作,當資料寫入某一節點後,叢集會將其同步到其它節點。這種架構不共享任何資料,是一種高冗餘架構。


MySQL高可用之GC-Galera Cluster for MySQL

圖1 三節點Galera叢集

 


        Galera叢集具有以下特點:


多主架構:真正的多主多活群集,可隨時對任何節點進行讀寫。

同步複製:叢集不同節點之間資料同步,某節點崩潰時沒有資料丟失。

資料一致:所有節點保持相同狀態,節點之間無資料分歧。

並行複製:重放支援多執行緒並行執行以獲得更好的效能。

故障轉移:故障節點本身對叢集的影響非常小,某節點出現問題時無需切換操作,因此不需要使用VIP,也不會中斷服務。

自動克隆:新增節點會自動拉取線上節點的資料,最終叢集所有節點資料一致,而不需要手動備份恢復。

應用透明:提供透明的客戶端訪問,不需要對應用程式進行更改。

        Galera叢集複製要求資料庫系統支援事務,因此僅支援MySQL的Innodb儲存引擎,並且多主模式下只能使用可重複讀隔離級別。


一、同步複製

        不同於MySQL原生的主從非同步複製,Galera採用的是多主同步複製,如圖2所示。


MySQL高可用之GC-Galera Cluster for MySQL

圖2 多主同步複製

        非同步複製中,主庫將資料更新傳播給從庫後立即提交事務,而不論從庫是否成功讀取或重放資料變化。這種情況下,在主庫事務提交後的短時間內,主從庫資料並不一致。同步複製時,主庫的單個更新事務需要在所有從庫上同步更新。換句話說,當主庫提交事務時,叢集中所有節點的資料保持一致。


        相對於非同步複製,同步複製的優點主要體現在以下幾方面:


資料一致:同步複製保證了整個叢集的資料一致性,無論何時在任何節點執行相同的select查詢,結果都一樣。

高可用性:由於所有節點資料一致,單個節點崩潰不需要執行復雜耗時的故障切換,也不會造成丟失資料或停止服務。

效能改進:同步複製允許在叢集中的所有節點上並行執行事務,從而提高讀寫效能。

        當然,同步複製的缺點也顯而易見,這主要源於其實現方式。同步複製協議通常使用兩階段提交或分散式鎖協調不同節點的操作。假設叢集有n個節點,每秒處理o個操作,每個操作中包含t個事務,則每秒將在網路中產生 n*o*t 條訊息。這意味著隨著節點數量的增加,事務衝突和死鎖的概率將呈指數級增加。這也是MySQL預設使用非同步複製的主要原因。


        為解決傳統同步複製的問題,現已提出多種資料庫同步複製的替代方法。除理論外,一些原型實現也顯示出了很大的希望,如以下重要改進:


組通訊(Group Communication):定義了資料庫節點間的通訊模式,保證複製資料的一致性。

寫集(Write-sets):將多個併發資料庫寫操作更新的資料,繫結到單個寫集訊息中,提高節點並行性。關於寫集的概念,參見https://wxy0327.blog.csdn.net/article/details/94614149#3.%20%E5%9F%BA%E4%BA%8EWriteSet%E7%9A%84%E5%A4%9A%E7%BA%BF%E7%A8%8B%E5%A4%8D%E5%88%B6。

資料庫狀態機:資料庫站點本地處理只讀事務。更新事務首先在本地的“影子拷貝(shallow copies)”上執行,然後作為讀集廣播到其它資料庫站點進行驗證並提交。

事務重排序:此操作在資料庫提交事務並將其廣播到其它站點之前重新排序事務,增加成功通過驗證的事務數。

        Galera叢集就是基於這些方法構建的。可以看到Galera複製的原理與實現與MySQL組複製有很多相似之處。為了更好地理解Galera,在深入細節之前,先將它和MySQL組複製作一類比,如下表所示。



二、Galera複製架構

        同步複製系統中的節點將通過單個事務更新副本,從而與所有其它節點同步。這意味著當事務提交時,所有節點都將具有相同的值。此過程通過組通訊使用寫集複製進行。


        Galera叢集的內部架構包含四個元件,如圖3所示:


資料庫管理系統(DBMS):在單個節點上執行的資料庫伺服器。Galera群集可以使用MySQL、Mariadb或Percona xtradb。

wsrep api:Galera與資料庫伺服器的介面,為上層提供了豐富的狀態資訊和回撥函式。wsrep api由wsrep hooks、dlopen函式兩部分組成。wsrep hooks鉤子程式用於與資料庫伺服器引擎整合。dlopen函式使Galera外掛中的複製程式對wsrep hooks可用。

Galera複製外掛:實現寫集複製功能的核心模組。

組通訊外掛:Galera叢集的組通訊系統(Group Communication System,GCS),如GComm。

MySQL高可用之GC-Galera Cluster for MySQL

圖3 Replication API

 


1. wsrep api

        wsrep api是資料庫的通用複製外掛介面,定義了一組應用程式回撥和複製外掛呼叫函式。wsrep api將資料庫中的資料改變視為一種狀態變化,當客戶端修改資料庫內容時,其狀態將更改。wsrep api將資料庫狀態更改表示為一系列事務。叢集中的所有節點始終具有相同狀態,它們通過以相同的順序複製和應用狀態更改來相互同步。從更技術角度看,Galera叢集使用以下方式處理狀態更改:


一個節點的資料庫中發生狀態更改。

wsrep鉤子將更改轉換為寫集。

dlopen函式連線wsrep鉤子與Galera複製外掛。

Galera複製外掛處理寫集驗證,並將更改複製到叢集中的其它節點。

2. 全域性事務ID(global transaction id,GTID)

        在MySQL社群中,GTID的概念並不新鮮,MySQL中的GTID由Master生成,是用於標記唯一事務並通過ID定位binlog位置的一種手段,從而有效解決了級聯複製等場景中的各種問題。


        對Galera Cluster而言,複製不基於binlog,而是通過Galera複製外掛來保障。Galera的GTID同樣也標記事務唯一性,wsrep api使用GTID識別狀態更改。Galera的GTID格式如下:


45eec521-2f34-11e0-0800-2a36050b826b:94530586304

GTID由兩部分組成:


狀態UUID:表示當前狀態的唯一ID,可以簡單認為是叢集的一個唯一識別符號。

順序號:一個64位有符號整數,表示事務在Galera Cluster所有節點中的序號。

3. Galera複製外掛

        Galera複製外掛實現wsrep api,作為wsrep provider執行。Galera複製外掛由以下元件構成:


驗證層:該層準備寫集,並檢測本機事務,以及從其它節點同步來的事務是否可以提交。

複製層:該層的工作包含組通訊和並行複製兩方面。組通訊負責與其它節點同步寫集,併為事務分配全域性唯一的GTID。並行複製實現Galera事務樂觀並行控制。

4. 組通訊外掛

        組通訊框架為各種gcomm系統提供了一個外掛體系結構。Galera叢集建立在專有的組通訊系統層之上,實現虛擬同步。所謂虛擬同步,簡單說是指一個事務在一個節點上執行成功後,保證它在其它節點也一定會被成功執行,但並不能保證實時同步。為了解決實時性問題,Galera叢集實現了自己的執行時可配置的時態流控。

        組通訊框架還使用GTID提供來自多個源的訊息總序(Total Order)。在傳輸層上,Galera叢集是一個對稱的無向圖,所有節點都通過TCP相互連線。預設情況下,TCP用於訊息複製和群整合員資格服務,但也可以使用udp多播在LAN中進行復制。


三、Galera複製工作原理

        Galera複製是一種基於驗證的複製,以這兩篇論文為理論基礎:Don’t be lazy, be consistent 和 Database State Machine Approach。基於驗證的複製使用組通訊和事務排序技術實現同步複製。它通過廣播併發事務之間建立的全域性總序來協調事務提交。簡單說就是事務必須以相同的順序應用於所有例項。事務在本節點樂觀執行,然後在提交時執行一個驗證過程以保證全域性資料一致性。所謂樂觀執行是指,事務在一個節點提交時,被認為與其它節點上的事務沒有衝突,首先在本地執行,然後再傳送到所有節點做衝突檢測,無衝突時在所有節點提交,否則在所有節點回滾。Galera複製原理如圖4所示:

MySQL高可用之GC-Galera Cluster for MySQL


圖4 基於驗證的複製

 


        當客戶端發出commit命令時,在實際提交之前,對資料庫所做的更改都將被收集到一個寫集中,寫集中包含事務資訊和所更改行的主鍵。然後,資料庫將此寫集傳送到所有其它節點。節點用寫集中的主鍵與當前節點中未完成事務的所有寫集(不僅包括當前節點其它事務產生的寫集,還包括其它節點傳送過來的寫集)的主鍵相比較,確定節點是否可以提交事務。同時滿足以下三個條件則驗證失敗(存在衝突):


兩個事務來源於不同節點。

兩個事務包含相同的主鍵。

老事務對新事務不可見,即老事務未提交完成。新老事務的劃定依賴於全域性事務總序,即GTID。

        驗證失敗後,節點將刪除寫集,叢集將回滾原始事務。對於所有的節點都是如此,每個節點單獨進行驗證。因為所有節點都以相同的順序接收事務,它們對事務的結果都會做出相同的決定,要麼全成功,要麼都失敗。成功後自然就提交了,所有的節點又會重新達到資料一致的狀態。節點之間不交換“是否衝突”的資訊,各個節點獨立非同步處理事務。由此可見,Galera本身的資料也不是嚴格同步的,很明顯在每個節點上的驗證是非同步的,這也就是前面提到的“虛擬同步”。


        最後,啟動事務的節點可以通知客戶端應用程式是否提交了事務。


四、狀態轉移

        當一個新節點加入叢集時,資料將從叢集複製到這個節點,這是一個全自動的過程,Galera將此稱為狀態轉移。前面介紹Galera架構時曾提到,wsrep api將叢集中的資料改變視為狀態改變,因此這裡將資料同步稱作狀態轉移也就不足為怪了。Galera叢集中有兩種狀態轉移方法:


狀態快照傳輸(State Snapshot Transfers,SST),也就是通常所說的全量資料同步。

增量狀態轉移(Incremental State Transfers,IST),指增量資料同步。

        當有新節點加入時,叢集會選擇出一個捐獻者(Donor)節點為新節點提供資料,這點與MySQL組複製類似。


1. 狀態快照傳輸

        新節點加入叢集時會啟動狀態快照傳輸(SST),將其資料與叢集同步。Galera支援rsync、rsync_-wan、xtrabackup、mysqldump四種狀態快照傳輸方法,由系統變數wsrep_sst_method指定,預設為rsync。


        rsync、rsync_-wan、xtrabackup三種方法是物理備份,將資料檔案直接從捐獻者伺服器複製到新節點伺服器,並在傳輸後初始化接收伺服器,其中xtrabackup方式可實現捐贈者無阻塞資料同步。這些方法比mysqldump快很多。


        mysqldump方法是邏輯備份,要求使用者手動初始化接收伺服器,並在傳輸之前準備好接受連線。這是一種阻塞方法,在傳輸期間,捐贈節點變為只讀。mysqldump是狀態快照傳輸最慢的方法,不建議在生產環境使用。


2. 增量狀態轉移

        增量狀態轉移(IST)只向新節點傳送它所缺失的事務。使用IST需要滿足兩個先決條件:


新加入節點的狀態UUID與叢集中的節點一致。

新加入節點所缺失的寫集在捐助者的寫集快取中存在。這點很好理解,類比MySQL的binlog,如果所需的binlog檔案缺失,是無法做增量備份恢復的。

        滿足這些條件時,捐助節點單獨傳輸缺失的事務,並按順序重放它們,直到新節點趕上叢集。例如,假設叢集中有一個節點落後於叢集。此節點攜帶的節點狀態如下:


5a76ef62-30ec-11e1-0800-dba504cf2aab:197222

同時,叢集上的捐助節點狀態為:


5a76ef62-30ec-11e1-0800-dba504cf2aab:201913

        叢集上的捐助節點從加入節點接收狀態轉移請求。它檢查自身寫集快取中的序列號197223。如果該序號在寫集快取中不可用,則會啟動SST。否則捐助節點將從197223到201913的提交事務傳送到新加入節點。增量狀態傳輸的優點是可以顯著加快節點合併到叢集的速度。另外,這個過程對捐贈者來說是非阻塞的。


        增量狀態傳輸最重要的引數是捐助節點上的gcache.size,它控制分配多少系統記憶體用於快取寫集。可用空間越大,可以儲存的寫集越多。可以儲存的寫集越多,通過增量狀態傳輸可以彌合的事務間隙就越大。另一方面,如果寫集快取遠大於資料庫大小,則增量狀態傳輸開始時的效率低於傳送狀態快照。


3. 寫集快取(gcache)

        Galera群集將寫集儲存在一個稱為gcache的特殊快取中。gcache使用三種型別的儲存:


永久記憶體儲存(Permanent In-Memory Store):寫集使用作業系統的預設記憶體分配器進行分配,永久儲存於實體記憶體中。gcache.keep_pages_size引數指定保留的記憶體頁總大小,預設值為0。由於硬體的限制,預設情況下是禁用的。

永久環緩衝區檔案(Permanent Ring-Buffer File):寫集在快取初始化期間預分配到磁碟,生成一個記憶體對映檔案,用作寫集儲存。檔案目錄和檔名分別由gcache.dir和gcache.name引數指定。檔案大小由gcache.size引數指定,預設值為128MB。

按需頁儲存(On-Demand Page Store):根據需要在執行時將寫集分配給記憶體對映頁檔案。大小由gcache.page_size引數指定,預設值為128M,可隨寫集自動變大。頁面儲存的大小受可用磁碟空間的限制。預設情況下,Galera會在不使用時刪除頁面檔案,使用者可以設定要保留的頁面檔案總大小(gcache.size)。當所有其它儲存被禁用時,磁碟上至少保留一個頁面的檔案。

        Galera叢集使用一種分配演算法,嘗試按上述順序儲存寫集。也就是說,它首先嚐試使用永久記憶體儲存,如果沒有足夠的空間用於寫入集,它將嘗試儲存到永久環緩衝區檔案。除非寫入集大於可用磁碟空間,否則頁面儲存始終成功。


        注意,如果gcache.recover引數設定為yes,則在啟動時將嘗試恢復gcache,以便該節點可以繼續向其它節點提供IST服務。如果設定為no(預設),gcache將在啟動時失效,節點將只能為SST提供服務。


五、流控

        Galera叢集內部使用一種稱為流控的反饋機制來管理複製過程。流控允許節點根據需要暫停和恢復複製,這可以有效防止任一節點在應用事務時落後其它節點太多。


1. 流控原理

        從Galera叢集同步複製(虛擬同步)原理可知,事務的應用和提交在各個節點上非同步發生。節點從叢集接收但尚未應用和提交的事務將保留在接收佇列中。由於不同節點之間執行事務的速度不一樣,慢節點的接收佇列會越積越長。當接收佇列達到一定大小時,節點觸發流控,作用就是協調各個節點,保證所有節點執行事務的速度大於佇列增長速度。流控的實現原理很簡單:整個Galera叢集中,同時只有一個節點可以廣播訊息,每個節點都會獲得廣播訊息的機會(獲得機會後也可以不廣播)。當慢節點的接收佇列超過一定長度後,它會廣播一個FC_PAUSE訊息,所有節點收到訊息後都會暫緩廣播訊息,直到該慢節點的接收佇列長度減小到一定長度後再恢復複製。


        流控相關引數如下:


gcs.fc_limit:接收佇列中積壓事務的數量超過該值時,流控被觸發,預設值為16。對於Master-Slave模式(只在一個節點寫)的Galera叢集,可以配置一個較大的值,防止主從複製延遲。對啟動多寫的Galera叢集,較小的值比較合適,因為較大的接收佇列長度意味著更多衝突。

gcs.fc_factor:當接收佇列長度開始小於 gcs.fc_factor * gcs.fc_limit 時恢復複製,預設值為1。

gcs.fc_master_slave:Galera叢集是否為Master-Slave模式,預設為no。

2. 理解節點狀態

        一個節點在Galera叢集中可能經歷的節點狀態有Open、Primary、Joiner、Joined、Synced、Donor。可以通過wsrep_local_state和wsrep_local_state_comment系統變數檢視節點的當前狀態。節點狀態更改如圖5所示:


MySQL高可用之GC-Galera Cluster for MySQL

圖5 節點狀態轉換

 


節點啟動並建立到主元件( Primary Component,PC)的連線。由於網路問題群集可能被拆分為多個部分,為避免資料差異或腦裂,此時只能有一部分可以修改資料,這部分稱為主元件。

當節點成功執行狀態傳輸請求時,它將開始快取寫集。

節點接收狀態快照傳輸(SST)。它將擁有所有叢集資料,並開始應用快取的寫集。

節點完成對群集的追趕。節點將mysql狀態變數wsrep_ready設定為值1,現在允許該節點處理事務。

節點接收狀態傳輸請求,成為捐贈者。節點快取它無法應用的所有寫集。

節點完成對新加入節點的狀態傳輸。

3. 節點狀態與流控

        Galera叢集根據節點狀態實現多種形式的流控以保證資料一致性。有四種主要流控型別:


無流控(No Flow Control):當節點處於Open或Primary狀態時,此流控型別生效。此時節點還不被視為叢集的一部分,不允許這些節點複製、應用或快取任何寫集。

寫集快取(Write-set Caching):當節點處於Joiner和Donor狀態時,此流控型別生效。節點在此狀態下不能應用任何寫集,必須快取它們以備以後使用。

趕上(Catching Up):此流控型別在節點處於Joined狀態時生效。處於此狀態的節點可以應用寫集。這裡的流控確保節點最終能夠追趕上叢集。由於應用寫集通常比處理事務快幾倍,處於這種狀態的節點幾乎不會影響叢集效能。

叢集同步(Cluster Sync):此流控型別在節點處於Synced狀態時生效。當節點進入此狀態時,流控將嘗試將接收佇列保持最小。

六、單節點故障與恢復

        當一個節點因為硬體、軟體、網路等諸多原因與叢集失去聯絡時,都被概括為節點故障。從叢集的角度看,主元件看不到出問題的節點,它將會認為該節點失敗。從故障節點本身的角度來看,假設它沒有崩潰,那麼唯一的跡象是它失去了與主元件的連線。可以通過輪詢wsrep_local_state狀態變數監控Galera群集節點的狀態,值及其含義見上節流控中的描述。


        叢集檢查從節點最後一次接收到資料包的時間確定該節點是否連線到叢集,檢查的頻率由evs.inactive_check_period引數指定,預設值為每隔0.5秒檢查一次。在檢查期間,如果群集發現自上次從節點接收網路資料包以來的時間大於evs.keepalive_period引數的值(預設值為1秒),則它將開始發出心跳訊號。如果叢集在evs.suspect_timeout引數(預設值為5秒)期間沒有繼續從節點接收到網路資料包,則該節點被宣告為suspect,表示懷疑該節點已下線。一旦主元件的所有成員都將該節點視為可疑節點,它就被宣告為inactive,即節點失敗。如果在大於evs.inactive_timeout(預設值為15秒)的時間內未從節點接收到訊息,則無論意見是否一致,都會宣告該節點失敗。在所有成員同意其成員資格之前,失敗節點將保持非操作狀態。如果成員無法就節點的活躍性達成一致,說明網路對於叢集操作來說太不穩定。       


        這些選項值之間的關係為:


evs.inactive_check_period <= evs.keepalive_period <= evs.suspect_timeout <=    evs.inactive_timeout

        需要注意,如果網路過於繁忙,以至於無法按時傳送訊息或心跳訊號無響應,也可能被宣佈為節點失敗,這可以防止叢集其餘部分的操作被鎖。如果不希望這樣處理,可以增加超時引數。如果用CAP原則來衡量,Galera叢集強調的是資料一致性(Consistency),這就導致了叢集需要在可用性(Availability)和分割槽容忍性(Partition tolerance)之間進行權衡。也就是說,當使用的網路不穩定時,低evs.suspect_timeout和evs.inactive_timeout值可能會導致錯誤的節點故障檢測結果,而這些引數的較高值可能會導致在實際節點故障的情況下更長的發現時間。


        叢集中的一個節點出現故障不會影響其它節點繼續正常工作,單節點故障不會丟失任何資料。失敗節點的恢復是自動的。當失敗節點重新聯機時,它會自動與其它節點同步資料,之後才允許它重新回到叢集中。如果重新同步過程中狀態快照傳輸(SST)失敗,會導致接收節點不可用,因為接收節點在檢測到狀態傳輸故障時將中止。這種情況下若使用的是mysqldump方式的SST,需要手動還原。


七、仲裁

        除了單節點故障外,群集還可能由於網路故障而拆分為多個部分。每部分內的節點相互連線,但各部分之間的節點失去連線,這被稱為網路分裂(network partitioning)。此情況下只有一部分可以繼續修改資料庫狀態,以避免資料差異,這一部分即為主元件。正常情況下主元件就是整個叢集。當發生網路分裂時,Galera叢集呼叫一個仲裁演算法選擇一部分作為主元件,保證叢集中只有一個主元件。


1. 加權法定票數(Weighted Quorum)

        叢集中的當前節點數量定義了當前叢集的大小,群集大小決定達到仲裁所需的票數。Galera叢集在節點不響應並且被懷疑不再是叢集的一部分時進行仲裁投票。可以使用evs.suspect_timeout引數微調此無響應的超時時間,預設為5秒。


        發生網路分裂時,斷開連線的兩側都有活動節點。主元件要求獲得仲裁的多數票,因此具有較多存活節點的部分將成為主元件,而另一部分將進入非主狀態並開始嘗試與主元件連線,如圖6所示。


MySQL高可用之GC-Galera Cluster for MySQL

圖6 仲裁新主元件

 


        仲裁要求多數,這意味著不能在雙節點群集中進行自動故障轉移,因為一個節點的故障會導致另一節點自動進入非主狀態。而具有偶數個節點的叢集則有腦裂風險。如果在網路分裂導致節點的數量正好分成兩半,則兩個分割槽都不能成為主元件,並且都進入非主狀態,如圖7所示。要啟用Galera叢集自動故障切換,至少需要使用三個節點。

MySQL高可用之GC-Galera Cluster for MySQL


圖7 腦裂

2. 裂腦(Split-Brain)

        導致資料庫節點彼此獨立執行的叢集故障稱為“腦裂”。這種情況可能導致資料不一致,並且無法修復,例如當兩個資料庫節點獨立更新同一表上的同一行時。與任何基於仲裁的系統一樣,當仲裁演算法無法選擇主元件時,Galera叢集會受到腦裂影響。


        Galera設計為避免進入分裂腦狀態,如果失敗導致將叢集分割為兩個大小相等的部分,則兩部分都不會成為主元件。在節點數為偶數的叢集中,為把腦裂風險降到最低,可以人為分割槽將一部分始終劃分為叢集主元件,如:


4 node cluster -> 3 (Primary) + 1 (Non-primary)

6 node cluster -> 4 (Primary) + 2 (Non-primary)

6 node cluster -> 5 (Primary) + 1 (Non-primary)

以上分割槽示例中,任何中斷或失敗都很難導致節點完全分成兩半。


3. 法定票數計算

        Galera群集支援加權仲裁,其中每個節點可以被分配0到255範圍內的權重參與計算。法定票數計算公式為:



MySQL高可用之GC-Galera Cluster for MySQL

其中:


pi:最後可見的主元件的成員;

li:已知正常離開叢集的成員;

mi:當前元件成員;

wi:成員權重。

        這個公式的含義是:當且僅當當前節點權重總和大於最後一個主元件節點權重和減去正常離開叢集節點權重和的一半時,才會被選為新的主元件。


        訊息傳遞時帶有權重資訊。預設的節點權重為1,此時公式被轉換為單純的節點計數比較。通過設定pc.weight引數,可以在執行時更改節點權重,例如:


set global wsrep_provider_options="pc.weight=3";

4. 加權仲裁示例

        在瞭解了加權仲裁的工作原理後,下面是一些部署模式的示例。


(1)三個節點的加權仲裁

        三個節點配置仲裁權重如下:


node1: pc.weight = 2

node2: pc.weight = 1

node3: pc.weight = 0

此時如果node2和node3失效,node1會成為主元件,而如果node1失效,node2和node3都將成為非主元件。


(2)一主一從方案的加權仲裁

        主、從節點配置仲裁權重如下:


node1: pc.weight = 1

node2: pc.weight = 0

如果主節點失效,node2將成為非主元件,如果node2失效,node1將繼續作為主元件。


(3)一主多從方案的加權仲裁

        為具有多個從節點的主從方案配置仲裁權重:


node1: pc.weight = 1

node2: pc.weight = 0

node3: pc.weight = 0

...

noden: pc.weight = 0

如果node1失效,所有剩餘的節點都將作為非主元件,如果任何其它節點失效,則保留主元件。在網路分裂的情況下,node1始終作為主元件。(4)主站點和從站點方案的加權仲裁

        為主站點和從站點配置仲裁權重:


Primary Site:

  node1: pc.weight = 2

  node2: pc.weight = 2

 

Secondary Site:

  node3: pc.weight = 1

  node4: pc.weight = 1

這種模式下,一些節點位於主站點,而其它節點位於從站點。如果從站點關閉或站點之間的網路連線丟失,則主站點上的節點仍然是主元件。此外,node1或node2崩潰不會讓其它剩餘節點成為非主元件。


參考:

Galera replication原理詳解

Galera for mysql介紹及叢集環境搭建一





Galera Cluster for MySQL 詳解(二)——安裝配置



一、Galera叢集實驗環境


二、初始安裝


1. 安裝galera-3、mysql-wsrep-5.7、Percona-XtraBackup-2.4.15


2. 修改配置檔案


3. 初始化叢集


4. 啟動叢集其它節點的mysqld服務


5. 驗證安裝


6. 問題排查


三、使用SST增加節點


四、使用IST增加節點


1. 設定gcache.size


2. IST測試


參考:


一、Galera叢集實驗環境

        本篇以搭建三節點Galera Cluster for MySQL 5.7為例,說明Galera叢集的安裝步驟與基本配置,實驗環境如下。


        IP與主機名:

172.16.1.125    hdp2

172.16.1.126    hdp3

172.16.1.127    hdp4


        軟體環境:

CentOS Linux release 7.2.1511 (Core)

galera-3.28

mysql-wsrep-5.7.27

Percona-XtraBackup-2.4.15


        硬體環境:

三臺虛擬機器,每臺基本配置為:

. 雙核雙CPU,Intel(R) Xeon(R) CPU E5-2420 0 @ 1.90GHz

. 8G實體記憶體,8G Swap

. 100G物理硬碟


二、初始安裝

        我們從最簡單的場景開始,假設在沒有任何應用資料和訪問的情況下,從頭開始安裝Galera叢集。


1. 安裝galera-3、mysql-wsrep-5.7、Percona-XtraBackup-2.4.15

        以下步驟以root使用者在三臺主機執行。


(1)安裝依賴包


yum install perl-Time-HiRes

yum -y install perl-DBD-MySQL.x86_64

yum -y install libaio*

(2)建立yum原始檔


cat > /etc/yum.repos.d/galera.repo <<-END

[galera]

name = Galera

baseurl = https://releases.galeracluster.com/galera-3.28/centos/7/x86_64

gpgkey = https://releases.galeracluster.com/galera-3.28/GPG-KEY-galeracluster.com

gpgcheck = 1

 

[mysql-wsrep]

name = MySQL-wsrep

baseurl =  https://releases.galeracluster.com/mysql-wsrep-5.7.27-25.19/centos/7/x86_64

gpgkey = https://releases.galeracluster.com/mysql-wsrep-5.7.27-25.19/GPG-KEY-galeracluster.com

gpgcheck = 1

END

(3)安裝galera-3與mysql-wsrep-5.7


yum install -y galera-3 mysql-wsrep-5.7

(4)確認相關的rpm包


[root@hdp2~]#rpm -qa | grep -E 'galera|wsrep'

mysql-wsrep-client-5.7-5.7.27-25.19.el7.x86_64

galera-3-25.3.28-1.el7.x86_64

mysql-wsrep-common-5.7-5.7.27-25.19.el7.x86_64

mysql-wsrep-libs-5.7-5.7.27-25.19.el7.x86_64

mysql-wsrep-server-5.7-5.7.27-25.19.el7.x86_64

mysql-wsrep-5.7-5.7.27-25.19.el7.x86_64

mysql-wsrep-libs-compat-5.7-5.7.27-25.19.el7.x86_64

[root@hdp2~]#

(5)安裝xtrabackup

        如果SST使用xtrabackup需要執行此步驟。注意xtrabackup與MySQL伺服器的相容性,如果版本不匹配會在xtrabackup的日誌中報類似下面的錯誤:


innobackupex: Error: Unsupported server version: '5.7.27' Please report a bug at https://bugs.launchpad.net/percona-xtrabackup

對於MySQL 5.7.27,可從https://www.percona.com/downloads/Percona-XtraBackup-2.4/LATEST/下載xtrabackup 2.4.15版本。


# 安裝xtrabackup

rpm -ivh percona-xtrabackup-24-2.4.15-1.el7.x86_64.rpm

        至此軟體包安裝已完成。啟動叢集只要很少幾項必須配置。


2. 修改配置檔案

        編輯/etc/my.cnf檔案,增加以下內容:


[mysqld]

log-error=/var/log/mysqld.log

wsrep_provider=/usr/lib64/galera-3/libgalera_smm.so

wsrep_cluster_name="mysql_galera_cluster"

wsrep_cluster_address="gcomm://172.16.1.125,172.16.1.126,172.16.1.127"

wsrep_sst_method=xtrabackup

wsrep_sst_auth=root:P@sswo2d

wsrep_node_name=node1               # 另外兩個節點分別為node2、node3

wsrep_node_address="172.16.1.125"   # 另外兩個節點分別為172.16.1.126、172.16.1.127

        系統變數說明:


log-error:MySQL錯誤日誌檔案,叢集初始化後從該檔案中查詢初始密碼。

wsrep_provider:galera庫檔案。

wsrep_cluster_name:叢集名稱。

wsrep_cluster_address:叢集節點IP地址。

wsrep_sst_method:SST方法。

wsrep_sst_auth:SST認證資訊,xtrabackup使用此使用者名稱和口令連線資料庫例項。

wsrep_node_name:當前節點名稱。

wsrep_node_address:當前節點地址。

3. 初始化叢集

        下面步驟以root使用者在任一主機執行。


(1)啟動第一個節點


/usr/bin/mysqld_bootstrap

        該命令會啟動本機的 mysqld 服務,MySQL預設安裝目錄為/var/lib/mysql。注意,/usr/bin/mysqld_bootstrap 命令只在叢集第一個節點啟動時使用,因為該指令碼中帶有一個引數:–wsrep-new-cluster,代表新建叢集。


# 檢視mysqld服務狀態

systemctl status mysqld

(2)查詢並修改初始密碼


# 查詢初始密碼

grep -i 'temporary password' /var/log/mysqld.log

 

# 修改mysql root使用者密碼,需要根據提示輸入上一步輸出的初始密碼

mysqladmin -uroot -p password 'P@sswo2d'

(3)建立一個非root管理賬號


create user wxy identified by 'P@sswo2d';

grant all on *.* to wxy with grant option;

4. 啟動叢集其它節點的mysqld服務

# 在其它兩個主機上以root使用者執行


systemctl start mysqld

5. 驗證安裝

(1)檢視叢集節點數量


mysql> show status like 'wsrep_cluster_size';

+--------------------+-------+

| Variable_name      | Value |

+--------------------+-------+

| wsrep_cluster_size | 3     |

+--------------------+-------+

1 row in set (0.00 sec)

(2)在三個節點分別建表插入資料,檢視複製情況


-- node1

create database test;

use test;

create table t1(a int);

insert into t1 values(1);

 

-- node2

use test;

create table t2(a int);

insert into t2 values(2);

 

-- node2

use test;

create table t3(a int);

insert into t3 values(3);

        在三個節點查詢資料,結果一致:


mysql> select t1.a,t2.a,t3.a from test.t1,test.t2,test.t3;

+------+------+------+

| a    | a    | a    |

+------+------+------+

|    1 |    2 |    3 |

+------+------+------+

1 row in set (0.00 sec)

6. 問題排查

        如果在初始化叢集或啟動mysqld服務時,錯誤日誌中出現類似以下錯誤:


2019-10-05T10:25:29.729981Z 0 [ERROR] WSREP: wsrep_load(): dlopen(): /usr/lib64/galera-3/libgalera_smm.so: symbol SSL_COMP_free_compression_methods, version libssl.so.10 not defined in file libssl.so.10 with link time reference

說明galera外掛沒有載入成功。此時mysqld仍然可以成功啟動,但是以單例項提供讀寫服務,不會進行節點間資料複製。升級OpenSSL軟體包即可解決此問題。例如:


cd /etc/yum.repos.d/

wget http://mirrors.163.com/.help/CentOS7-Base-163.repo

yum -y upgrade openssl

三、使用SST增加節點

        假設node1、node2是正在使用的Galera叢集節點,現在要增加第三個節點node3。目標是在對現有節點無阻塞的前提下,為新增節點進行SST資料同步。


(1)將hdp4初始化為新節點


# 在hdp4上執行

systemctl stop mysqld

rm -rf /var/lib/mysql

rm -rf /var/log/mysqld.log

(2)使用tpcc-mysql對hdp2執行壓測,模擬應用負載


# 安裝tpcc-mysql

tar -zxvf tpcc-mysql.tar.gz

cd tpcc-mysql/src

make

cd ..

 

# 建立壓測庫表

mysql -uwxy -pP@sswo2d -h172.16.1.125 -e "create database tpcc_test;"

mysql -uwxy -pP@sswo2d -h172.16.1.125 -Dtpcc_test < create_table.sql

mysql -uwxy -pP@sswo2d -h172.16.1.125 -Dtpcc_test < add_fkey_idx.sql

 

# 準備資料

tpcc_load 172.16.1.125 tpcc_test wxy P@sswo2d 10

 

# 備份測試庫用於重複測試

mysqldump --databases tpcc_test -uwxy -pP@sswo2d -h172.16.1.125 > tpcc_test.sql

 

# 執行壓測

tpcc_start -h172.16.1.125 -d tpcc_test -u wxy -p "P@sswo2d" -w 10 -c 32 -r 60 -l 300

        關於tpcc-mysql的詳細安裝及使用說明參見https://wxy0327.blog.csdn.net/article/details/94614149#1.%20%E6%B5%8B%E8%AF%95%E8%A7%84%E5%88%92。


(3)在壓測執行期間,啟動hdp4上的MySQL例項


systemctl start mysqld

        在hdp4啟動過程中,hdp2、hdp3都是非阻塞的,但是會報以下鎖錯誤:


Deadlock found when trying to get lock; try restarting transaction

Lock wait timeout exceeded; try restarting transaction

        生產系統的Galera叢集中聯機新增節點時需要關注這個問題。當hdp4的MySQL例項啟動成功,後續的壓測過程不會再報錯。hdp2的/var/log/mysqld.log檔案中有以下關於SST的資訊:


2019-10-16T02:04:07.877299Z 2 [Note] WSREP: Assign initial position for certification: 106026, protocol version: 4

2019-10-16T02:04:07.877385Z 0 [Note] WSREP: Service thread queue flushed.

2019-10-16T02:04:08.307002Z 0 [Note] WSREP: Member 0.0 (node3) requested state transfer from '*any*'. Selected 1.0 (node1)(SYNCED) as donor.

2019-10-16T02:04:08.307028Z 0 [Note] WSREP: Shifting SYNCED -> DONOR/DESYNCED (TO: 106177)

2019-10-16T02:04:08.377506Z 2 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.

2019-10-16T02:04:08.377644Z 0 [Note] WSREP: Running: 'wsrep_sst_xtrabackup --role 'donor' --address '172.16.1.127:4444/xtrabackup_sst' --socket '/var/lib/mysql/mysql.sock' --datadir '/var/lib/mysql/' --defaults-file '/etc/my.cnf' --defaults-group-suffix ''   '' --gtid 'cada8d04-ef2b-11e9-a196-1ea90518b418:106177''

2019-10-16T02:04:08.380201Z 2 [Note] WSREP: sst_donor_thread signaled with 0

WSREP_SST: [INFO] Streaming with tar (20191016 10:04:08.542)

WSREP_SST: [INFO] Using socat as streamer (20191016 10:04:08.544)

WSREP_SST: [INFO] Streaming the backup to joiner at 172.16.1.127 4444 (20191016 10:04:08.552)

WSREP_SST: [INFO] Evaluating innobackupex --defaults-file=/etc/my.cnf $INNOEXTRA --galera-info --stream=$sfmt ${TMPDIR} 2>${DATA}/innobackup.backup.log | socat -u stdio TCP:172.16.1.127:4444; RC=( ${PIPESTATUS[@]} ) (20191016 10:04:08.555)

2019-10-16T02:04:10.586433Z 0 [Note] WSREP: (cad9d0f0, 'tcp://0.0.0.0:4567') turning message relay requesting off

2019-10-16T02:05:11.408356Z 89 [Note] WSREP: Provider paused at cada8d04-ef2b-11e9-a196-1ea90518b418:108094 (111402)

2019-10-16T02:05:11.679454Z 89 [Note] WSREP: resuming provider at 111402

2019-10-16T02:05:11.679485Z 89 [Note] WSREP: Provider resumed.

2019-10-16T02:05:12.057568Z 0 [Note] WSREP: 1.0 (node1): State transfer to 0.0 (node3) complete.

2019-10-16T02:05:12.057596Z 0 [Note] WSREP: Shifting DONOR/DESYNCED -> JOINED (TO: 108185)

WSREP_SST: [INFO] Total time on donor: 0 seconds (20191016 10:05:12.057)

2019-10-16T02:05:12.058281Z 0 [Note] WSREP: Member 1.0 (node1) synced with group.

2019-10-16T02:05:12.058296Z 0 [Note] WSREP: Shifting JOINED -> SYNCED (TO: 108185)

2019-10-16T02:05:12.127179Z 2 [Note] WSREP: Synchronized with group, ready for connections

2019-10-16T02:05:12.127215Z 2 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.

2019-10-16T02:05:20.968604Z 0 [Note] WSREP: 0.0 (node3): State transfer from 1.0 (node1) complete.

2019-10-16T02:09:34.556227Z 0 [Note] WSREP: Member 0.0 (node3) synced with group.

        當在hdp4上執行systemctl start mysqld後,叢集中的所有節點首先會將已提交的事務重新整理到磁碟,之後選擇一個捐贈者向新增節點全量同步資料,本例中系統選擇了node1作為捐獻者。然後node1呼叫xtrabackup向node3拷貝物理檔案,期間產生的寫集將被快取。node1成為捐獻者時,狀態由SYNCED轉為DONOR/DESYNCED;當xtrabackup備份完成時,其狀態變為JOINED;最後應用完快取的寫集時,狀態又從JOINED變為SYNCED。同樣從hdp4的/var/log/mysqld.log檔案中可以發現,node3的狀態變化過程為:OPEN -> PRIMARY -> JOINER -> JOINED -> SYNCED。


四、使用IST增加節點

        SST方法將全量資料從捐獻者節點拷貝到新加入節點,這類似於在MySQL主庫做一個全備份,然後在從庫還原,只不過在Galera叢集中,該過程依賴於新加入節點的狀態而自動觸發。對於高併發大庫環境下新增節點,SST方式可能會很痛苦。首先,如果使用mysqldump或rsync做SST,捐贈者節點時被阻塞的。其次,對於幾百GB或更多的資料集,即使網路夠快,同步過程也需要幾個小時才能完成。所以生產環境新增節點時最好避免使用SST,而是改用IST。


        IST只向新節點傳送它比捐贈者Gcache中少的寫集。Gcache是Galera節點儲存寫集副本的檔案。IST比SST快得多,無阻塞,對捐贈者無明顯影響。只要可能,這應該是新增節點的首選方案。


        有時SST是不可避免的,當Galera無法確定新增節點狀態時會發生這種情況。狀態儲存在grastate.dat檔案中,如果發生以下情況將觸發SST:


在MySQL資料目錄下不存在grastate.dat檔案——節點可能是一個“乾淨的”新節點。

grastate.dat檔案中沒有seqno或group id——節點可能在DDL期間崩潰。

由於缺少許可權或檔案系統損壞,grastate.dat無法讀取。

1. 設定gcache.size

        在上篇介紹IST時曾經提到,使用IST需要滿足兩個先決條件:新節點UUID與叢集相同;Gcache足夠儲存增量寫集。第一點很好滿足,用xtrabackup對叢集例項做物理備份時會自動為新節點保持叢集的UUID。要滿足第二個條件,需要進行一些計算,估計所需Gcache的大小。例如,對於tpcc-mysql壓測,可以按下面的方法估算。


(1)執行壓測


tpcc_start -h172.16.1.125 -d tpcc_test -u wxy -p "P@sswo2d" -w 10 -c 32 -r 60 -l 300

(2)在壓測期間執行查詢

 


set global show_compatibility_56=on;

set @start := (select sum(variable_value/1024/1024) from information_schema.global_status where variable_name like 'wsrep%bytes'); 

do sleep(60); 

set @end := (select sum(variable_value/1024/1024) from information_schema.global_status where variable_name like 'wsrep%bytes'); 

select round((@end - @start),2) as `Mb/min`, round((@end - @start),2) * 60 as `Mb/hour`;

        該查詢計算每分鐘寫的位元組數,結果如下:


+--------+---------+

| Mb/min | Mb/hour |

+--------+---------+

| 116.66 | 6999.60 |

+--------+---------+

        壓測總執行時間6分鐘(預熱1分鐘,執行5分鐘),gcache.size只要設定為大於117 * 6MB即可,因此這裡把gcache.size均設定為1G,足夠演示IST資料同步。在三個節點的配置檔案/etc/my.cnf中新增如下引數,然後重啟例項使之生效。


wsrep_provider_options="gcache.size=1073741824"

2. IST測試

        同樣假設node1、node2是正在使用的Galera叢集節點,現在要增加第三個節點node3。為避免SST,將從node1使用xtrabackup建立完整備份,在node3上恢復備份並建立Galera狀態檔案,以便Galera可以確定節點的狀態並跳過SST。為了儘可能接近IST之前的最新資料,還將建立一個增量備份。


(1)將hdp4初始化為新節點


# 在hdp4上用root使用者執行

systemctl stop mysqld

rm -rf /var/lib/mysql/*

rm -rf /var/log/mysqld.log 

rm -rf /tmp/incremental/*

(2)向叢集重新匯入壓測庫


mysql -uwxy -pP@sswo2d -h172.16.1.125 -Dtpcc_test < tpcc_test.sql

(3)執行壓測模擬生產負載


tpcc_start -h172.16.1.125 -d tpcc_test -u wxy -p "P@sswo2d" -w 10 -c 32 -r 60 -l 300

        接下來的第(4)、(5)、(6)、(7)步驟均在第(3)步執行期間執行。


(4)手工執行對叢集的xtrabackup備份


# 在hdp2上用mysql使用者執行下面的命令進行全量備份(已經事先配置好了hdp2到hdp4的免密登入)

innobackupex --defaults-file=/etc/my.cnf --user=wxy --password=P@sswo2d --socket=/var/lib/mysql/mysql.sock --galera-info --no-lock --stream=xbstream ./ | ssh mysql@172.16.1.127 "xbstream -x -C /var/lib/mysql"

 

# 再執行一個增量備份,這裡僅用於演示

scp mysql@172.16.1.127:/var/lib/mysql/xtrabackup_checkpoints /home/mysql/

innobackupex --defaults-file=/etc/my.cnf --user=wxy --password=P@sswo2d --socket=/var/lib/mysql/mysql.sock --incremental --incremental-basedir=/home/mysql --galera-info --no-lock --stream=xbstream ./ | ssh mysql@172.16.1.127 "xbstream -x -C /tmp/incremental"

(5)恢復hdp4的資料檔案

        第(4)步執行完成後,在hdp4上用mysql使用者執行以下命令:


# 恢復全量

innobackupex --apply-log --redo-only /var/lib/mysql/

# 恢復增量

innobackupex --apply-log --redo-only /var/lib/mysql/ --incremental-dir=/tmp/incremental

(6)生成grastate.dat檔案

        根據xtrabackup_galera_info檔案中的內容生成grastate.dat檔案,用於IST增量同步。在hdp4上用mysql使用者執行以下命令:


# 檢視xtrabackup_galera_info

cat /var/lib/mysql/xtrabackup_galera_info

 

# 生成grastate.dat檔案,uuid和seqno的值來自xtrabackup_galera_info

tee /var/lib/mysql/grastate.dat <<EOF

# GALERA saved state

version: 2.1

uuid:    650c3acb-eff8-11e9-9905-c73959fd46ca

seqno:   743544

safe_to_bootstrap: 0

EOF

(7)啟動新節點例項


# 用root使用者在hdp4上執行

systemctl start mysqld

        hdp2的/var/log/mysqld.log檔案中有以下關於IST的資訊:


2019-10-17T06:37:00.517675Z 1 [Note] WSREP: Assign initial position for certification: 758430, protocol version: 4

2019-10-17T06:37:00.517777Z 0 [Note] WSREP: Service thread queue flushed.

2019-10-17T06:37:00.961803Z 0 [Note] WSREP: Member 2.0 (node3) requested state transfer from '*any*'. Selected 1.0 (node2)(SYNCED) as donor.

2019-10-17T06:37:01.223935Z 0 [Note] WSREP: 1.0 (node2): State transfer to 2.0 (node3) complete.

2019-10-17T06:37:01.224331Z 0 [Note] WSREP: Member 1.0 (node2) synced with group.

2019-10-17T06:37:02.301018Z 0 [Note] WSREP: (4ce6e1a5, 'tcp://0.0.0.0:4567') turning message relay requesting off

2019-10-17T06:38:14.740957Z 0 [Note] WSREP: 2.0 (node3): State transfer from 1.0 (node2) complete.

2019-10-17T06:39:31.183193Z 0 [Note] WSREP: Member 2.0 (node3) synced with group.

        可以看到,系統選擇node2作為捐贈者,它的/var/log/mysqld.log檔案中有以下關於IST的資訊:


2019-10-17T06:37:00.991588Z 0 [Note] WSREP: Shifting SYNCED -> DONOR/DESYNCED (TO: 758624)

2019-10-17T06:37:01.045666Z 2 [Note] WSREP: IST request: 650c3acb-eff8-11e9-9905-c73959fd46ca:743544-758430|tcp://172.16.1.127:4568

2019-10-17T06:37:01.045701Z 2 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.

2019-10-17T06:37:01.045885Z 0 [Note] WSREP: Running: 'wsrep_sst_xtrabackup --role 'donor' --address '172.16.1.127:4444/xtrabackup_sst' --socket '/var/lib/mysql/mysql.sock' --datadir '/var/lib/mysql/' --defaults-file '/etc/my.cnf' --defaults-group-suffix ''   '' --gtid '650c3acb-eff8-11e9-9905-c73959fd46ca:743544' --bypass'

2019-10-17T06:37:01.046440Z 2 [Note] WSREP: sst_donor_thread signaled with 0

2019-10-17T06:37:01.048205Z 0 [Note] WSREP: async IST sender starting to serve tcp://172.16.1.127:4568 sending 743545-758430

顯示由hdp3向hdp4傳送743545-758430之間的寫集。


        可以在hdp4的/var/log/mysqld.log檔案中找到node3的IST增量同步和狀態變化過程:


2019-10-17T06:37:01.445113Z 0 [Note] WSREP: Signalling provider to continue.

2019-10-17T06:37:01.445151Z 0 [Note] WSREP: Initialized wsrep sidno 2

2019-10-17T06:37:01.445185Z 0 [Note] WSREP: SST received: 650c3acb-eff8-11e9-9905-c73959fd46ca:743544

2019-10-17T06:37:01.445588Z 0 [Note] /usr/sbin/mysqld: ready for connections.

Version: '5.7.27'  socket: '/var/lib/mysql/mysql.sock'  port: 3306  MySQL Community Server - (GPL), wsrep_25.19

2019-10-17T06:37:01.446278Z 2 [Note] WSREP: Receiving IST: 14886 writesets, seqnos 743544-758430

2019-10-17T06:37:01.446519Z 0 [Note] WSREP: Receiving IST...  0.0% (    0/14886 events) complete.

2019-10-17T06:37:02.539991Z 0 [Note] WSREP: (852308ca, 'tcp://0.0.0.0:4567') turning message relay requesting off

2019-10-17T06:37:11.453604Z 0 [Note] WSREP: Receiving IST... 11.1% ( 1648/14886 events) complete.

2019-10-17T06:37:21.485718Z 0 [Note] WSREP: Receiving IST... 23.5% ( 3504/14886 events) complete.

2019-10-17T06:37:31.686873Z 0 [Note] WSREP: Receiving IST... 37.8% ( 5632/14886 events) complete.

2019-10-17T06:37:31.751232Z 24 [Note] Got an error writing communication packets

2019-10-17T06:37:41.721891Z 0 [Note] WSREP: Receiving IST... 56.2% ( 8368/14886 events) complete.

2019-10-17T06:37:51.733818Z 0 [Note] WSREP: Receiving IST... 67.3% (10016/14886 events) complete.

2019-10-17T06:37:54.160644Z 39 [Note] Got an error writing communication packets

2019-10-17T06:38:01.739171Z 0 [Note] WSREP: Receiving IST... 80.0% (11904/14886 events) complete.

2019-10-17T06:38:03.165189Z 45 [Note] Got an error reading communication packets

2019-10-17T06:38:11.778534Z 0 [Note] WSREP: Receiving IST... 94.9% (14128/14886 events) complete.

2019-10-17T06:38:14.765552Z 0 [Note] WSREP: Receiving IST...100.0% (14886/14886 events) complete.

2019-10-17T06:38:14.765871Z 2 [Note] WSREP: IST received: 650c3acb-eff8-11e9-9905-c73959fd46ca:758430

2019-10-17T06:38:14.766840Z 0 [Note] WSREP: 2.0 (node3): State transfer from 1.0 (node2) complete.

2019-10-17T06:38:14.766873Z 0 [Note] WSREP: Shifting JOINER -> JOINED (TO: 777023)

2019-10-17T06:39:31.208799Z 0 [Note] WSREP: Member 2.0 (node3) synced with group.

2019-10-17T06:39:31.208825Z 0 [Note] WSREP: Shifting JOINED -> SYNCED (TO: 777023)

2019-10-17T06:39:31.241137Z 2 [Note] WSREP: Synchronized with group, ready for connections

2019-10-17T06:39:31.241155Z 2 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.

參考:

How to Avoid SST When Adding a New Node to MySQL Galera Cluster




Galera Cluster for MySQL 詳解(三)——管理監控

原創wzy0623 最後釋出於2019-10-30 15:29:01 閱讀數 641  收藏

展開

目錄


一、管理


1. 線上DDL


(1)TOI


(2)RSU


(3)pt-online-schema-change


2. 恢復主元件


(1)瞭解主元件狀態


(2)修改儲存的主元件狀態


3. 重置仲裁


(1)查詢最高階的節點


(2)重置仲裁


(3)自動引導


(4)手動引導


4. 管理流控


(1)監控流控


(2)配置流控


5. 自動逐出


(1)配置自動逐出


(2)檢查收回狀態


6. Galera仲裁員


(1)從shell啟動Galera仲裁程式


(2)啟動Galera仲裁員服務


(3)腦裂測試


二、監控


1. 使用狀態變數


(1)檢查叢集完整性


(2)檢查節點狀態


(3)檢查複製執行狀況


(4)檢測網路


2. 使用通知指令碼


(1)通知引數


(2)啟用通知指令碼


3. 使用資料庫伺服器日誌


參考:


一、管理

1. 線上DDL

        MySQL上線上執行DDL語句(create table、alter table、create index、grant ...)一直是個令人頭疼的操作。一方面大表上的DDL語句需要執行很長時間,這是因為MySQL的實現,它需要複製一遍表的資料。另一方面在高併發訪問的表上執行DDL期間會阻塞其上所有DML(insert、update、delete)語句的執行,直到DDL語句執行完。不但如此,高併發大表上的線上DDL還極易產生經典的“Waiting for table metadata lock”等待。


        Galera叢集也同樣如此,來看下面的例子。


-- 建立測試表並裝載大量資料

create table t1 as select * from information_schema.tables;

insert into t1 select * from t1;

...

insert into t1 select * from t1;

 

-- 建立主鍵

alter table t1 add column id int auto_increment primary key first;

 

-- 在session 1中執行加欄位的DDL

alter table t1 add column c1 int;

 

-- 在session 1的語句執行期間,在session 2中執行插入記錄的DML

insert into t1 (table_catalog,table_schema,table_name,table_type,table_comment) values('a','a','a','a','a');

        session 2的DML語句會立即返回以下錯誤,直到session 1的DDL語句完成,insert語句才能執行成功。


ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction

        DDL語句更改資料庫本身,並且是非事務性的(自動提交)。Galera群集通過兩種不同的方法處理DDL:


總序隔離(Total Order Isolation,TOI):以相同順序在所有叢集節點上執行DDL,防止在操作期間提交其它事務。

滾動升級(Rolling Schema Upgrade,RSU):在本地執行DDL,僅影響執行這些更改的節點,更改不會複製到叢集的其餘部分。

        可以配置wsrep_osu_method引數指定下線DDL方法,預設設定為TOI。DDL涉及到的是表鎖及MDL鎖(Meta Data Lock),只要在執行過程中,遇到了MDL鎖的衝突,所有情況下都是DDL優先,將所有使用到這個物件的事務統統殺死,被殺的事務都會報出死鎖異常,正如前面例子中看到的報錯。


(1)TOI

        如果並不關心叢集處理DDL語句時其它事務將被阻止,可使用TOI方法。DDL作為語句複製到群集中的所有節點,節點等待前面的所有事務同時提交,然後單獨執行DDL更改。在DDL處理期間,不能提交其它事務。這種方法的主要優點是它保證了資料的一致性。在使TOI時應考慮以下特性:


從事務驗證的角度來看,TOI模式永遠不會與前面的事務衝突,因為它們只在叢集提交所有前面的事務之後執行。因此DDL更改永遠不會使驗證失敗,並且它們的執行是有保證的。

DDL執行時正在進行的事務以及涉及相同資料庫資源的事務將在提交時報出死鎖錯誤,並將回滾。

叢集在執行DDL之前將其複製為語句,無法知道單個節點是否成功處理該DDL。TOI可防止單個節點的DDL執行出錯。

(2)RSU

        如果要在DDL期間保持高可用性,並且避免新、舊結構定義之間的衝突,則應該使用RSU方法。可以使用set語句執行此操作:


set global wsrep_osu_method='RSU';

        RSU僅在本地節點上處理DDL。當節點處理表結構更改時,它將與叢集解除同步。處理完表結構更改後,它將應用延遲的複製事件並將自身與群集同步。若要在整個叢集範圍內更改表結構,必須依次在每個節點上手動執行DDL。在RSU期間,叢集將繼續執行,其中一些節點使用舊錶結構,而另一些節點使用新表結構。RSU的主要優點是一次只阻塞一個節點,主要缺點是可能不安全,如果新結構和舊結構定義在複製事件級別不相容,則可能會失敗。例如:


-- 在節點1執行

set wsrep_osu_method='RSU';

alter table t1 add column c1 int;

insert into t1(c1) select 1;

 

-- 在節點2執行

alter table t1 add column c1 int;

        節點1向t1.c1欄位插入值時,節點2上並沒有t1.c1欄位,因此資料複製失敗。當在節點2上手動執行DDL新增t1.c1欄位後,兩節點資料不一致。


(3)pt-online-schema-change

        RSU只避免了執行DDL的節點對其它節點的阻塞,但對於同一節點上DDL與DML的相互影響問題卻無能為力。在當前階段,解決非阻塞線上DDL的終極解決方案是使用pt-online-schema-change。


        pt-online-schema-change是percona-toolkit中的一個工具,功能是無鎖定線上修改表結構,要求被修改表具有主鍵或唯一索引。percona-toolkit工具包的安裝和使用非常簡單。例如,從https://www.percona.com/downloads/percona-toolkit/LATEST/下載percona-toolkit,然後執行下面的命令進行安裝:


# 安裝依賴包

yum install perl-TermReadKey.x86_64 

yum install perl-DBI

yum install perl-DBD-MySQL

yum install perl-Time-HiRes

yum install perl-IO-Socket-SSL

 

# 安裝percona-toolkit

rpm -ivh percona-toolkit-3.1.0-2.el7.x86_64.rpm

        執行類似下面的命令修改表結構:


pt-online-schema-change --alter="add column c1 int;" --execute D=test,t=t1,u=root,p=P@sswo2d

        alter引數指定修改表結構的語句,execute表示立即執行,D、t、u、p分別指定庫名、表名、使用者名稱和密碼,執行期間不阻塞其它並行的DML語句。pt-online-schema-change還有許多選項,具體用法可以使用pt-online-schema-change --help檢視聯機幫助。官方文件連結為:https://www.percona.com/doc/percona-toolkit/LATEST/pt-online-schema-change.html。


        pt-online-schema-change工作原理其實很簡單:


如果存在外來鍵,根據alter-foreign-keys-method引數的值,檢測外來鍵相關的表,做相應設定的處理。如果被修改表存在外來鍵定義但沒有使用 --alter-foreign-keys-method 指定特定的值,該工具不予執行。

建立一個新的表,表結構為修改後的資料表,用於從源資料表向新表中匯入資料。

建立觸發器,用於記錄從拷貝資料開始之後,對源資料表繼續進行資料修改的操作記錄下來,資料拷貝結束後,執行這些操作,保證資料不會丟失。如果表中已經定義了觸發器這個工具就不能工作了。

拷貝資料,從源資料表中拷貝資料到新表中。

修改外來鍵相關的子表,根據修改後的資料,修改外來鍵關聯的子表。

rename源資料表為old表,把新表rename為源表名,並將old表刪除。

刪除觸發器。

2. 恢復主元件

        群集節點將主元件狀態儲存到本地磁碟。節點記錄主元件的狀態以及連線到它的節點的uuid。中斷情況下,一旦最後儲存狀態中的所有節點都實現連線,叢集將恢復主元件。如果節點之間的寫集位置不同,則恢復過程還需要完整狀態快照傳輸(SST)。關於主元件的概念參見https://wxy0327.blog.csdn.net/article/details/102522268#%E4%B8%83%E3%80%81%E4%BB%B2%E8%A3%81。


(1)瞭解主元件狀態

        節點將主元件狀態儲存到磁碟時,會將其儲存在MySQL資料目錄下的gvwstate.dat檔案中,內容如下所示。


[root@hdp2/var/lib/mysql]#more /var/lib/mysql/gvwstate.dat

my_uuid: 4a6cfe9d-f9de-11e9-9ad4-23840b115384

#vwbeg

view_id: 3 4a6cfe9d-f9de-11e9-9ad4-23840b115384 3

bootstrap: 0

member: 4a6cfe9d-f9de-11e9-9ad4-23840b115384 0

member: 78bdb344-f9de-11e9-bcfa-eb03d339c6d7 0

member: 7d14464b-f9de-11e9-83b3-5b022ee44499 0

#vwend

[root@hdp2/var/lib/mysql]#

        gvwstate.dat檔案分為節點資訊和檢視資訊兩部分。節點資訊在my_uuid欄位中提供節點的uuid。檢視資訊提供有關節點所屬主元件檢視的資訊,該檢視包含在vwbeg和vwend標記之間。view_id 從三個部分構成檢視的識別符號:view_type 始終為3,表示主檢視,view_uuid和view_seq一起構成識別符號唯一值;bootstrap 顯示節點是否已引導,不影響主元件恢復過程;member 顯示此主元件中節點的uuid。


        當群集形成或更改主元件時,節點建立並更新此檔案,這將確保節點保留其所在的最新主元件狀態。如果節點失去連線,則它具有要引用的檔案。如果節點正常關閉,則會刪除該檔案。


(2)修改儲存的主元件狀態

        如果叢集處於需要強制特定節點彼此連線的異常情況,可以通過手動更改儲存的主元件狀態來執行此操作。注意,正常情況下應完全避免編輯或修改gvwstate.dat檔案,因為這樣做可能會導致意想不到的結果。


        當一個節點第一次啟動或在正常關機後啟動時,它會隨機生成一個uuid並將其分配給自己,該uuid用作叢集其餘部分的識別符號。如果節點在資料目錄中找到gvwstate.dat檔案,它將讀取my_uuid欄位以找到它應該使用的值。通過手動將任意uuid值分配給每個節點上的相應欄位,可以強制它們在開始時相互連線,形成一個新的主元件。下面看一個例子。


首先停止實驗環境三節點Galera叢集中的所有MySQL例項:


systemctl stop mysqld

然後在任意節點啟動MySQL例項都會報錯:


[root@hdp2/var/lib/mysql]#systemctl start mysqld

Job for mysqld.service failed because the control process exited with error code. See "systemctl status mysqld.service" and "journalctl -xe" for details.

[root@hdp2/var/lib/mysql]#

日誌中顯示如下錯誤:


2019-10-29T00:19:11.470690Z 0 [ERROR] WSREP: failed to open gcomm backend connection: 110: failed to reach primary view: 110 (Connection timed out)

         at gcomm/src/pc.cpp:connect():158

2019-10-29T00:19:11.470710Z 0 [ERROR] WSREP: gcs/src/gcs_core.cpp:gcs_core_open():209: Failed to open backend connection: -110 (Connection timed out)

2019-10-29T00:19:11.470912Z 0 [ERROR] WSREP: gcs/src/gcs.cpp:gcs_open():1458: Failed to open channel 'mysql_galera_cluster' at 'gcomm://172.16.1.125,172.16.1.126,172.16.1.127': -110 (Connection timed out)

2019-10-29T00:19:11.470931Z 0 [ERROR] WSREP: gcs connect failed: Connection timed out

2019-10-29T00:19:11.470941Z 0 [ERROR] WSREP: wsrep::connect(gcomm://172.16.1.125,172.16.1.126,172.16.1.127) failed: 7

2019-10-29T00:19:11.470968Z 0 [ERROR] Aborting

        很明顯例項啟動時取不到主元件檢視。由於三個節點中至少有兩個活躍節點才能構成主元件,但現在一個例項都不存在,而且節點找不到叢集主元件資訊,致使節點無法啟動。


        我們希望三個節點一起啟動以形成叢集的新主元件。此時需要為每個節點提供一個任意唯一的uuid值,例如在其它可用的MySQL上執行select uuid()來獲得。下面手工生成三個節點的gvwstate.dat檔案。


節點1上的gvwstate.dat檔案內容如下:


my_uuid: 9085dadf-f953-11e9-92e9-005056a50f77

#vwbeg

view_id: 3 9085dadf-f953-11e9-92e9-005056a50f77 3

bootstrap: 0

member: 9085dadf-f953-11e9-92e9-005056a50f77 0

member: 8e2de005-f953-11e9-88b4-005056a5497f 0

member: 7dc3eb7e-f953-11e9-ad17-005056a57a4e 0

#vwend

然後對節點2重複該過程:


my_uuid: 8e2de005-f953-11e9-88b4-005056a5497f

#vwbeg

view_id: 3 9085dadf-f953-11e9-92e9-005056a50f77 3

bootstrap: 0

member: 9085dadf-f953-11e9-92e9-005056a50f77 0

member: 8e2de005-f953-11e9-88b4-005056a5497f 0

member: 7dc3eb7e-f953-11e9-ad17-005056a57a4e 0

#vwend

節點3也一樣:


my_uuid: 7dc3eb7e-f953-11e9-ad17-005056a57a4e

#vwbeg

view_id: 3 9085dadf-f953-11e9-92e9-005056a50f77 3

bootstrap: 0

member: 9085dadf-f953-11e9-92e9-005056a50f77 0

member: 8e2de005-f953-11e9-88b4-005056a5497f 0

member: 7dc3eb7e-f953-11e9-ad17-005056a57a4e 0

#vwend

下面啟動第一個節點:


systemctl start mysqld

當節點啟動時,Galera叢集將讀取每個節點的gvwstate.dat檔案,從中提取其uuid並使用member欄位的uuid來確定它應該連線哪些節點以形成新的主元件。但此時該命令執行的現象是“掛起”。現在叢集中還沒有主元件,該節點正在等待SST完成,正如日誌中所顯示的:


2019-10-29T00:41:31.058586Z 0 [Note] WSREP: Received NON-PRIMARY.

2019-10-29T00:41:31.058596Z 0 [Note] WSREP: Waiting for SST to complete.

2019-10-29T00:41:31.058995Z 2 [Note] WSREP: New cluster view: global state: 4a6db23a-f9de-11e9-ba76-93e71f7c9a45:3, view# -1: non-Primary, number of nodes: 1, my index: 0, protocol version -1

2019-10-29T00:41:31.059022Z 2 [Note] WSREP: wsrep_notify_cmd is not defined, skipping notification.

2019-10-29T00:41:31.558645Z 0 [Warning] WSREP: last inactive check more than PT1.5S ago (PT3.50285S), skipping check

下面啟動第二個節點:


systemctl start mysqld

依然“掛起”,日誌中顯示的同節點1一樣。


最後啟動第三個節點:


systemctl start mysqld

        此時第三個節點和前面正在啟動中的兩個節點同時啟動成功。只有當主元件包含的所有節點都啟動後才能確定SST的方向,繼而完成整個叢集的啟動。


3. 重置仲裁

        在網路連線出現問題,或超過一半的叢集出現故障,或出現腦裂等情況時,可能會發現節點不再將自己視為主元件的一部分。可以檢查wsrep_cluster_status變數是否發生這種情況。在每個節點上執行以下查詢:


mysql> show global status like 'wsrep_cluster_status';

+----------------------+---------+

| Variable_name        | Value   |

+----------------------+---------+

| wsrep_cluster_status | Primary |

+----------------------+---------+

1 row in set (0.00 sec)

        返回值primary表示節點是主元件的一部分。當查詢返回任何其它值時,表示節點是不可操作元件的一部分。這種情況的節點會向所有應用查詢返回未知命令的錯誤。如果沒有任何節點返回primary,則意味著需要重置仲裁,這種情況是非常少見的。如果有一個或多個返回primary的節點,則表示是網路連線出現問題,而不是需要重置仲裁。一旦節點重新獲得網路連線,它們就會自動與主元件重新同步。


(1)查詢最高階的節點

        重置仲裁前需要標識群集中最高階的節點。也就是說,必須找到本地資料庫提交了最後一個事務的節點。無論重置仲裁時使用何種方法,此節點都將作為新主元件的起點。可以使用wsrep_last_committed狀態變數識別叢集中最高階的節點。在每個節點上執行以下查詢:


mysql> show status like 'wsrep_last_committed';

+----------------------+-------+

| Variable_name        | Value |

+----------------------+-------+

| wsrep_last_committed | 392   |

+----------------------+-------+

1 row in set (0.00 sec)

        返回值是該節點提交的最後一個事務的序號,序號最大的節點是叢集中最高階的節點,將被用作引導新主元件時的起點。


(2)重置仲裁

        重置仲裁所做的是在可用的最高階節點上引導主元件,然後該節點作為新的主元件執行,使叢集的其餘部分與其狀態保持一致。有自動和手動兩種方法完成仲裁重置,首選方法是自動方法。自動引導在每個節點上保留寫集快取gcache,這意味著當新主元件啟動時,可以使用增量狀態轉移(IST)而不是速度慢得多的狀態快照轉移(SST)進行自我配置。


(3)自動引導

        重置仲裁將主元件引導到最高階的節點上。在自動方法中,這是通過在wsrep_provider_options引數下動態啟用pc.bootstrap來完成的。要執行自動引導,在最高階節點的資料庫上執行以下命令:

set global wsrep_provider_options='pc.bootstrap=yes';


        該節點現在作為新主元件中的起始節點執行。如果可能,具有網路連線的不可操作元件中的節點將嘗試啟動增量狀態傳輸,如果不可能,則使用狀態快照傳輸,以使其自己的資料庫保持最新。


(4)手動引導

        手動引導時中,首先需要關閉群集,然後從最高階的節點開始重新啟動群集。手動引導群集需要完成以下步驟:


1. 關閉所有群集節點。


systemctl stop mysqld

2. 使用--wsrep-new-cluster選項啟動最高階的節點。


/usr/bin/mysqld_bootstrap

        如果mysqld_bootstrap命令將執行失敗,並且日誌中顯示以下錯誤資訊:


2019-10-29T02:17:41.041493Z 0 [ERROR] WSREP: It may not be safe to bootstrap the cluster from this node. It was not the last one to leave the cluster and may not contain all the updates. To force cluster bootstrap with this node, edit the grastate.dat file manually and set safe_to_bootstrap to 1 .

2019-10-29T02:17:41.041501Z 0 [ERROR] WSREP: wsrep::connect(gcomm://172.16.1.125,172.16.1.126,172.16.1.127) failed: 7

2019-10-29T02:17:41.041511Z 0 [ERROR] Aborting

說明該節點可能不是最高階節點。Galera認為這種情況下bootstrap是不安全的,因為可能丟失事務。如果要強制執行引導,可以編輯grastate.dat檔案,將safe_to_bootstrap設定為1,然後再執行mysqld_bootstrap命令。


3. 逐次啟動群集中的其它節點。


systemctl start mysqld

        當第一個節點以--wsrep-new-cluster選項開始時,它使用前一個叢集中可用的最高階狀態的資料初始化一個新叢集。當其它節點啟動時,它們會連線到此節點並請求狀態快照傳輸,以使自己的資料庫保持最新。


4. 管理流控

        叢集通過全域性排序同步複製更改,但從原始節點非同步應用這些更改。為了防止任何一個節點落後叢集太多,Galera叢集實現了一種稱為流控的反饋機制。節點將接收到的寫集按全域性順序排隊,並開始在資料庫中應用和提交它們。如果接收到的佇列太大,節點將啟動流控,此時節點將暫停複製而處理接收佇列。一旦接收佇列減小到一個閾值,節點就會恢復複製。


(1)監控流控

        Galera群集提供全域性狀態變數用於監視流控,這些變數分為計數流控暫停事件的狀態變數和記錄暫停複製時長的狀態變數。


mysql> show status like 'wsrep_flow_control_%';

+------------------------------+----------+

| Variable_name                | Value    |

+------------------------------+----------+

| wsrep_flow_control_paused_ns | 0        |

| wsrep_flow_control_paused    | 0.000000 |

| wsrep_flow_control_sent      | 0        |

| wsrep_flow_control_recv      | 0        |

+------------------------------+----------+

4 rows in set (0.01 sec)

        流控使用fc_pause事件通知群集它正在暫停複製。Galera叢集提供了兩個狀態變數來監視此事件。


wsrep_flow_control_sent:顯示自上次狀態查詢以來本地節點傳送的流控暫停事件數。

wsrep_flow_control_recv:顯示自上次狀態查詢以來群集上的流控暫停事件數,包括來自其它節點的事件數和本地節點傳送的事件數。

        除了跟蹤流控暫停事件數之外,Galera叢集還可以跟蹤自上次 FLUSH STATUS 以來由於流控而暫停複製的時長。


wsrep_flow_control_paused:暫停複製的時長。

wsrep_flow_control_paused_ns:以納秒為單位暫停複製的時長。

(2)配置流控

        Galera叢集提供了兩組引數管理節點如何處理複製速率和流控,一組控制寫集快取,另一組涉控制流控的觸發或取消條件。以下三個引數控制節點如何響應複製速率的更改。


gcs.recv_q_hard_limit:設定最大接收佇列的大小,單位是位元組。引數值取決於記憶體、交換區大小和效能考慮。在32位系統上,預設值為ssize_max減2GB。64位系統沒有實際限制,預設值為LLONG_MAX。如果某個節點超過此限制,並且gcs.max_throttle未設定為0.0,則該節點將因記憶體不足錯誤而中止。如果gcs.max_throttle設定為0.0,則群集中的複製將停止。

gcs.max_throttle:限制狀態傳輸期間的複製速率,以避免耗盡記憶體,預設值為0.25。如果將引數設定為1.0,則節點不會限制複製速率。如果將引數設定為0.0,則可以完全停止複製。

gcs.recv_q_soft_limit:預設值為0.25。當複製速率超過軟限制時,節點計算在此期間的平均複製速率(以位元組為單位)。之後,節點會隨著快取大小線性降低複製速率,以便在recv_q_hard_limit下達到gcs.max_throttle乘以平均複製速率的值。

        以下引數控制節點觸發流控的條件以及用於確定何時應斷開流控並恢復複製。


gcs.fc_limit:此引數確定流控觸發點。當接收佇列中的事務數超過此限制時,節點將暫停複製,預設值為16。對於多主配置,必須將此限制保持在較低值,以減少驗證衝突。如果是主從設定,可以使用更高的值來減少流控干預,減少從庫複製延遲。

gcs.fc_factor:此引數用於確定節點何時可以取消流控,預設值為1。當節點上的接收佇列低於gcs.fc_limit * gcs.fc_factor的值時將恢復複製。

        雖然使用盡可能小的接收佇列對於多主操作來說非常重要,但接收列長度在主從設定中並不是那麼重要。根據應用程式和硬體的不同,節點可能在幾秒鐘內應用1k個寫集。接收佇列長度對故障轉移沒有影響。


        叢集節點彼此非同步處理事務,節點不能以任何方式預期複製資料的數量,因此流控總是被動的。也就是說,流控只有在節點超過某些限制後才會生效,它並不能防止超過這些限制。


5. 自動逐出

        當Galera叢集 發現某個節點出現異常,如很長的響應時間時,可以啟動一個程式將該節點從叢集中永久刪除,此過程稱為自動逐出。


(1)配置自動逐出

        群集中的每個節點監視群集中所有其它節點的組通訊響應時間。當叢集從一個節點響應延時,它會向延遲列表中生成一個關於該節點的條目。如果延遲節點在固定時間內再次響應,則該節點的條目將從延遲列表中移除。但如果節點接收到足夠多的延遲條目,並且在大多數叢集的延遲列表中都可以找到該條目,則會將延遲節點從叢集中永久逐出,被逐出的節點重啟後才能重新加入群集。


        通過wsrep_provider_options設定以下選項,可以配置自動逐出的引數:


evs.delayed_margin:節點響應時間大於該引數定義的時長,則將條目新增到延遲列表,預設為1秒。必須將此引數設定為高於節點之間的往返延時(Round-trip time,RTT)的值。

evs.delayed_keep_period:從被新增到延遲列表,到此引數定義的時間範圍內,如果該節點再次響應,則將其從延遲列表條目中刪除,預設為30秒。

evs.evict:如果設定為某個節點的UUID,則該節點將從叢集中逐出。

evs.auto_evict:定義節點在觸發自動逐出協議之前允許的延遲節點條目數,預設值為0,表示禁用節點上的自動逐出協議,但叢集繼續監視節點響應時間。

evs.version:此引數確定節點使用的EVS協議的版本。為了確保向後相容,預設值為0。啟用自動逐出需要將改引數設定為更高版本,例如在配置檔案中新增:

wsrep_provider_options="evs.version=1"

 


(2)檢查收回狀態

        可以通過Galera狀態變數檢查其逐出狀態。


wsrep_evs_state:提供evs協議的內部狀態。

wsrep_evs_delayed:提供延遲列表中以逗號分隔的節點列表。列表中使用的格式是uuid:address:count。計數是指給定延遲節點的條目數。

wsrep_evs_evict_list:列出被逐出節點的uuid。

6. Galera仲裁員

        Galera仲裁員是參與投票但不參與實際複製的群整合員。雖然Galera仲裁員不參與複製,也不儲存資料,但它接收的資料與所有其它節點相同,因此必須保證它的網路連線。當叢集具有偶數個節點時,仲裁員作為奇數節點發揮作用,以避免出現腦裂的情況。具有仲裁員的叢集架構如圖1所示。


MySQL高可用之GC-Galera Cluster for MySQL

圖1 Galera Arbitrator

 


        Galera仲裁員是Galera叢集的一個獨立守護程式,名為garbd。這意味著必須從叢集單獨啟動它,並且不能通過my.cnf配置檔案配置Galera仲裁員。可以從shell啟動仲裁員,或者作為服務執行。如何配置Galera仲裁員取決於如何啟動它。


        注意,Galera仲裁員啟動時,指令碼將在程式中以使用者nobody身份執行sudo語句。預設的sudo配置將阻止沒有tty訪問許可權的使用者操作。要更正此問題,編輯/etc/sudoers檔案並註釋掉此行:


Defaults requiretty

這將防止作業系統阻塞Galera仲裁員。


(1)從shell啟動Galera仲裁程式

1. 編輯配置檔案arbitrator.config,內容如下:


# arbitrator.config

group = mysql_galera_cluster

address = gcomm://172.16.1.125,172.16.1.126,172.16.1.127

2. 啟動仲裁員


garbd --cfg /var/lib/mysql/arbitrator.config &

(2)啟動Galera仲裁員服務

1. 編輯/etc/sysconfig/garb檔案,內容如下:


# 已存在的兩個節點地址

GALERA_NODES="172.16.1.125:4567 172.16.1.126:4567"    

# group名稱保持與兩節點的wsrep_cluster_name系統變數一致

GALERA_GROUP="mysql_galera_cluster"    

# 日誌檔案

LOG_FILE="/var/log/garb.log"

2. 修改日誌檔案屬性


touch /var/log/garb.log

chown nobody:nobody /var/log/garb.log

chmod 644 /var/log/garb.log

3. 啟動Galera仲裁員服務


systemctl start garb

(3)腦裂測試

1. 在節點3停止garb服務。


systemctl stop garb

2. 在節點2 drop掉去往第一個節點和仲裁員的資料包。


iptables -A OUTPUT -d 172.16.1.125 -j DROP

iptables -A OUTPUT -d 172.16.1.127 -j DROP

3. 檢查前節點1、2的狀態,都不是Synced,發生了腦裂。


mysql> show status like 'wsrep_local_state_comment';

+---------------------------+-------------+

| Variable_name             | Value       |

+---------------------------+-------------+

| wsrep_local_state_comment | Initialized |

+---------------------------+-------------+

1 row in set (0.00 sec)

4. 清除節點2的資料包過濾規則。


iptables -F

5. 啟動節點3的garb服務。


systemctl start garb

6. 前兩個節點檢視叢集節點數,結果是3,說明包括了仲裁節點。


mysql> show status like 'wsrep_cluster_size';

+--------------------+-------+

| Variable_name      | Value |

+--------------------+-------+

| wsrep_cluster_size | 3     |

+--------------------+-------+

1 row in set (0.00 sec)

7. 在節點2 drop掉去往第一個節點和仲裁員的資料包


iptables -A OUTPUT -d 172.16.1.125 -j DROP

iptables -A OUTPUT -d 172.16.1.127 -j DROP

8. 這時檢節點1的同步狀態,仍然是Synced,沒有發生腦裂。


mysql> show status like 'wsrep_local_state_comment';

+---------------------------+--------+

| Variable_name             | Value  |

+---------------------------+--------+

| wsrep_local_state_comment | Synced |

+---------------------------+--------+

1 row in set (0.00 sec)

9. 再在節點1檢視叢集節點數,結果是2,說明節點1成為叢集主元件。


mysql> show status like 'wsrep_cluster_size';

+--------------------+-------+

| Variable_name      | Value |

+--------------------+-------+

| wsrep_cluster_size | 2     |

+--------------------+-------+

1 row in set (0.00 sec)

10. 檢查節點2的同步狀態和叢集節點數,說明它已和叢集主元件斷開連線。


mysql> show status like 'wsrep_local_state_comment';

+---------------------------+-------------+

| Variable_name             | Value       |

+---------------------------+-------------+

| wsrep_local_state_comment | Initialized |

+---------------------------+-------------+

1 row in set (0.01 sec)

 

mysql> show status like 'wsrep_cluster_size';

+--------------------+-------+

| Variable_name      | Value |

+--------------------+-------+

| wsrep_cluster_size | 1     |

+--------------------+-------+

1 row in set (0.01 sec)

二、監控

        本節說明監控Galera叢集的主要方法,包括查詢狀態變數、使用指令碼監控和檢查資料庫伺服器日誌等。


1. 使用狀態變數

可以使用標準查詢檢查整個叢集中寫集複製的狀態:


mysql> show global status like 'wsrep_%';

+------------------------------+----------------------------------------------------------------+

| Variable_name                | Value                                                          |

+------------------------------+----------------------------------------------------------------+

| wsrep_local_state_uuid       | 4a6db23a-f9de-11e9-ba76-93e71f7c9a45                           |

| wsrep_protocol_version       | 9                                                              |

| ...                          | ...                                                            |

| wsrep_ready                  | ON                                                             |

+------------------------------+----------------------------------------------------------------+

60 rows in set (0.00 sec)

        下面列舉一些需要重點監控的狀態變數。


(1)檢查叢集完整性

        可以使用以下狀態變數檢查群集完整性:


wsrep_cluster_state_uuid:叢集狀態uuid,可以使用它確定節點是否屬於叢集的一部分。群集中的每個節點都應提供相同的值。當一個節點具有不同值時,表示它不再連線到叢集。一旦節點重新連線到叢集,該狀態變數的值變為與叢集其它節點一致。

wsrep_cluster_conf_id:發生群整合員身份更改的總數,可以使用它確定節點是否是主元件的一部分。群集中的每個節點都應提供相同的值。當一個節點具有不同值時,表示叢集已經發生網路分割槽。一旦節點重新連線到叢集,該狀態變數的值變為與叢集其它節點一致。

wsrep_cluster_size:叢集中的節點數量,可以使用它來確定是否缺少節點。當返回值小於叢集中的節點數時,表示某些節點已經與叢集失去連線。

wsrep_cluster_status:節點所在的群集主元件狀態,可用於確定群集是否處於網路分割槽狀態。節點的返回值只應該為primary,任何其它值都表示該節點是不可操作元件的一部分。這發生在多個成員的變化導致失去法定票數,或腦裂情況下。如果檢查群集中的所有節點都不返回Primary,則需要重置仲裁。

        當每個節點上的這些狀態變數都返回所需結果時,叢集具有完整性,這意味著複製可以在每個節點上正常進行。下一步是檢查節點狀態,以確保它們都處於工作狀態並能夠接收寫集。


(2)檢查節點狀態

        節點狀態顯示節點是否接收和處理來自群集寫集的更新,並可能揭示阻止複製的問題。


wsrep_ready:節點是否可以接受查詢。當節點返回值ON時,它可以接受來自叢集的寫集。當它返回值OFF時,所有查詢都將失敗,並出現錯誤:ERROR 1047 (08501) Unknown Command。

wsrep_connected:節點是否與任何其它節點連線。當該值為ON時,該節點與構成群集的一個或多個節點連線。當該值為OFF時,該節點沒有與任何群集其它節點的連線。連線丟失的原因可能與配置錯誤有關,例如wsrep_cluster_address或wsrep_cluster_name引數不對。檢查錯誤日誌以獲得正確的診斷。

wsrep_local_state_comment:節點狀態註釋。當節點是主元件的一部分時,典型的返回值是join、waiting on sst、joined、synced或donor。如果節點是不可操作元件的一部分,則返回值為Initialized。如果節點返回除此以外的值,則狀態註釋是瞬時的,應再次檢查狀態變數以獲取更新。

        如果每個狀態變數返回所需的值,則節點處於工作狀態,這意味著它正在從叢集接收寫集並將它們複製到本地資料庫中的表中。


(3)檢查複製執行狀況

        群集完整性和節點狀態相關變數可以反映阻止複製的問題。而以下狀態變數將有助於識別效能問題。這些變數是變化的,每次執行FLUSH STATUS後都會重置。


wsrep_local_recv_queue_avg:自上次FLUSH STATUS以來本地接收佇列的平均事務數。當節點返回一個大於0的值時,說明應用寫集慢於接收寫集,一個較大值可能觸發流控。除此狀態變數外,還可以使用wsrep_local_recv_queue_max和wsrep_local_recv_queue_min檢視節點本地接收佇列的最大、最小值。

wsrep_flow_control_paused:自上次FLUSH STATUS以來節點因流控而暫停的時長。如果flush status和show status之間的時間為1分鐘,並且節點返回0.25,則表示該節點在該時間段內總共暫停了15秒。返回0時,表示該節點在此期間沒有由於流控而暫停。返回1時,表示該節點在整個時段都處於暫停複製狀態。理想情況下,返回值應儘可能接近0,如果發現節點經常暫停,可以調整wsrep_slave_threads引數增加應用寫集的執行緒數,也可以從叢集中移除該節點。

wsrep_cert_deps_distance:節點可能並行應用的事務序號之差,表示節點的並行化程度。可與wsrep_slave_threads引數配合使用,wsrep_slave_threads的值不應該大於此狀態變數的值。

(4)檢測網路

wsrep_local_send_queue_avg:自上次FLUSH STATUS以來傳送佇列中的平均事務數。如果該值遠大於0,表示網路吞吐量可能有問題。從伺服器的物理元件到作業系統配置,任何層級都可能導致出現此問題。除此狀態變數外,還可以使用wsrep_local_send_queue_max和wsrep_local_send_queue_min檢視節點本地傳送佇列的最大、最小值。

2. 使用通知指令碼

        固然可以通過查詢狀態變數獲得叢集狀態、節點狀態和複製的執行狀況,但登入每個節點執行此類查詢是何等繁瑣。作為更好的替代方法,Galera叢集提供了一種叫做通知指令碼(notification script)的方法,可以通過定製指令碼來自動化叢集的監控過程。我們先來看一下Galera自帶的示例指令碼。


[root@hdp2~]#more /usr/share/mysql/wsrep_notify 

#!/bin/sh -eu

 

# This is a simple example of wsrep notification script (wsrep_notify_cmd).

# It will create 'wsrep' schema and two tables in it: 'membeship' and 'status'

# and fill them on every membership or node status change.

#

# Edit parameters below to specify the address and login to server.

 

USER=root

PSWD=rootpass

HOST=127.0.0.1

PORT=3306

 

SCHEMA="wsrep"

MEMB_TABLE="$SCHEMA.membership"

STATUS_TABLE="$SCHEMA.status"

 

BEGIN="

SET wsrep_on=0;

DROP SCHEMA IF EXISTS $SCHEMA; CREATE SCHEMA $SCHEMA;

CREATE TABLE $MEMB_TABLE (

    idx  INT UNIQUE PRIMARY KEY,

    uuid CHAR(40) UNIQUE, /* node UUID */

    name VARCHAR(32),     /* node name */

    addr VARCHAR(256)     /* node address */

) ENGINE=MEMORY;

CREATE TABLE $STATUS_TABLE (

    size   INT,      /* component size   */

    idx    INT,      /* this node index  */

    status CHAR(16), /* this node status */

    uuid   CHAR(40), /* cluster UUID */

    prim   BOOLEAN   /* if component is primary */

) ENGINE=MEMORY;

BEGIN;

DELETE FROM $MEMB_TABLE;

DELETE FROM $STATUS_TABLE;

"

END="COMMIT;"

 

configuration_change()

{

    echo "$BEGIN;"

 

    local idx=0

 

    for NODE in $(echo $MEMBERS | sed s/,/\ /g)

    do

        echo "INSERT INTO $MEMB_TABLE VALUES ( $idx, "

        # Don't forget to properly quote string values

        echo "'$NODE'" | sed  s/\\//\',\'/g

        echo ");"

        idx=$(( $idx + 1 ))

    done

 

    echo "INSERT INTO $STATUS_TABLE VALUES($idx, $INDEX, '$STATUS', '$CLUSTER_UUID', $PRIMARY);"

 

    echo "$END"

}

 

status_update()

{

    echo "SET wsrep_on=0; BEGIN; UPDATE $STATUS_TABLE SET status='$STATUS'; COMMIT;"

}

 

COM=status_update # not a configuration change by default

 

while [ $# -gt 0 ]

do

    case $1 in

    --status)

        STATUS=$2

        shift

        ;;

    --uuid)

        CLUSTER_UUID=$2

        shift

        ;;

    --primary)

        [ "$2" = "yes" ] && PRIMARY="1" || PRIMARY="0"

        COM=configuration_change

        shift

        ;;

    --index)

        INDEX=$2

        shift

        ;;

    --members)

        MEMBERS=$2

        shift

        ;;

    esac

    shift

done

 

# Undefined means node is shutting down

if [ "$STATUS" != "Undefined" ]

then

    $COM | mysql -B -u$USER -p$PSWD -h$HOST -P$PORT

fi

 

exit 0

#

[root@hdp2~]#

        該指令碼先定義了一個建立資料庫表語句的字串,然後定義了兩個函式維護表資料,最後給出如何處理通知引數。


(1)通知引數

        當節點在自身或叢集中註冊更改時,它將觸發通知指令碼執行,並把一些引數傳遞給通知指令碼。下面是引數列表及其基本含義:


        --status:節點傳遞一個指示其當前狀態的字串,值是以下六個值之一。


Undefined:表示不屬於主元件的節點。

Joiner:表示作為主元件一部分並正在接收狀態快照傳輸(SST)的節點。

Donor:表示作為主元件一部分並正在傳送狀態快照傳輸(SST)的節點。

Joined:表示作為主元件一部分的節點,該節點處於完成加入叢集的狀態並正在追趕群集。

Synced:表示與群集同步的節點。

Error:表示發生了錯誤。此狀態字串可能會提供一個錯誤程式碼,其中包含有關發生情況的詳細資訊。

        通知指令碼必須捕獲--status引數的值並執行相應的操作。


        --uuid:傳一個表示節點UUID的字串。


        --primary:傳一個yes或no的字串,標識它是否認為自己是主元件的一部分。


        --members:傳當前群整合員列表,格式為 <node UUID> / <node name> / <incoming address>。Node UUID 指節點唯一識別符號,Node Name 指wsrep_node_name引數定義的節點名,Incoming Address 指客戶端連線的IP地址,由引數wsrep_node_incoming_address設定,預設值為auto。


        --index:傳一個字串,該字串指示其在成員資格列表中的索引值。


(2)啟用通知指令碼

        可以通過配置檔案中的wsrep_notify_cmd引數啟用通知指令碼。在每個節點上建立可執行的shell檔案/home/mysql/wsrep_notify.sh,然後設定wsrep_notify_cmd引數值為/home/mysql/wsrep_notify.sh。


cp /usr/share/mysql/wsrep_notify /home/mysql/wsrep_notify.sh

chown mysql:mysql /home/mysql/wsrep_notify.sh

chmod 755 /home/mysql/wsrep_notify.sh

sed -i 's/rootpass/P@sswo2d/' /home/mysql/wsrep_notify.sh

mysql -uroot -pP@sswo2d -e "set global wsrep_notify_cmd='/home/mysql/wsrep_notify.sh';"

節點將為叢集成員資格和節點狀態的每次更改呼叫指令碼。下面測試指令碼執行情況:


1. 在節點2 drop掉去往第一、三個節點的資料包。


iptables -A OUTPUT -d 172.16.1.125 -j DROP

iptables -A OUTPUT -d 172.16.1.127 -j DROP

2. 去掉資料包過濾


iptables -F

3. 在節點2上查詢wsrep庫表


[root@hdp3/var/lib/mysql]#mysql -uroot -pP@sswo2d -e "select * from wsrep.membership;select * from wsrep.status;"

mysql: [Warning] Using a password on the command line interface can be insecure.

+-----+--------------------------------------+-------+-------------------+

| idx | uuid                                 | name  | addr              |

+-----+--------------------------------------+-------+-------------------+

|   0 | 605dc61c-fa2e-11e9-8b01-9f8f00127724 | node3 | 172.16.1.127:3306 |

|   1 | 6c468740-fa1a-11e9-8214-62a1abb74da6 | node2 | 172.16.1.126:3306 |

|   2 | ac8e4a3f-fadb-11e9-ad70-0a894466f015 | node1 | 172.16.1.125:3306 |

+-----+--------------------------------------+-------+-------------------+

+------+------+--------+--------------------------------------+------+

| size | idx  | status | uuid                                 | prim |

+------+------+--------+--------------------------------------+------+

|    3 |    1 | Synced | 4a6db23a-f9de-11e9-ba76-93e71f7c9a45 |    1 |

+------+------+--------+--------------------------------------+------+

[root@hdp3/var/lib/mysql]#

        利用iptables資料包過濾,使節點2的狀態發生變化,此時觸發執行了通知指令碼。這裡只使用了Galera自帶的示例指令碼,可以將它作為編寫自定義通知指令碼的起點,如加入響應群集更改的警報等。


3. 使用資料庫伺服器日誌

        log_error系統變數指定MySQL伺服器錯誤日誌檔名,預設將寫入錯誤日誌資料目錄中的<hostname>.err檔案。Galera群集提供引數和wsrep選項,啟用錯誤日誌記錄複製衝突事件。


wsrep_log_conflicts: 此引數啟用錯誤日誌的衝突日誌記錄,例如兩個節點試圖同時寫入同一表的同一行,預設為OFF。

cert.log_conflicts: 此wsrep_provider_options選項允許在複製期間記錄有關驗證失敗的資訊,預設為no。

wsrep_debug: 此引數啟用資料庫伺服器日誌的除錯資訊,預設為OFF。

        可以通過my.cnf配置檔案啟用這些功能:


wsrep_log_conflicts=ON

wsrep_provider_options="cert.log_conflicts=ON"

wsrep_debug=ON

        注意,wsrep_debug引數會將資料庫伺服器的連線密碼記錄到錯誤日誌中。這是一個安全漏洞,因此不要在生產環境中啟用它。


        除MySQL伺服器日誌外,如果wsrep_sst_method指定為xtrabackup,Galera還會將SST資訊記錄到資料目錄下的innobackup.backup.log檔案中。當一個節點無法應用事務時,MySQL伺服器就在資料目錄中建立該事件的特殊二進位制日誌檔案,檔案命名為GRA_*.log。該檔案的讀取參見https://community.pivotal.io/s/article/How-to-decode-Galera-GRA-logs-for-MySQL-for-PCF-v1-10


參考:

MariaDB Galera Cluster部署實戰





Galera Cluster for MySQL 詳解(四)——效能測試



一、測試目標


二、測試規劃


三、測試過程


1. 預設配置


2. 多執行緒


3. 流控


四、測試結論


參考:


        本篇使用tpcc-mysql壓測工具對實驗環境的三節點Galera叢集進行一系列效能測試。


一、測試目標

驗證Galera的同步複製,檢查是否存在複製延遲。

對比Galera與MySQL組複製的每秒事務數(TPS)。

驗證多執行緒複製對Galera效能的影響。

驗證流控對Galera效能的影響。

二、測試規劃

        這裡採用與MySQL組複製效能測試相同的環境和方法,但組複製與Galera使用的MySQL版本不同。組複製測試用的是MySQL 8.0.16版本,而Galera測試用的是Galera Cluster for MySQL 5.7。之所以版本不同,是因為我在測試時使用的都是當時的最新版本。


節點1:172.16.1.125

節點2:172.16.1.126

節點3:172.16.1.127


        具體思路與環境參見https://wxy0327.blog.csdn.net/article/details/97782304#2.%20%E6%B5%8B%E8%AF%95%E8%A7%84%E5%88%92。需要注意tpcc-mysql與Galera叢集的相容性,並不是所有版本的tpcc-mysql安裝包都支援Galera。在我的環境中,最新的tpcc-mysql-master在Galera Cluster for MySQL 5.7上執行資料裝載(tpcc_load)時就報錯。


        Galera是多主複製,叢集中的多個節點對等。為了便於與MySQL組複製推薦的單主模式進行比較,我們只在Galera叢集的節點1上執行壓測。Galera使用自己定義的GTID,當前版本也沒有提供類似master_pos_wait或wait_for_executed_gtid_set類似功能的函式,因此需要修改測試指令碼獲得壓測在節點2和節點3上的執行時間。修改後的tpcc_test.sh 檔案內容如下:


[mysql@hdp1~/tpcc-mysql]$more tpcc_test.sh 

# 初始化tpcc資料

mysql -uwxy -pP@sswo2d -h172.16.1.125 -Dtpcc_test < tpcc_test.sql

 

# 獲取節點1的last_committed用於比較

read last_committed < <(mysql -uwxy -pP@sswo2d -h172.16.1.125 -e "show status like 'wsrep_last_committed';" --skip-column-names | awk '{prin

t $2}' | sed "s/\\\n//g")

 

# 等待其它兩個節點執行完初始化複製

read last_committed_1 < <(mysql -uwxy -pP@sswo2d -h172.16.1.126 -e "show status like 'wsrep_last_committed';" --skip-column-names | awk '{pr

int $2}' | sed "s/\\\n//g")

read last_committed_2 < <(mysql -uwxy -pP@sswo2d -h172.16.1.127 -e "show status like 'wsrep_last_committed';" --skip-column-names | awk '{pr

int $2}' | sed "s/\\\n//g")

 

while [ $last_committed_1 -lt $last_committed -o $last_committed_2 -lt $last_committed ]

do

    read last_committed_1 < <(mysql -uwxy -pP@sswo2d -h172.16.1.126 -e "show status like 'wsrep_last_committed';" --skip-column-names | awk 

'{print $2}' | sed "s/\\\n//g")

    read last_committed_2 < <(mysql -uwxy -pP@sswo2d -h172.16.1.127 -e "show status like 'wsrep_last_committed';" --skip-column-names | awk 

'{print $2}' | sed "s/\\\n//g")

done

 

# 開始時間

start_time=`date '+%s'`

 

# 開始事務序號

read start_last_committed < <(mysql -uwxy -pP@sswo2d -h172.16.1.125 -e "show status like 'wsrep_last_committed';" --skip-column-names | awk 

'{print $2}' | sed "s/\\\n//g")

 

# 節點1執行壓測,10個倉庫,32個併發執行緒,預熱1分鐘,壓測5分鐘

tpcc_start -h172.16.1.125 -d tpcc_test -u wxy -p "P@sswo2d" -w 10 -c 32 -r 60 -l 300 > tpcc_test.log 2>&1

 

# 獲取節點1的last_committed用於比較

read last_committed < <(mysql -uwxy -pP@sswo2d -h172.16.1.125 -e "show status like 'wsrep_last_committed';" --skip-column-names | awk '{prin

t $2}' | sed "s/\\\n//g")

 

# 等待其它兩個節點執行完複製

read last_committed_1 < <(mysql -uwxy -pP@sswo2d -h172.16.1.126 -e "show status like 'wsrep_last_committed';" --skip-column-names | awk '{pr

int $2}' | sed "s/\\\n//g")

read last_committed_2 < <(mysql -uwxy -pP@sswo2d -h172.16.1.127 -e "show status like 'wsrep_last_committed';" --skip-column-names | awk '{pr

int $2}' | sed "s/\\\n//g")

 

while [ $last_committed_1 -lt $last_committed -o $last_committed_2 -lt $last_committed ]

do

    if [ $last_committed_1 -lt $last_committed ] 

    then

        read last_committed_1 < <(mysql -uwxy -pP@sswo2d -h172.16.1.126 -e "show status like 'wsrep_last_committed';" --skip-column-names | 

awk '{print $2}' | sed "s/\\\n//g")

    else

        end_time1=`date '+%s'`

    fi

    

    if [ $last_committed_2 -lt $last_committed ] 

    then

        read last_committed_2 < <(mysql -uwxy -pP@sswo2d -h172.16.1.127 -e "show status like 'wsrep_last_committed';" --skip-column-names | 

awk '{print $2}' | sed "s/\\\n//g")

    else

        end_time2=`date '+%s'`

    fi

done

 

if [ ! $end_time1 ]; then

    end_time1=`date '+%s'`

fi

 

if [ ! $end_time2 ]; then

    end_time2=`date '+%s'`

fi

 

# 複製執行時長

elapsed1=$(($end_time1 - $start_time))

elapsed2=$(($end_time2 - $start_time))

 

# 執行的事務數

trx=$(($last_committed - $start_last_committed))

 

# 計算三個節點的TPS

Master_TPS=`expr $trx / 360`

Slave1_TPS=`expr $trx / $elapsed1`

Slave2_TPS=`expr $trx / $elapsed2`

 

# 列印輸出

echo "TRX: $trx" 

echo "Node1 TPS: $Master_TPS"

echo "Elapsed1: $elapsed1" "Node2 TPS: $Slave1_TPS"

echo "Elapsed2: $elapsed2" "Node3 TPS: $Slave2_TPS"

 

[mysql@hdp1~/tpcc-mysql]$

        當三個節點的last_committed相等時,它們執行了相同的事務數。如果存在複製延遲,節點2或節點3會比節點1後執行到last_committed點。


三、測試過程

        每次測試只需要執行tpcc_test.sh即可。


1. 預設配置

        獲得預設配置的測試結果,作為後面不同配置的對比基準。測試結果如下:


TRX: 76472 

Node1 TPS: 212

Elapsed1: 360 Node2 TPS: 212

Elapsed2: 360 Node3 TPS: 212

        可以看到,雖然Galera只是虛擬同步複製,每個節點上的事務驗證是非同步的,但實際測試中沒有複製延遲,壓測節點1與複製節點2、3的執行時間和TPS相同。這點與組複製大相徑庭。單主模式的組複製中,相同壓測主庫比從庫的TPS高一倍。另一方面,預設配置組複製中主庫的TPS比Galera高一倍,也就是說Galera的效能與單主模式組複製中的從庫大致相當。因為兩者MySQL版本不同,這裡的測試結果只作參考。


2. 多執行緒

        上篇文章提到wsrep_cert_deps_distance狀態變數指示並行提交的事務序號之差,可用作wsrep_slave_threads的參考值。


mysql> show status like 'wsrep_cert_deps_distance';

+--------------------------+-----------+

| Variable_name            | Value     |

+--------------------------+-----------+

| wsrep_cert_deps_distance | 56.673657 |

+--------------------------+-----------+

1 row in set (0.00 sec)

        wsrep_cert_deps_distance的值為56,因此在三個節點執行下面的SQL命令,指定複製執行緒數為60。


set global wsrep_slave_threads=60;

再次執行測試,結果如下,TPS提高了40%:


TRX: 106848 

Node1 TPS: 296

Elapsed1: 360 Node2 TPS: 296

Elapsed2: 360 Node3 TPS: 296

3. 流控

        查詢流控相關的狀態變數:


mysql> show status like 'wsrep_flow_control_%';

+------------------------------+--------------+

| Variable_name                | Value        |

+------------------------------+--------------+

| wsrep_flow_control_paused_ns | 947249076448 |

| wsrep_flow_control_paused    | 0.037075     |

| wsrep_flow_control_sent      | 0            |

| wsrep_flow_control_recv      | 932          |

+------------------------------+--------------+

4 rows in set (0.00 sec)

        接收佇列中的事務數超過gcs.fc_limit時觸發流控,節點將暫停複製,gcs.fc_limitde的預設值16顯然太小。在三個節點執行下面的SQL命令,指定流控限制為1000。


set global wsrep_provider_options = 'gcs.fc_limit = 1000';

再次執行測試,流控狀態變數的值如下,確認沒有觸發流控。


mysql> show status like 'wsrep_flow_control_%';

+------------------------------+--------------+

| Variable_name                | Value        |

+------------------------------+--------------+

| wsrep_flow_control_paused_ns | 947249076448 |

| wsrep_flow_control_paused    | 0.000000     |

| wsrep_flow_control_sent      | 0            |

| wsrep_flow_control_recv      | 0            |

+------------------------------+--------------+

4 rows in set (0.00 sec)

測試結果如下:


TRX: 103760 

Node1 TPS: 288

Elapsed1: 361 Node2 TPS: 287

Elapsed2: 361 Node3 TPS: 287

        可見,是否觸發流控對於TPS並沒有明顯影響。


四、測試結論

Galera是同步複製,節點間無延遲。

Galera比單主模式組複製中的主庫,TPS相差一半。

wsrep_slave_threads引數對TPS影響較大。

是否觸發流控對TPS沒有明顯影響。

參考:

https://blog.csdn.net/chenhaifeng2016/article/details/77530569

https://www.percona.com/blog/2017/04/19/performance-improvements-percona-xtradb-cluster-5-7-17/

http://mysqlhighavailability.com/performance-evaluation-mysql-5-7-group-replication/?spm=5176.100239.blogcont66550.17.T4N8cZ















About Me

........................................................................................................................

● 本文作者:小麥苗,部分內容整理自網路,若有侵權請聯絡小麥苗刪除

● 本文在itpub、部落格園、CSDN和個人微 信公眾號( xiaomaimiaolhr)上有同步更新

● 本文itpub地址: http://blog.itpub.net/26736162

● 本文部落格園地址: http://www.cnblogs.com/lhrbest

● 本文CSDN地址: https://blog.csdn.net/lihuarongaini

● 本文pdf版、個人簡介及小麥苗雲盤地址: http://blog.itpub.net/26736162/viewspace-1624453/

● 資料庫筆試面試題庫及解答: http://blog.itpub.net/26736162/viewspace-2134706/

● DBA寶典今日頭條號地址: http://www.toutiao.com/c/user/6401772890/#mid=1564638659405826

........................................................................................................................

● QQ群號: 230161599 、618766405

● 微 信群:可加我微 信,我拉大家進群,非誠勿擾

● 聯絡我請加QQ好友 646634621 ,註明新增緣由

● 於 2020-02-01 06:00 ~ 2020-02-31 24:00 在西安完成

● 最新修改時間:2020-02-01 06:00 ~ 2020-02-31 24:00

● 文章內容來源於小麥苗的學習筆記,部分整理自網路,若有侵權或不當之處還請諒解

● 版權所有,歡迎分享本文,轉載請保留出處

........................................................................................................................

小麥苗的微店https://weidian.com/s/793741433?wfr=c&ifr=shopdetail

小麥苗出版的資料庫類叢書http://blog.itpub.net/26736162/viewspace-2142121/

小麥苗OCP、OCM、高可用網路班http://blog.itpub.net/26736162/viewspace-2148098/

小麥苗騰訊課堂主頁https://lhr.ke.qq.com/

........................................................................................................................

使用 微 信客戶端掃描下面的二維碼來關注小麥苗的微 信公眾號( xiaomaimiaolhr)及QQ群(DBA寶典)、新增小麥苗微 信, 學習最實用的資料庫技術。

........................................................................................................................

歡迎與我聯絡

 

 



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26736162/viewspace-2676344/,如需轉載,請註明出處,否則將追究法律責任。

相關文章