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是在存儲引擎層實現的同步複製,而非異步複製,因此其數據的一致性是至關高的。
要搭建PXC架構至少須要三個MySQL實例來組成一個集羣,三個實例之間不是主從模式,而是各自爲主,因此三者是對等關係,不分從屬,這也叫multi-master架構。客戶端讀寫時,連接哪一個實例都是同樣的,讀取到的數據是相同的,寫入任意一個實例後,集羣會將本身新寫入的數據同步到其餘實例上,這樣架構不共享任何數據,是一種高冗餘的集羣架構。
PXC優缺點node
優勢:mysql
- 實現了MySQL集羣的高可用性和數據的強一致性;
- 完成了真正的多節點讀寫的集羣方案;
- 改善了主從複製延遲問題,基本上達到了實時同步;
- 新加入的節點能夠自動部署,無需提交手動備份,維護方便;
- 因爲是多節點寫入,因此DB故障切換很容易。
.sql
缺點:數據庫
- 加入新節點時開銷大。添加新節點時,必須從現有節點之一複製完整數據集。若是是100GB,則複製100GB。
- 任何更新的事務都須要全局驗證經過,纔會在其餘節點上執行,集羣性能受限於性能最差的節點,也就說常說的木桶定律。
- 由於須要保證數據的一致性,PXC採用的實時基於存儲引擎層來實現同步複製,因此在多節點併發寫入時,鎖衝突問題比較嚴重。
- 存在寫擴大的問題。因此節點上都會發生寫操做,對於寫負載過大的場景,不推薦使用PXC。
- 只支持InnoDB存儲引擎。
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)