Galera replication for MySQL
這篇文章總結了之前對Galera replication的調研,內容包括Galera特性,原理,Galera cluster配置,參數及性能等
Galera replication是什麼
MySQL DBA及開發應該都知道MySQL源生複製及semi-sync半同步複製,它們都基於MySQL binlog,原生複製是完全異步的,master不需要保證slave接收並執行了binlog,能夠保證master最大性能,但是slave可能存在延遲,主備數據無法保證一致性,在不停服務的前提下如果master宕機讓slave頂上,就會丟失數據,semi-sync在異步複製基礎上增加了數據保護的考慮,master必須確認slave收到binlog後(但不保證slave執行了事務)才能最終提交事務,在沒有退化(延遲較大時可能發生)成異步複製之前可以保證數據安全,此時master掛掉之後,slave可以在apply完所有relay log後切換成master提供讀寫服務
Galera replication是codership提供的MySQL數據同步方案,具有高可用,易於擴展等特點,它將多個MySQL節點組織成一個cluster
Galera replication特性
1. 同步複製,主備無延遲
2. 支持多主同時讀寫,保證數據一致性
3. 集羣中各節點保存全量數據
4. 節點添加/刪除,自動檢測和配置
5. 行級別並行複製
6. 不需要寫binlog
相對於MySQL源生複製和semi-sync,Galera replication比較有吸引力的特性:
1. 同步複製,主備無延遲,master宕機後slave可以立即頂上並提供服務(semi-sync需要apply完所有relay log)
2. 事務衝突檢測保證數據一致性,多個節點可以同時讀寫數據,可以極大簡化數據訪問
3. 行級別並行複製,MySQL 5.6之前slave sql線程只有一個,這個長期飽受詬病,是導致slave落後master的主要原因
Galera replicateion限制
1. 集羣至少3個節點(2個節點也可以運行)
2. 存儲引擎:Innodb / XtraDB / Maria
3. 不支持的SQL:LOCK / UNLOCK TABLES / GET_LOCK(), RELEASE_LOCK()…
4. 不支持XA Transaction
目前可用的產品:MariaDB Galera Cluster 和 Percona XtraDB Cluster
Galera replication原理
Galera replication是一種Certification based replication,保證one-copy serializability,理論基於這兩篇論文:Don’t be lazy, be consistent 和 Database State Machine Approach
算法示意圖
算法僞代碼(Certification包含了後續流程,來自上面兩篇論文)
事務執行協議
遵守deferred update replication,事務在commit時才複製到其他節點,執行過程分爲4個階段:
1.Local read phase a) 本地(client連接到的節點)執行事務Ti,但不真正提交,真正提交之前進入Send phase 2.Send phase a) 若事務只讀,直接提交,結束(多版本,只讀事務不加鎖) b) 將事務的寫操作封裝成WS(Write Set,基於行),廣播到所有節點(包括自身) 3.Lock / Certificaion phase a) 對收到的WS中的每個WSi(X) i. 若X沒有被加鎖,對X加鎖 ii. 若X已被Tj加鎖且Tj處於Local read phase/Send phase,回滾Tj,對X加鎖 iii. Certification based conflict detect 4.Write phase a) 若檢測出衝突,回滾Ti b) 否則,執行WS,提交事務後釋放鎖資源 c) 對於源節點,提交事務並向client返回結果 |
客戶端/Galera節點信息交互圖
Galera replication採取的是樂觀策略,即事務在一個節點提交時,被認爲與其他節點上的事務沒有衝突,首先在本地“執行”(之所以帶引號,是因爲事務沒有執行完)後再發送到所有節點做衝突檢測,存在兩種情況下需要回滾事務:
1. WS複製到其它節點,被加到每個節點的slave trx queue中,與queue中前面的trxs在做certification test時發現衝突
2. WS通過了certification test後被保證一定會執行,在它執行過程中,如果該節點上有與其衝突的local trxs(Local phase),回滾local trxs
Galera提供了兩個狀態參數記錄衝突:
wsrep_local_cert_failures:certification test中未通過的trx數目
wsrep_local_bf_aborts:apply trxs(已經通過certification test)時,回滾的local trxs(open but not commit)數目
因此事務在commit節點廣播後,節點之間不交換“是否衝突”的信息,各個節點獨立異步的處理該事務,certification based replication協議保證:
1. 事務在所有節點上要麼都commit,要麼都rollback/abort
2. 事務在所有節點的執行順序一致
Certification based replication所依賴的基礎技術:
Group Communication System
1) Atomic delivery (事務傳輸要麼成功傳給了所有節點,要麼都失敗)
2) Total order (事務在所有節點中的順序一致)
3) Group maintenance (每個節點知道所有節點的狀態)
傳統的2PC(兩階段提交)做法
1. 2PC 事務結束時,所有節點數據達到一致
2. 協調者與參與者之間通信,參與者之間無連接
3. 受網絡狀態影響較大
4. 兩次通信,需要得到每個參與者的反饋後才能決定是否提交事務
因此Galera replicateion相對於2PC減少了網絡傳輸次數,消除了等待節點返回“決定是否衝突”的時間,從而可以提高了性能
Galera replication原理總結
1. 事務在本地節點執行時採取樂觀策略,成功廣播到所有節點後再做衝突檢測
2. 檢測出衝突時,本地事務優先被回滾
3. 每個節點獨立、異步執行隊列中的WS
4. 事務T在A節點執行成功返回客戶端後,其他節點保證T一定會被執行,因此有可能存在延遲,即虛擬同步
Galera flow control
galera是同步複製(虛擬同步)方案,事務在本地節點(客戶端提交事務的節點)上提交成功時,其它節點保證執行該事務。在提交事務時,本地節點把事務複製到所有節點後,之後各個節點獨立異步地進行certification test、事務插入待執行隊列、執行事務。然而由於不同節點之間執行事務的速度不一樣,長時間運行後,慢節點的待執行隊列可能會越積越長,最終可能導致事務丟失。
galera內部實現了flow control,作用就是協調各個節點,保證所有節點執行事務的速度大於隊列增長速度,從而避免丟失事務。實現原理和簡單:整個galera cluster中,同時只有一個節點可以廣播消息(數據),每個節點都會獲得廣播消息的機會(獲得機會後也可以不廣播),當慢節點的待執行隊列超過一定長度後,它會廣播一個FC_PAUSE消息,所以節點收到消息後都會暫緩廣播消息,直到該慢節點的待執行隊列長度減小到一定長度後,galera cluster數據同步又開始恢復
flow control相關參數:
gcs.fc_limit:待執行隊列長度超過該值時,flow control被觸發,對於Master-Slave模式(只在一個節點寫)的galera cluster,可以配置一個較大的值,對啓動多寫的galera cluster,較小的值比較合適,因爲較大待執行隊列長度意味着更大的衝突,默認值16
gcs.fc_factor:當待執行隊列長度開始小於(gcs.fc_factor*gcs.fc_limit)時,數據同步恢復,默認0.5
gcs.fc_master_slave:galera cluster是否爲Master-Slave模式,默認
安裝MariaDB Galera Cluster
安裝準備:
1. MariaDB Galera Cluster 5.5.28a RC
1) https://downloads.mariadb.org/mariadb-galera/5.5.28a/
2) patched MariaDB 5.5.28,代碼中增加了Galera Library API(wsrep API),並在事務、鎖、handler等模塊添加/修改了調用邏輯
2. Galera wsrep provider
1) https://launchpad.net/galera/+download
2) Galera Library的實現,其中實現了group communication system, certification
編譯安裝
1. MariaDB Galera Cluster 5.5.28a RC
1) 與MariaDB基本相同,cmake時增加兩項:-DWITH_WSREP=ON , -DWITH_INNODB_DISALLOW_WRITES=1.
2. Galera wsrep provider: 源碼編譯後得到libgalera_smm.so(需要用到scons)
參數配置(每個節點)
wsrep_provider = /path/to/libgalera_smm.so
wsrep_cluster_address = cluster connection URL(後面詳細介紹)
binlog_format = ROW
default_storage_engine = INNODB
innodb_autoinc_lock_mode = 2
innodb_locks_unsafe_for_binlog = 1
選配:(可以提高性能,galera保證不丟數據)
innodb_flush_log_at_trx_commit = 2
構建集羣(三個節點)
節點名稱 | IP地址 |
---|---|
galera_node1 | 10.0.0.11 |
galera_node2 | 10.0.0.22 |
galera_node3 | 10.0.0.33 |
新建Galera Cluster
以galera_node1作爲第一個節點新建集羣,在my.cnf中配置參數:
wsrep_cluster_address = gcomm:// wsrep_cluster_name = galera_cluster wsrep_node_address = 10.0.0.11 wsrep_node_name = galera_node1 wsrep_sst_method = rsync |
添加galera_node2節點
在my.cnf中配置wsrep_cluster_address爲node1的ip或者hostname
wsrep_cluster_address = gcomm://10.0.0.11 wsrep_cluster_name = galera_cluster wsrep_node_address = 10.0.0.22 wsrep_node_name = galera_node2 wsrep_sst_method = rsync |
添加galera_node3節點
在my.cnf中配置wsrep_cluster_address爲node1的ip或者hostname
wsrep_cluster_address = gcomm://10.0.0.11 wsrep_cluster_name = galera_cluster wsrep_node_address = 10.0.0.33 wsrep_node_name = galera_node3 wsrep_sst_method = rsync |
多實例配置
因爲測試機器資源有限,需要在同一臺機器上啓動多個mysqld實例,爲每個mysqld配置兩個端口號(一個是mysql server端口號,默認3306;另外一個是wsrep端口號,默認4567),並修改部分wsrep配置參數,例如:
節點名稱 | IP地址 | SERVER PORT | WSREP PORT | WSREP配置 |
---|---|---|---|---|
galera_node1 | 127.0.0.1 | 3306 | 4405 | wsrep_cluster_address=gcomm:// wsrep_node_address=127.0.0.1:4405 port=3306 |
galera_node2 | 127.0.0.1 | 3307 | 4407 | wsrep_cluster_address=gcomm://127.0.0.1:4405 wsrep_node_address=127.0.0.1:4407 port=3307 |
galera_node3 | 127.0.0.1 | 308 | 4409 | wsrep_cluster_addres=gcomm:// 127.0.0.1:4405 wsrep_node_address=127.0.0.1:4409 port=3308 |
啓動後在每個節點執行:
|
當看到下述狀態時:
wsrep_connected=ON wsrep_ready=ON wsrep_cluster_status =Primary wsrep_cluster_size=3(節點個數) |
則galera集羣建立成功,如下圖所示:
說明:
1. MariaDB Galera Cluster 5.5.28a RC源碼安裝,在編譯時若沒有打開-DWITH_WSREP=ON, -DWITH_INNODB_DISALLOW_WRITES=1,或者沒有配置任何wsrep相關參數,它運行時就是一個普通的mysqld實例
2. Galera cluster複製不依賴於binlog文件,因此mysql-binlog和log-slave-updates都可以不配置,當然如果需要記錄binlog,也可以打開
3. 需要以wsrep_cluster_address = gcomm://啓動第一個節點後,才能相繼添加其他節點
Galera相關參數配置
InnoDB 相關參數
galera補丁版的mysql在cmake時需要指定:
-DWITH_WSREP=ON , -DWITH_INNODB_DISALLOW_WRITES=1
galera 目前只支持Innodb/xtradb/mariad存儲引擎
default_storage_engine = INNODB
爲了降低衝突,下列兩項需要設置
innodb_autoinc_lock_mode = 2
innodb_locks_unsafe_for_binlog = 1(gap不加鎖)
選配:(可以提高性能,galera保證不丟數據)
innodb_flush_log_at_trx_commit = 2
選配:galera可以不寫binlog,註釋binlog路徑理論上可以提高性能
#log-bin
#log-slave-updates=1
wsrep 相關參數
wsrep參數都是以wsrep_開頭的(30+個),其中有一個字符串參數(wsrep_provider_options)可以配置50+個更底層的參數。
可以通過“show variables like wsrep%”查看,wsrep_開頭參數,點擊查看詳情
列舉幾個重要的參數:
wsrep_auto_increment_control:控制auto_increment_increment=#nodes和auto_increment_offset=#node_id,默認ON wsrep_causal_reads:默認是在本地節點讀,讀到的可能不是最新數據,開啓後將讀到最新數據,但會增加響應時間,默認OFF wsrep_certify_nonPK:爲沒有顯示申明主鍵的表生成一個用於certification test的主鍵,默認ON wsrep_cluster_address: 啓動節點時需要指定galera cluster的地址,作爲cluster中第一個啓動的節點,wsrep_cluster_address=gcomm://,對於後續啓動的節點,wsrep_cluster_address=gcomm://node1,node2,node3 wsrep_cluster_name: 所有node必須一樣, 默認my_test_cluster wsrep_convert_LOCK_to_trx:將LOCK/UNLOCK TABLES轉換成BEGIN/COMMIT,默認OFF wsrep_data_home_dir:galera會生成一些文件,默認使用mysql_data_dir,默認mysql_data_dir wsrep_node_name:節點名稱 wsrep_on:session/global,設置爲OFF時,事務將不會複製到其他節點,默認ON wsrep_OSU_method:Online Schema Update設置,TOI/RSU(MySQL >= 5.5.17),默認TOI wsrep_provider:libgalera_smm.so的路徑,若沒有配置,galera複製不會啓動,默認none wsrep_provider_options:很長的字符串變量,可以配置很多group communication system相關參數,很長很長... wsrep_retry_autocommit:事務在衝突時重新嘗試的次數,默認1 wsrep_slave_threads:並行複製的slave線程數,默認4 wsrep_sst_method:Snapshot State Transter方法:mysqldump/rsync/xt,默認mysqldump |
wsrep_provider_options
該參數是一個字符串,包含了group communication system中很多參數設置,配置時使用分號隔開:
wsrep_provider_options=”key_a=value_a;key_b=value_b;key_c=value_c”,點擊查看詳情
列舉其中部分重要參數:
evs.send_window:節點一次可以發送的消息數目,默認4 evs.user_send_window:其與evs.send_window之間的差別類似於max_connections與max_user_connection,默認2 gcs.fc_factor:flow control參數,默認0.5 gcs.fc_limit:flow control參數,默認16 gcs.fc_master_slave:flow control參數,默認NO gcs.recv_q_hard_limit:接收隊列的佔用的最大內存,默認LLONG_MAX gcs.recv_q_soft_limit:當接收隊列佔用內存超過(gcs.recv_q_hard_limit*gcs.recv_q_soft_limit),複製被延遲,默認0.25 gmcast.listen_addr:節點用於接收其它節點消息的地址,默認tcp://0.0.0.0:4567 pc.checksum:是否對發送的消息做checksum,默認true pc.ignore_sb:是否忽略split brain,默認false |
一個例子
binlog_format=row default-storage-engine = INNODB innodb_autoinc_lock_mode = 2 innodb_locks_unsafe_for_binlog = 1 wsrep_provider = /u01/mariadb-galera/lib/libgalera_smm.so wsrep_cluster_address = "gcomm://192.168.xxx.01" wsrep_cluster_name = galera wsrep_node_address = 192.168.xxx.xxx wsrep_node_name = slave wsrep_sst_method = rsync wsrep_slave_threads = 16 wsrep_provider_options="gcache.page_size=128M;gcache.size=2G;gcs.fc_limit=512;gcs.fc_factor=0.9;evs.send_window=256;evs.user_send_window=128" |
Galera status variables
Galera提供了很多以wsrep_開頭狀態參數監控mysql狀態,通過show status like ‘wsrep%’可以查看:
wsrep_local_state_uuid:應該與wsrep_cluster_state_uuid一致,如363acc29-9160-11e2-0800-4316271a76e4 wsrep_last_committed:已經提交事務數目,所有節點之間相差不大,可以用來計算延遲 wsrep_replicated:從本地節點複製出去的write set數目 wsrep_replicated_bytes:從本地節點複製出去的write set的總共字節數 wsrep_received:本地節點接收來自其他節點的write set數目 wsrep_received_bytes:本地節點接收來自其他節點的write set的總共字節數 wsrep_local_commits:從本地節點發出的write set被提交的數目,不超過wsrep_replicated wsrep_local_cert_failures:certification test失敗的數目 wsrep_local_bf_aborts:certification test通過的write set執行過程中回滾的與其衝突的本地事務 wsrep_local_replays:事務被回滾(bf abort)重做的數目 wsrep_local_send_queue:發送隊列的長度 wsrep_local_send_queue_avg:從上次查詢狀態到目前發送隊列的平均長度,>0.0意味着複製過程被節流了 wsrep_local_recv_queue:接收隊列的長度 wsrep_local_recv_queue_avg:從上次查詢狀態到目前接收隊列的平均長度,>0.0意味着執行速度小於接收速度 wsrep_flow_control_paused:從上次查詢狀態到目前處於flow control的時間佔比,如0.388129 wsrep_flow_control_sent:從上次查詢狀態到目前節點發送出的FC_PAUSE消息數目,如1 wsrep_flow_control_recv:從上次查詢狀態到目前及節點接收的FC_PAUSE消息數目,如1 wsrep_cert_deps_distance:可以並行執行的write set的最大seqno與最小seqno之間的平均差值,如1851.825751 wsrep_apply_oooe:隊列中事務併發執行佔比,值越高意味着效率越高 wsrep_commit_window:平均併發提交窗口大小 wsrep_local_state:節點的狀態,取值1-6 wsrep_local_state_comment:節點的狀態描述,比如Synced wsrep_incoming_addresses:集羣中其它節點的地址,多個地址之間用逗號分隔 wsrep_cluster_conf_id:集羣節點關係改變的次數(每次增加/刪除都會+1) wsrep_cluster_size:集羣節點個數 wsrep_cluster_state_uuid:集羣uuid,所有節點應該一樣,如:363acc29-9160-11e2-0800-4316271a76e4 wsrep_cluster_status:集羣的目前狀態,取值:PRIMARY(正常)/NON_PRIMARY(不一致) wsrep_connected:節點是否連接到集羣,取值:ON/OFF wsrep_local_index:節點id wsrep_provider_name:默認Galera wsrep_provider_vendor:默認Codership Oy <[email protected]> wsrep_provider_version:wsrep版本,如:2.2(rXXXX) wsrep_ready:節點是否可以接受查詢了,取值:ON/OFF |
一個截圖:
如何檢查節點是否加入到集羣
1. wsrep_cluster_state_uuid應該與其它所有節點相同
2. wsrep_cluster_conf_id應該與其它所有節點相同
3. wsrep_cluster_size應該是所有節點的數目
4. wsrep_cluster_status取值應該是:Primary
5. wsrep_ready取值應該是ON
6. wsrep_connected取值應該是ON
判斷複製過程是否出現問題
wsrep_flow_control_paused,正常情況下,其取值應該接近於0.0,大於0.0意味着有‘慢節點’影響了集羣的速度,可以嘗試通過增大wsrep_slave_threads來解決
找出最慢的節點
wsrep_flow_control_sent,wsrep_local_recv_queue_avg兩個值最大的節點
參考:galera status,galera monitoring
性能測試
由於galera同步複製在每個寫事務提交時都增加了replicate trx和certification test的開銷,因此性能遠遠低於異步MySQL實例
測試場景
使用TPCC進行測試,包含3組數據:
1、normal mysql: baseline,單個mysql server
2、galera (RTT: 0.5ms): 2-nodes galera cluster,單節點讀寫
3、galera (RTT: 15.2ms): 2-nodes galera cluster,單節點讀寫
測試結論:
1. 相對於異步MySQL實例,Galera replication性能下降約50% ~ 60%左右
2. Galera最大性能不受RTT影響,RTT 較小時(0.5ms),在達到最大性能之前(32併發),性能下降並不明顯 (32併發下降25%,16併發性能下降更低),RTT較大時(15.2ms),在達到最大性能之前(64併發),相對於norml mysq性能下降一直到很明顯,當壓力逐漸增大,由於group io的原因,galera性能在達到最大時還會提高
Galera replication for MySQL學習資料
1. codership官網
2. mysqlperformanceblog搜索中PXC(Percona XtraDB Cluster)