mysql8.0使用PXC实现高可用
什么是 PXC
PXC 是一套 MySQL 高可用集群解决方案,与传统的基于主从复制模式的集群架构相比 PXC 最突出特点就是解决了诟病已久的数据复制延迟问题,基本上可以达到实时同步。而且节点与节点之间,他们相互的关系是对等的。PXC 最关注的是数据的一致性,对待事物的行为时,要么在所有节点上执行,要么都不执行,它的实现机制决定了它对待一致性的行为非常严格,这也能非常完美的保证 MySQL 集群的数据一致性;
PXC 的特点
- 完全兼容 MySQL。
- 同步复制,事务要么在所有节点提交或不提交。
- 多主复制,可以在任意节点进行写操作。
- 在从服务器上并行应用事件,真正意义上的并行复制。
- 节点自动配置,数据一致性,不再是异步复制。
- 故障切换:因为支持多点写入,所以在出现数据库故障时可以很容易的进行故障切换。
- 自动节点克隆:在新增节点或停机维护时,增量数据或基础数据不需要人工手动备份提供,galera cluster 会自动拉取在线节点数据,集群最终会变为一致。
PXC 的优缺点
优点:
- 服务高可用。
- 数据同步复制(并发复制),几乎无延迟。
- 多个可同时读写节点,可实现写扩展,不过最好事先进行分库分表,让各个节点分别写不同的表或者库,避免让 galera 解决数据冲突。
- 新节点可以自动部署,部署操作简单。
- 数据严格一致性,尤其适合电商类应用。
- 完全兼容 MySQL。
缺点:
- 复制只支持InnoDB 引擎,其他存储引擎的更改不复制。
- 写入效率取决于节点中最弱的一台,因为 PXC 集群采用的是强一致性原则,一个更改操作在所有节点都成功才算执行成功。
- 所有表都要有主键。
- 不支持 LOCK TABLE 等显式锁操作
- 锁冲突、死锁问题相对更多。
PXC 集群节点越多,数据同步的速度就越慢。
PXC 与 Replication 的区别
Replication | PXC |
---|---|
数据同步是单向的,master 负责写,然后异步复制给 slave;如果 slave 写入数据,不会复制给 master | 数据同步时双向的,任何一个 mysql 节点写入数据,都会同步到集群中其它的节点 |
异步复制,从和主无法保证数据的一致性 | 同步复制,事务在所有集群节点要么同时提交,要么同时不提交 |
PXC的原理
复制分为四个阶段
1.Local read phase
本地(client连接的节点)执行事务Ti,但是不真正提交,真正提交(提交给引擎)之前进入Send phase发送阶段
2.Send phase
1). 若事务只读,直接提交,结束
2). 若事务非只读,将事物的写操作封装成WS(Write Set,基于行),并且携带一个全局唯一标识global tex ID,广播到所有节点(包括自身)
3.Certification phase 认证测试阶段
Certification based conflict detect 测试发送来的事务与本地事务是否有冲突
4.Write phase 写阶段
a) 若检测出冲突,其他节点discard,原节点回滚Ti
b) 否则,执行WS,提交事务后释放锁资源
c) 对于源节点,提交事务并向client返回结果
Galera replication
采取的是乐观策略,即事务在一个节点提交时,被认为与其他节点事务没有冲突,首先在本地“执行”(事务并没有执行完),后再发送给所有节点做冲突检测,存在两种情况下需要回滚事务:
- WS复制到其他节点时,被加到每个节点的slave trx queue(一个事务队列,专门用来存放其他节点发送过来的事务)中,与queue中前面的trxs再做certification test时发现冲突,该事务被抛弃掉
- WS通过了certification test后被保证一定会执行,在他执行过程中,如果该节点上有与其冲突的local trxs(本地事务,因为每个节点都是可读可写的),回滚这个local trxs本地事务
事务在commit节点广播后,节点之间不交换“是否冲突”的信息 (因为每个节点上的slave trx queue事务队列都相同,所以当本地认证失败/成功后,其他节点一定也是认证失败/成功,当事务认证通过后,就算与本地事务认证冲突,也只会回滚本地事务,因此提交后,不再交换冲突信息),各个节点独立异步的处理该事务,certification based replication 协议保证
1. 事务在所有节点上要么都commit,要么都rollback/abort
2. 事务在所有节点的执行顺序一致(通过全局唯一序列Global trx ID)
Certification based replication所依赖的基础技术:
- Atomic delivery(事务传输要么成功传给所有节点,要么都失败)
- Total order(事务在所有节点中的顺序一致)
- Group maintenance(每个节点知道所有节点的状态)
PXC中的两个缓存 GCache and Record-Set Cache
在PXC集群中,有一个GCache和 Record-Set Cache(也称为事务写集缓存)概念。如果正在运行长事务,这两个缓存的使用通常会让人感到困惑,因为它们都会导致创建磁盘级文件。
- Record-Set Cache
- 当在节点上运行事务时,将尝试为修改的每一行附加一个键。这些数据就缓存在out-write-set中,然后将其广播至所有节点
- 生命周期和事务相关
- Gcache
- 执行事务的本机节点也将充当订阅节点,并通过集群发布机制接收自己的wirte-set(第二阶段)。节点将尝试将write-set缓存到其Gcache中。Gcache保留多少数据配置控制
- Gcache中的write-set 的生存周期与实物无关
- 当一个节点需要IST时,它将通过这个GCache提供服务
- 在任何给定的时间点,本机节点都有两个写集副本:一个在GCache,另外一个在Record-Set Cache
PXC的传输方式 SST,IST
- State Snapshot Transfer(SST)全量传输
当一个新节点加入集群并从现有节点接收所有数据时,通常使用SST。在PXC集群中有三种SST的方法:- mysqldump
- rsync
- Xtrabackup
mysqldump和reync的缺点是,在复制数据时,集群变成只读的
Xtrabackup 的优点是不需要READ LOCK命令,只使用备份锁
- Incremental state Transfer(IST)增量传输
是指只将增量更改从一个节点复制到另一个节点。
SST即使没有将集群锁定为只读状态,SST也可能会干扰并中断服务的正常运行。IST可以让你避免这种情况。如果一个节点宕机时间很短,那么它只获取在宕机期间发生的更改。使用节点上的缓存机制实现。每个节点都包含一个缓存,上次N次更改的缓冲区(即GCache,大小可配置),并且节点能够传输此缓存的一部分。只有当需要传输的更改量小于N时才能执行IST。如果超过N,则必须执行SST。
PXC 常用端口
- 3306:数据库对外服务的端口号。
- 4444:请求 SST 的端口。
- 4567:组成员之间进行沟通的一个端口号。
- 4568:用于传输 IST。
- SST(State Snapshot Transfer): 全量传输
- IST(Incremental state Transfer)??*增量传输
PXC的状态参数
复制信息
获取信息:
show status like 'wsrep%';
名称 | 描述 |
---|---|
wsrep_replicated | 被其他节点复制的次数 |
wsrep_replicated_bytes | 发送到其他节点的写入集的总大小 |
wsrep_received | 从其他节点处收到的写入请求数 |
wsrep_received_bytes | 从其他节点接受的写入集的总大小 |
wsrep_local_commits | 节点上的写入集数目 |
wsreo_local_cert_failures | certification test中未通过的trx数目 |
wsrep_local_bf_aborts | apply trxs(已经通过certification test)时,回滚的local trxs(open but not commit)数目 |
日常运维运维中应该关注wsreo_local_cert_failures,wsrep_local_bf_aborts这两个参数,如果数目持续增加,看看是不是应用上有问题
队列信息
如果pxc正在满负荷工作,没有线程去执行数据的同步,同步请求会缓存到队列中,然后空闲线程会从队列中取出任务,执行同步的请求,有了队列pxc就能用少量的线程应对瞬时大量的同步请求。
名称 | 描述 |
---|---|
wsrep_local_send_queue | 发送队列的长度(瞬时同步的请求数量) |
wsrep_local_send_queue_max | 发送队列的最大长度 |
wsrep_local_send_queue_min | 发送队列的最小长度 |
wsrep_local_send_queue_avg | 发送队列的平均长度 |
wsrep_local_recv_queue | 接收队列的长度 |
wsrep_local_recv_queue_max | 接收队列的最大长度 |
wsrep_local_recv_queue_min | 接收队列的最小长度 |
wsrep_local_recv_queue_avg | 接收队列的平均长度 |
wsrep_local_send_queue:如果这个值比较高,那么表示当前负载比较高,也可能是硬件性能导致
wsrep_local_send_queue_avg:同上
wsrep_local_recv_queue:如果这个值比较高,那么表示接收到了请求,应用线程负载比较高,可能是应用线程比较少,干不来活了,那就增加硬件cpu性能或者增加线程数
-
当发送队列的平均长度(wsrep_local_send_queue_avg)值很大, 发送队列的长度(wsrep_local_send_queue)也很大的时候,说明pxc集群同步数据的速度已经很慢了,队列里边积压了大量的同步请求,这个时候就得检查一下网速是不是正常,或者同步的线程数量是不是太少。
-
当接收队列的平均长度(wsrep_local_recv_queue_avg)值很大, 接收队列的长度(wsrep_local _recv_queue)也很大的时候,这说明本地没有足够的线程去执行持久化的操作,增加线程就可以解决这个问题。
流控信息(流量控制)
- 什么是流控(FC)?如何工作?
节点接收写集并把它们按照全局顺序组织(根据全局序列号)起来,节点将接收到的未应用和提交的事务保存在接收队列中,当这个接收队列达到一定的大小,将触发限流;此时节点将暂停复制,节点会先处理接收队列中的任务。当接收队列减小到一个可管理的值后,复制将恢复。
比如说队列每满之前一直死四个线程往里面写请求,当队列快满的时候,缩减为两个队列往里面写请求
名称 | 描述 |
---|---|
wsrep_flow_control paused_ns | 流控暂停状态下的总时间(纳秒) |
wsrep_flow_control_paused | 表示复制停止了多长时间。值为0~1,越靠近0越好,值为1表示复制完全停止。. |
wsrep_flow_control_sent | 发送的流控暂停事件的数量 |
wsrep_flow_control_recv | 接收的流控暂停事件的数量 |
wsrep_flow_control_interval | 流量控制的下限和上限。上限 是队列中允许的最大请求数。如果队列达到上限,则拒绝新的请求。当处理现有 |
wsrep_flow_control_interval | 请求时,队列会减少,一旦到达下限,将再次允许新的请求 |
wsrep_flow_control_status | 流量控制状态OFF:关闭 ON:开启 |
-
流控的主要原因节点之间同步的速度慢,队列积压了大量的请求,这才是流控的主要原因。流控解决办法:
1.提高带宽, 更换交换机,千兆网卡更换成万兆网卡
2.提升硬件性能,比如升级CPU,内存以及更换光纤硬盘等等都可以提高写入速度
3.增加线程,线程多了执行的速度也就快了。队列里边就不会积压大量的请求
前两项属于硬件升级,主要说一下第三个方法增加线程数提升同步速度。在pxc的配置文
件加上wsrep_slave_ threads 参数。代表的是本地执行队列的线程数量,一般这个数是CPU线程数的1-1.5倍。也可以使用wsrep_cert_deps_distance 状态变量来确定可能的线程的最大数量。不要使wsrep_slave_threads 值高于wsrep _cert_deps_distance 状态变量平均值。
(wsrep_cert_deps_distance 表示有多少事务可以并行应用处理。)
节点与集群的状态信息
名称 | 描述 |
---|---|
wsrep_ local state_ comment | 节点状态:Joining节点正在加入到pxc集群中、Joined节点已经加入到pxc集群中、Synced节点可以提供读写服务,算正常的状态、Donar/Desynced如果有节点跟当前节点同步则进入此状态,不能提供读写服务 |
wsrep_cluster_status | 集群状态:(Primary正常状态、Non- Primary出现了脑裂请求、Disconnected 不能提供服务,已经出现宕机了) |
wsrep_connected | 节点是否连接到集群 |
wsrep_ready | 集群是否正常工作 |
wsrep_cluster_size | 节点数量 |
wsrep_desync_count | 延时节点数量 |
wsrep_ incoming. _addresses | 集群节点IP地址 |
事务相关信息
名称 | 描述 |
---|---|
wsrep_cert deps_distance | 事务执行并发数 |
wsrep_apply_window | 接收队列中事务的平均数量 |
wsrep_commit_window | 发送队列中事务的平均数量 |
一般将线程数设置为wsrep_cert deps_distance的平均数
搭建 PXC 集群
Percona XtraDB Cluster (简称 PXC)集群是基于 Galera 2.x library,事务型应用下的通用的多主同步复制插件,主要用于解决强一致性问题,使得各个节点之间的数据保持实时同步以及实现多节点同时读写。提高了数据库的可靠性,也可以实现读写分离,是 MySQL 关系型数据库中大家公认的集群优选方案之一。
准备好下面三台服务器,本文搭建PXC集群基于CentOS7.x:
IP | 端口 | 角色 |
---|---|---|
192.168.150.11 | 3306 | pxc |
192.168.150.12 | 3306 | pxc2 |
192.168.150.13 | 3306 | pxc3 |
配置hosts解析
# cat >> /etc/hosts << EOF
192.168.150.11 pxc1
192.168.150.12 pxc2
192.168.150.13 pxc3
EOF
- 删除 MariaDB 程序包
# yum -y remove mari*
- 下载 PXC 安装包
安装 PXC 里面集成了 Percona Server 数据库,所以不需要安装 Percona Server 数据库。
Software Downloads - Percona
下载 qpress-11-1.el7.x86_64.rpm
https://repo.percona.com/yum/release/7/RPMS/x86_64/qpress-11-1.el7.x86_64.rpm
最后上传到 centos 服务器中。
[root@pxc1 ~]# ll *.rpm
-rw-rw-r-- 1 root root 28360 Oct 19 20:21 percona-xtradb-cluster-8.0.34-26.1.el7.x86_64.rpm
-rw-rw-r-- 1 root root 15169548 Oct 19 20:21 percona-xtradb-cluster-client-8.0.34-26.1.el7.x86_64.rpm
-rw-rw-r-- 1 root root 509619476 Oct 19 20:21 percona-xtradb-cluster-debuginfo-8.0.34-26.1.el7.x86_64.rpm
-rw-rw-r-- 1 root root 1912512 Oct 19 20:21 percona-xtradb-cluster-devel-8.0.34-26.1.el7.x86_64.rpm
-rw-rw-r-- 1 root root 27840 Oct 19 20:21 percona-xtradb-cluster-full-8.0.34-26.1.el7.x86_64.rpm
-rw-rw-r-- 1 root root 754084 Oct 19 20:21 percona-xtradb-cluster-garbd-8.0.34-26.1.el7.x86_64.rpm
-rw-rw-r-- 1 root root 2292512 Oct 19 20:21 percona-xtradb-cluster-icu-data-files-8.0.34-26.1.el7.x86_64.rpm
-rw-rw-r-- 1 root root 5243092 Oct 19 20:21 percona-xtradb-cluster-mysql-router-8.0.34-26.1.el7.x86_64.rpm
-rw-rw-r-- 1 root root 151051960 Oct 19 20:21 percona-xtradb-cluster-server-8.0.34-26.1.el7.x86_64.rpm
-rw-rw-r-- 1 root root 1535736 Oct 19 20:21 percona-xtradb-cluster-shared-8.0.34-26.1.el7.x86_64.rpm
-rw-rw-r-- 1 root root 1179040 Oct 19 20:21 percona-xtradb-cluster-shared-compat-8.0.34-26.1.el7.x86_64.rpm
-rw-rw-r-- 1 root root 399166472 Oct 19 20:21 percona-xtradb-cluster-test-8.0.34-26.1.el7.x86_64.rpm
-rw-r--r-- 1 root root 32624 Dec 6 14:50 qpress-11-1.el7.x86_64.rpm
执行下面命令进行安装
# yum localinstall *.rpm -y
之后还是对 Percona Server 数据库的初始化:
- 初始化数据库
应为使用的是8.0版本,部分配置需要在初始化数据库前进行配置,如忽略表名大小写等
[root@pxc1 ~]# vim /etc/my.cnf
...
[mysqld]
server-id=11 #每台mysql的id不能相同
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
# Binary log expiration period is 604800 seconds, which equals 7 days
binlog_expire_logs_seconds=604800 #二进制日志过期时间为604800秒,等于7天注意:pxc2和pxc3只需要server-id设置为12和13即可。
然后我们启动 mysql,修改密码。
# systemctl start mysqld
# tmp_pass=$(awk '/temporary password/ {print $NF}' /var/log/mysqld.log)
# mysql -uroot -p${tmp_pass}
mysql> alter user root@localhost identified by '123456';
Query OK, 0 rows affected (0.01 sec)# 授权用户
# mysql -uroot -p123456
mysql> CREATE USER 'admin'@'%' IDENTIFIED WITH mysql_native_password BY 'Abc_123456';
Query OK, 0 rows affected (0.00 sec)mysql> GRANT all privileges ON *.* TO 'admin'@'%';
Query OK, 0 rows affected (0.00 sec)
- 创建集群
# 停止所有节点的mysqld服务
# systemctl stop mysqld[root@pxc1 ~]# vim /etc/my.cnf
...
######## wsrep ###############
# Path to Galera library
wsrep_provider=/usr/lib64/galera4/libgalera_smm.so# Cluster connection URL contains IPs of nodes
#If no IP is found, this implies that a new cluster needs to be created,
#in order to do that you need to bootstrap this node
wsrep_cluster_address=gcomm://192.168.150.11,192.168.150.12,192.168.150.13 # PXC集群的所有ip# In order for Galera to work correctly binlog format should be ROW
binlog_format=ROW# Slave thread to use
wsrep_slave_threads=8wsrep_log_conflicts# This changes how InnoDB autoincrement locks are managed and is a requirement for Galera
innodb_autoinc_lock_mode=2 # 主键自增长不锁表# Node IP address
wsrep_node_address=192.168.150.11 # 当前节点的IP
# Cluster name
wsrep_cluster_name=pxc-cluster # PXC集群的名称#If wsrep_node_name is not specified, then system hostname will be used
wsrep_node_name=pxc1 # 当前节点的名称#pxc_strict_mode allowed values: DISABLED,PERMISSIVE,ENFORCING,MASTER
pxc_strict_mode=ENFORCING# SST method
wsrep_sst_method=xtrabackup-v2 # 同步方法注意:pxc2和pxc3参照,修改集群节点ip和名称 wsrep_node_name,wsrep_node_address
将引导服务mysql目录下的*.pem拷贝给其他服务器
[root@pxc1 ~]# scp /var/lib/mysql/*.pem pxc2:/var/lib/mysql/
[root@pxc1 ~]# scp /var/lib/mysql/*.pem pxc3:/var/lib/mysql/
第一个节点需要以引导模式启动:
[root@pxc1 ~]# systemctl start mysql@bootstrap.service
接着在第二和第三个节点上正常启动数据库服务,命令如下:
[root@pxc2 ~]# chown -R mysql.mysql /var/lib/mysql/
[root@pxc2 ~]# systemctl start mysqld
[root@pxc3 ~]# chown -R mysql.mysql /var/lib/mysql/
[root@pxc3 ~]# systemctl start mysqld
查询集群信息
mysql> show status like 'wsrep%';
+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------+
| Variable_name | Value |
+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------+
| wsrep_local_state_uuid | 47f68dce-940c-11ee-85d5-c29e7cbcc6e4 |
| wsrep_protocol_version | 10 |
| wsrep_last_applied | 5 |
| wsrep_last_committed | 5 |
| wsrep_monitor_status (L/A/C) | [ (5, 5), (5, 5), (5, 5) ] |
| wsrep_replicated | 0 |
| wsrep_replicated_bytes | 0 |
| wsrep_repl_keys | 0 |
| wsrep_repl_keys_bytes | 0 |
| wsrep_repl_data_bytes | 0 |
| wsrep_repl_other_bytes | 0 |
| wsrep_received | 4 |
| wsrep_received_bytes | 504 |
| wsrep_local_commits | 0 |
| wsrep_local_cert_failures | 0 |
| wsrep_local_replays | 0 |
| wsrep_local_send_queue | 0 |
| wsrep_local_send_queue_max | 1 |
| wsrep_local_send_queue_min | 0 |
| wsrep_local_send_queue_avg | 0 |
| wsrep_local_recv_queue | 0 |
| wsrep_local_recv_queue_max | 1 |
| wsrep_local_recv_queue_min | 0 |
| wsrep_local_recv_queue_avg | 0 |
| wsrep_local_cached_downto | 4 |
| wsrep_flow_control_paused_ns | 0 |
| wsrep_flow_control_paused | 0 |
| wsrep_flow_control_sent | 0 |
| wsrep_flow_control_recv | 0 |
| wsrep_flow_control_active | false |
| wsrep_flow_control_requested | false |
| wsrep_flow_control_interval | [ 173, 173 ] |
| wsrep_flow_control_interval_low | 173 |
| wsrep_flow_control_interval_high | 173 |
| wsrep_flow_control_status | OFF |
| wsrep_cert_deps_distance | 0 |
| wsrep_apply_oooe | 0 |
| wsrep_apply_oool | 0 |
| wsrep_apply_window | 0 |
| wsrep_apply_waits | 0 |
| wsrep_commit_oooe | 0 |
| wsrep_commit_oool | 0 |
| wsrep_commit_window | 0 |
| wsrep_local_state | 4 |
| wsrep_local_state_comment | Synced |
| wsrep_cert_index_size | 0 |
| wsrep_cert_bucket_count | 1 |
| wsrep_gcache_pool_size | 3448 |
| wsrep_causal_reads | 0 |
| wsrep_cert_interval | 0 |
| wsrep_open_transactions | 0 |
| wsrep_open_connections | 0 |
| wsrep_ist_receive_status | |
| wsrep_ist_receive_seqno_start | 0 |
| wsrep_ist_receive_seqno_current | 0 |
| wsrep_ist_receive_seqno_end | 0 |
| wsrep_incoming_addresses | 192.168.150.13:3306,192.168.150.11:3306,192.168.150.12:3306 |
| wsrep_cluster_weight | 3 |
| wsrep_desync_count | 0 |
| wsrep_evs_delayed | |
| wsrep_evs_evict_list | |
| wsrep_evs_repl_latency | 0/0/0/0/0 |
| wsrep_evs_state | OPERATIONAL |
| wsrep_gcomm_uuid | df5aed67-940d-11ee-bc8f-8e8bab9eea9d |
| wsrep_gmcast_segment | 0 |
| wsrep_cluster_capabilities | |
| wsrep_cluster_conf_id | 3 |
| wsrep_cluster_size | 3 |
| wsrep_cluster_state_uuid | 47f68dce-940c-11ee-85d5-c29e7cbcc6e4 |
| wsrep_cluster_status | Primary |
| wsrep_connected | ON |
| wsrep_local_bf_aborts | 0 |
| wsrep_local_index | 2 |
| wsrep_provider_capabilities | :MULTI_MASTER:CERTIFICATION:PARALLEL_APPLYING:TRX_REPLAY:ISOLATION:PAUSE:CAUSAL_READS:INCREMENTAL_WRITESET:UNORDERED:PREORDERED:STREAMING:NBO: |
| wsrep_provider_name | Galera |
| wsrep_provider_vendor | Codership Oy <info@codership.com> (modified by Percona <https://percona.com/>) |
| wsrep_provider_version | 4.16(841837f) |
| wsrep_ready | ON |
| wsrep_thread_count | 9 |
+----------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------+
79 rows in set (0.00 sec)
查看 PXC 集群状态信息,在任意一个节点执行以下命令:
[root@pxc1 ~]# mysql -uroot -p123456 -e "show status like 'wsrep_cluster%';"
mysql: [Warning] Using a password on the command line interface can be insecure.
+----------------------------+--------------------------------------+
| Variable_name | Value |
+----------------------------+--------------------------------------+
| wsrep_cluster_weight | 3 |
| wsrep_cluster_capabilities | |
| wsrep_cluster_conf_id | 3 |
| wsrep_cluster_size | 3 |
| wsrep_cluster_state_uuid | 47f68dce-940c-11ee-85d5-c29e7cbcc6e4 |
| wsrep_cluster_status | Primary |
+----------------------------+--------------------------------------+
- 节点下线
PXC 集群允许动态下线节点,但需要注意的是节点的启动命令和关闭命令必须一致,如以引导模式启动的第一个节点必须
以引导模式来进行关闭:
# systemctl stop mysql@bootstrap.service
其他节点则可以按照正常方式关闭:
# systemctl stop mysqld