MySQL高可用之PXC

PXC簡介
PXC(Percona XtraDB Cluster)是一個開源的MySQL高可用解決方案。他將Percona Server和XtraBackup與Galera庫集成,以實現同步多主複製。基於Galera的高可用方案主要有MariaDB Galera Cluster和Percona XtraDB Cluster,目前PXC架構在生產線上用的更多並且更成熟一些。PXC相比那些傳統的基於主從模式的集羣架構MHA和雙主,Galera Cluster 最突出的特色就是解決了詬病已久的複製延遲問題,基本上能夠達到實時同步。並且節點與節點之間,它們互相的關係是對等的。自己Galera Cluster也是一種多主架構。PXC是在存儲引擎層實現的同步複製,而非異步複製,因此其數據的一致性是至關高的。
MySQL高可用之PXC
要搭建PXC架構至少須要三個MySQL實例來組成一個集羣,三個實例之間不是主從模式,而是各自爲主,因此三者是對等關係,不分從屬,這也叫multi-master架構。客戶端讀寫時,連接哪一個實例都是同樣的,讀取到的數據是相同的,寫入任意一個實例後,集羣會將本身新寫入的數據同步到其餘實例上,這樣架構不共享任何數據,是一種高冗餘的集羣架構。
PXC優缺點node

優勢:mysql

  • 實現了MySQL集羣的高可用性和數據的強一致性;
  • 完成了真正的多節點讀寫的集羣方案;
  • 改善了主從複製延遲問題,基本上達到了實時同步;
  • 新加入的節點能夠自動部署,無需提交手動備份,維護方便;
  • 因爲是多節點寫入,因此DB故障切換很容易。

.sql

缺點:數據庫

  • 加入新節點時開銷大。添加新節點時,必須從現有節點之一複製完整數據集。若是是100GB,則複製100GB。
  • 任何更新的事務都須要全局驗證經過,纔會在其餘節點上執行,集羣性能受限於性能最差的節點,也就說常說的木桶定律。
  • 由於須要保證數據的一致性,PXC採用的實時基於存儲引擎層來實現同步複製,因此在多節點併發寫入時,鎖衝突問題比較嚴重。
  • 存在寫擴大的問題。因此節點上都會發生寫操做,對於寫負載過大的場景,不推薦使用PXC。
  • 只支持InnoDB存儲引擎。

PXC原理
MySQL高可用之PXC
PXC的操做流程:
首先客戶端向請求鏈接的寫入節點提交事務以前,由該節點將須要產生的relication writeset廣播出去,而後獲取全局事務ID,一併傳送到其餘節點上去。其餘節點經過certification合併數據以後,發現沒有衝突數據,便執行apply_cb和commit_cb操做,不然就discard這次事務。而當前節點(客戶端請求的寫入節點)經過驗證後,執行commit_cb操做,並返回OK給客戶端。若是驗證沒有經過,則rollback_cb。
在生產線上的PXC集羣中,至少要有三臺節點。若是其中一個節點沒有驗證經過,出現了數據衝突,那麼此時採起的方式就是將出現數據不一致的節點踢出集羣,並且他會自動執行shutdown命令來關機。
PXC中的重要概念
首先要規範集羣中節點的數量,整個集羣節點數控制在最少3個、最多8個的範圍內。最少3個是爲了防止腦裂現象,由於只有在兩個節點的狀況下才會出現腦裂。腦裂的表現就是輸出任何命令,返回結果都是unkown command。
當一個新節點要加入PXC集羣的時候,須要從集羣中各節點裏選舉出一個doner節點做爲全量數據的貢獻者。
PXC有兩種節點的數據傳輸方式,一種叫SST全呈傳輸,另外一種叫IST增是傳輸。SST傳輸有XtraBackup、mysqldump、rsync三種方式, 而增量傳輸只有XtraBackup。通常數據量不大的時候可使用SST做爲全量傳輸,但也只使用XtraBackup方式。vim

節點在集羣中,會因新節點的加入或故障,同步失效等而發生狀態的切換,下面列舉出這些狀態的含義:
open:節點啓動成功,嘗試鏈接到集羣。
primary:節點已在集羣中,在新節點加入集羣時,選取donor進行數據同步時會產生式的狀態。
joiner:節點處於等待接收同步數據文件的狀態。
joined:節點已完成了數據同步,嘗試保持和集羣中其它節點進度- -致。
synced:節點正常提供服務的狀態,表示已經同步完成並和集羣進度保持一致。
doner:節點處於爲新加入節點提供全星數據時的狀態。centos

