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

目錄

一、管理

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工作原理其實很簡單:

  1. 如果存在外鍵,根據alter-foreign-keys-method參數的值,檢測外鍵相關的表,做相應設置的處理。如果被修改表存在外鍵定義但沒有使用 --alter-foreign-keys-method 指定特定的值,該工具不予執行。
  2. 創建一個新的表,表結構爲修改後的數據表,用於從源數據表向新表中導入數據。
  3. 創建觸發器,用於記錄從拷貝數據開始之後,對源數據表繼續進行數據修改的操作記錄下來,數據拷貝結束後,執行這些操作,保證數據不會丟失。如果表中已經定義了觸發器這個工具就不能工作了。
  4. 拷貝數據,從源數據表中拷貝數據到新表中。
  5. 修改外鍵相關的子表,根據修改後的數據,修改外鍵關聯的子表。
  6. rename源數據表爲old表,把新表rename爲源表名,並將old表刪除。
  7. 刪除觸發器。

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所示。

圖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

參考:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章