PXC中的重要配置參數緩存

搭建PXC過程當中,須要在my.cnf中設置如下參數:網絡

  • wsrep cluster _name:指定集羣的邏輯名稱,對於集羣中的全部節點,集羣名稱必須相同。
  • wsrep_ cluster _address: 指定集羣中各節點的地址
  • wsrep node name:指定當前節點在集羣中的邏輯名稱
  • wsrep node address: 指定當前節點的IP地址
  • wsrep_ provider: 指定Galera庫的路徑
  • wsrep sst _method: 模式狀況下,PXC使用XtraBackup進行SST傳輸。 強烈建議該參數指爲xtrabackup-v2
  • wsrep sst auth: 指定認證憑證SST做爲<sst user>:<sst _pwd>。 必須在引導第一個節點後建立此用戶並賦予
  • 必要的權限。
  • pxc_ _strict mode:嚴格模式,官方建議該參數值爲ENFORCING。

在PXC中還有一個特別重要的模塊就是Gcache。它的核心功能就是每一個節點緩存當前最新的寫集。若是有新節點加入集羣,就能夠把新數據等待增星傳遞給新節點,而不須要再使用SST方式了。這樣可讓節點更快地加入
集羣中。架構

GCache模塊涉及了以下參數:併發

  • gcache.size表明用來緩存寫集增量信息的大小。它的默認大小是128MB,經過wsrep provider options變量參數設置。建議調整爲2G 4G範圍,足夠的空間便於緩存更多的增量信息。
  • gcache.mem_ size表明Gcache中內存緩存的大小,適度調大能夠提升整個集羣的性能。
  • gcache. page_ size能夠理解爲若是內存不夠用(Gcache不足),就直接將寫集寫入到磁盤文件中。

PXC集羣狀態監控

在集羣搭建好以後,能夠經過以下狀態變量'%wsrep%'來查看集羣中各節點的狀態,下面例舉出幾個重要的參數,便於發現問題。

  • wsrep local state uid: 集羣中全部節點的該狀態值應該是相同的,若是有不一樣值的節點,說明其沒有加入集羣。
  • wsrep_ last _committed:最後提交的事務數目。
  • wsrep cluster _size: 當前集羣中的節點數量。
  • wsrep_ cluster _status: 集羣組成的狀態。若是不是"Primary", 說明出現腦裂現象。
  • wsrep local state:當前節點狀態,值爲4表示正常。該狀態有四個值:
    • joining:表示節點正在加入集羣
    • doner:節點處於爲新加入節點提供全量數據時的狀態。
    • joined:當前節點已成功加入集羣。
    • synced:當前節點與集羣中各節點是同步狀態。
    • wsrep_ ready: 爲ON表示當前節點能夠正常提供服務。爲OFF, 則該節點可能發生腦裂或網絡問題致使。

部署PXC

主機名 IP Column 3
pxc-node1 192.168.171.150 Text
pxc-node2 192.168.171.151 Text
pxc-node3 192.168.171.152 Text
#OS版本
[root@pxc-node1 ~]# cat /etc/centos-release
CentOS Linux release 7.8.2003 (Core)
#在三臺數據庫安裝依賴包
[root@pxc-node1 ~]# yum install -y libev lsof perl-Compress-Raw-Bzip2 perl-Compress-Raw-Zlib perl-DBD-MySQL perl-DBI  perl-Digest perl-Digest-MD5 perl-IO-Compress perl-Net-Daemon perl-PIRPC qpress socat openssl openssl-devel
#下載軟件
[root@pxc-node1 ~]# wget https://www.percona.com/downloads/Percona-XtraBackup-2.4/Percona-XtraBackup-2.4.18/binary/redhat/7/x86_64/percona-xtrabackup-24-2.4.18-1.el7.x86_64.rpm
[root@pxc-node1 ~]# wget https://www.percona.com/downloads/Percona-XtraDB-Cluster-57/Percona-XtraDB-Cluster-5.7.28-31.41/binary/tarball/Percona-XtraDB-Cluster-5.7.28-rel31-31.41.1.Linux.x86_64.ssl101.tar.gz
#安裝xtrabackup
[root@pxc-node1 ~]# rpm -ivh percona-xtrabackup-24-2.4.18-1.el7.x86_64.rpm 
#卸載掉原有mariadb
[root@pxc-node1 ~]# rpm -e mariadb-libs --nodeps
#建立MySQL的組和用戶
[root@pxc-node1 ~]# groupadd -r mysql
[root@pxc-node1 ~]# useradd -M -s /bin/felse -r -g mysql mysql
#解包爲mysql
[root@pxc-node1 ~]# tar zxf Percona-XtraDB-Cluster-5.7.28-rel31-31.41.1.Linux.x86_64.ssl101.tar.gz 
mv Percona-XtraDB-Cluster-5.7.28-rel31-31.41.1.Linux.x86_64.ssl101/ /usr/local/mysql
#建立數據目錄並賦予權限
[root@pxc-node1 ~]# mkdir /usr/local/mysql/data
[root@pxc-node1 ~]# chown -R mysql:mysql /usr/local/mysql/
#配置環境變量
[root@pxc-node1 ~]# vim /etc/profile
export PATH=/usr/local/mysql/bin:$PATH
[root@pxc-node2 ~]# . /etc/profile
#編輯配置文件
[root@pxc-node1 ~]# vim /etc/my.cnf
[client]
port = 3306
socket = /tmp/mysql.sock
[mysql]
prompt = "\u@\h \R:\m:\s[\d]>"
no-auto-rehash
[mysqld]
user = mysql
port = 3306
basedir = /usr/local/mysql
datadir = /usr/local/mysql/data
socket = /tmp/mysql.sock
pid-file = db.pid
character-set-server = utf8mb4
skip_name_resolve = 1
open_files_limit = 65535
back_log = 1024
max_connections = 512
max_connect_errors =1000000
table_open_cache = 1024
table_definition_cache = 1024
table_open_cache_instances = 64
thread_stack = 512K
external-locking =FALSE
max_allowed_packet = 32M
sort_buffer_size = 4M
join_buffer_size = 4M
thread_cache_size = 768
#query_cache_size = 0
#query_cache_type = 0
interactive_timeout = 600
wait_timeout = 600
tmp_table_size = 32M
max_heap_table_size = 32M
slow_query_log = 1
slow_query_log_file = /usr/local/mysql/data/slow.log
log-error = /usr/local/mysql/data/error.log
long_query_time = 0.1
server-id = 1813306
log-bin = /usr/local/mysql/data/mysql-bin
sync_binlog = 1
binlog_cache_size = 4M
max_binlog_cache_size = 1G
max_binlog_size = 1G
expire_logs_days = 7
master_info_repository = TABLE
relay_log_info_repository = TABLE
gtid_mode = on
enforce_gtid_consistency = 1
log_slave_updates
binlog_format = row
relay_log_recovery = 1
relay-log-purge = 1
key_buffer_size = 32M
read_buffer_size = 8M
read_rnd_buffer_size = 4M
bulk_insert_buffer_size = 64M
lock_wait_timeout = 3600
explicit_defaults_for_timestamp = 1
innodb_thread_concurrency = 0
innodb_sync_spin_loops = 100
innodb_spin_wait_delay = 30
transaction_isolation = REPEATABLE-READ
innodb_buffer_pool_size = 1024M
innodb_buffer_pool_instances = 8
innodb_buffer_pool_load_at_startup = 1
innodb_buffer_pool_dump_at_shutdown = 1
innodb_data_file_path = ibdata1:1G:autoextend
innodb_flush_log_at_trx_commit = 1
innodb_log_buffer_size = 32M
innodb_log_file_size = 2G
innodb_log_files_in_group = 2
#innodb_nax_undo_log_size = 4G
innodb_io_capacity = 2000
innodb_io_capacity_max = 4000
innodb_flush_neighbors = 0
innodb_write_io_threads = 4
innodb_read_io_threads = 4
innodb_purge_threads = 4
innodb_page_cleaners = 4
innodb_open_files = 65535
innodb_max_dirty_pages_pct = 50
innodb_flush_method = O_DIRECT
innodb_lru_scan_depth = 4000
innodb_checksum_algorithm = crc32
#innodb_file_format = Barracuda
#innodb_file_format_max = Barracuda
innodb_lock_wait_timeout = 10
innodb_rollback_on_timeout = 1
innodb_print_all_deadlocks = 1
innodb_file_per_table = 1
innodb_online_alter_log_max_size = 4G
internal_tmp_disk_storage_engine = InnoDB
innodb_stats_on_metadata = 0
#PXC
wsrep_provider=/usr/local/mysql/lib/libgalera_smm.so
wsrep_provider_options="gcache.size=1G"
wsrep_cluster_name=pxc-test
wsrep_cluster_address=gcomm://192.168.171.150,192.168.171.151,192.168.171.152
wsrep_node_name=pxc-node1
wsrep_node_address=192.168.171.150
wsrep_sst_method=xtrabackup-v2
wsrep_sst_auth=sst:pwd@123
pxc_strict_mode=ENFORCING
default_storage_engine=InnoDB
innodb_autoinc_lock_mode = 2
[mysqldump]
quick
max_allowed_packet = 32M
#pxc-node2上修改
server-id = 1813307
wsrep_node_name=pxc-node2
wsrep_node_address=192.168.171.151
#pxc-node3上修改
server-id = 1813308
wsrep_node_name=pxc-node3
wsrep_node_address=192.168.171.152

各節點完成MySQL初始化

[root@pxc-node1 ~]# mysqld --defaults-file=/etc/my.cnf --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --initialize

引導第一個節點以初始化集羣

#pxc-node1上啓動MySQL
[root@pxc-node1 ~]# mysqld --defaults-file=/etc/my.cnf --wsrep_new_cluster & 
[root@pxc-node1 ~]# ss -anput | grep mysql        # 確認啓動
tcp    LISTEN     0      128       *:4567                  *:*                   users:(("mysqld",pid=45268,fd=11))
tcp    LISTEN     0      128    [::]:3306               [::]:*                   users:(("mysqld",pid=45268,fd=35))
[root@pxc-node1 ~]# grep password /usr/local/mysql/data/error.log              # 在錯誤日誌中獲取臨時密碼
2020-07-05T08:23:24.636538Z 1 [Note] A temporary password is generated for root@localhost: 1&U))a?(ulOj
#第一次登錄修改密碼
root@localhost 16:32: [(none)]>alter user root@localhost identified by '123';        
#建立PXC中的SST傳輸帳號
root@localhost 16:32: [(none)]>grant all privileges on *.* to 'sst'@'localhost' identified by 'pwd@123';
root@localhost 16:36: [(none)]>flush privileges;

將其餘節點添加到集羣

#在pxc-node2和pxc-node3上啓動MySQL(可能須要點時間)
[root@pxc-node2 ~]# mysqld --defaults-file=/etc/my.cnf &
[root@pxc-node3~]# mysqld --defaults-file=/etc/my.cnf &
[root@pxc-node2 ~]# ss -anput | grep mysql     # 剛啓動時只會有4567這個端口,過一會加入集羣后就會啓動3306
tcp    LISTEN     0      128       *:4567                  *:*                   users:(("mysqld",pid=45248,fd=11))
#當node2和node3將node1的數據同步到本地後,能夠直接使用node1的密碼登錄數據庫
#查看集羣狀態,能夠看到集羣中有3個節點
root@localhost 16:43: [(none)]>show global status like 'wsrep_cluster_%';
+--------------------------+--------------------------------------+
| Variable_name            | Value                                |
+--------------------------+--------------------------------------+
| wsrep_cluster_weight     | 3                                    |
| wsrep_cluster_conf_id    | 3                                    |
| wsrep_cluster_size       | 3                                    |
| wsrep_cluster_state_uuid | b30f83dd-be99-11ea-b21c-b61232d3c9ee |
| wsrep_cluster_status     | Primary                              |
+--------------------------+--------------------------------------+
5 rows in set (0.00 sec)
root@localhost 16:49: [(none)]>show global status like '%wsrep_ready%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wsrep_ready   | ON    |
+---------------+-------+
1 row in set (0.00 sec)

驗證複製

#在任意節點建立庫表,往表中插入一些數據,在另外兩個節點上查看是否同步
root@localhost 16:50: [(none)]>create database test1;
root@localhost 16:52: [(none)]>use test1;
root@localhost 16:52: [test1]>create table tb1(id int primary key auto_increment,name varchar(22));
root@localhost 16:54: [test1]>insert into tb1(name) values('zhangsan'),('lisi'),('liubin');
#在其餘節點上查看數據是否同步
#node2上
root@localhost 16:55: [(none)]>select * from test1.tb1;
+----+----------+
| id | name     |
+----+----------+
|  2 | zhangsan |
|  5 | lisi     |
|  8 | liubin   |
+----+----------+
3 rows in set (0.00 sec)
#node3上
root@localhost 16:56: [(none)]>select * from test1.tb1;
+----+----------+
| id | name     |
+----+----------+
|  2 | zhangsan |
|  5 | lisi     |
|  8 | liubin   |
+----+----------+
3 rows in set (0.00 sec)
相關文章
相關標籤/搜索