MySQL之PXC集群搭建
一、PXC 介绍
1.1 PXC 简介
PXC 是一套 MySQL 高可用集群解决方案,与传统的基于主从复制模式的集群架构相比 PXC 最突出特点就是解决了诟病已久的数据复制延迟问题,基本上可以达到实时同步。而且节点与节点之间,他们相互的关系是对等的。PXC 最关注的是数据的一致性,对待事物的行为时,要么在所有节点上执行,要么都不执行,它的实现机制决定了它对待一致性的行为非常严格,这也能非常完美的保证 MySQL 集群的数据一致性;
1.2 PXC特性和优点
完全兼容 MySQL。
同步复制,事务要么在所有节点提交或不提交。
多主复制,可以在任意节点进行写操作。
在从服务器上并行应用事件,真正意义上的并行复制。
节点自动配置,数据一致性,不再是异步复制。
故障切换:因为支持多点写入,所以在出现数据库故障时可以很容易的进行故障切换。
自动节点克隆:在新增节点或停机维护时,增量数据或基础数据不需要人工手动备份提供,galera cluster会自动拉取在线节点数据,集群最终会变为一致;
PXC最大的优势:强一致性、无同步延迟
1.3 PXC的局限和劣势
复制只支持InnoDB 引擎,其他存储引擎的更改不复制
写入效率取决于节点中最慢的一台
1.4 PXC与Replication的区别
Replication PXC
数据同步是单向的,master负责写,然后异步复制给slave;如果slave写入数据,不会复制给master。 数据同步时双向的,任何一个mysql节点写入数据,都会同步到集群中其它的节点。
异步复制,从和主无法保证数据的一致性 同步复制,事务在所有集群节点要么同时提交,要么同时不提交
1.5 PXC 常用端口
3306:数据库对外服务的端口号。
4444:请求SST的端口。
4567:组成员之间进行沟通的一个端口号
4568:用于传输IST。
名词解释:
SST(State Snapshot Transfer): 全量传输
IST(Incremental state Transfer):增量传输
二、实践
2.1 搭建 PXC 集群
与 MySQL 不同的是 PXC 官方提供了 Docker 镜像,所以我们可以很方便的搭建 PXC 集群。
1)下载 Docker 镜像
docker pull percona/percona-xtradb-cluster:5.7
2) 重命名镜像名称
docker tag percona/percona-xtradb-cluster:5.7 pxc:5.7
3)删除原始镜像
docker rmi percona/percona-xtradb-cluster:5.7
4) 创建 Docker 网络,用于 PXC 集群独立使用
docker network create pxc-network
5) 创建数据卷用于之后挂载
docker volume create --name v1
docker volume create --name v2
docker volume create --name v3
注:PXC容器只支持数据卷挂载方式,不支持目录挂载
6) 创建第一个节点
docker run -di --name=pn1 --net=pxc-network -p 9000:3306 -v v1:/var/lib/mysql --privileged -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=cluster1 -e XTRABACKUP_PASSWORD=123456 pxc:5.7
因为后续节点的添加需要关联到第一个节点,所以需要等待数据库启动完成。通过 docker logs pn1 查看日志,如果出现下面的输出,证明启动成功:
2019-09-04T06:27:30.085880Z 0 [Note] InnoDB: Buffer pool(s) load completed at 190904 6:27:30
注:CLUSTER_NAME 名称不要用关键字PXC,否则无法启动。
7) 加入第二个节点
docker run -di --name=pn2 --net=pxc-network -p 9001:3306 -v v2:/var/lib/mysql --privileged -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=cluster1 -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=pn1 pxc:5.7
需要注意是第二个节点开始需要增加 e CLUSTER_JOIN=pn1 参数,表示与 pn1 节点同步,否则 pn1 容器会自动关闭。
当 PXC集群中存在两个节点以上之后就没有主节点的概念了。集群中最后一个退出的节点就会变为主节点,在 /var/lib/mysql/grastate.dat 文件中属性 safe_to_bootstrap 的值 会从 0 被设置为 1 表示该节点是主节点。
8)加入第三个节点
docker run -di --name=pn3 --net=pxc-network -p 9002:3306 -v v3:/var/lib/mysql --privileged -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=cluster1 -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=pn2 pxc:5.7
可以看到我们这次我们 CLUSTER_JOIN 的是 pn2 容器,可以证明我们刚刚说的 当 PXC 集群存在两个节点以上之后就没有主节点的概念了 这个说法是正确的。
9)进入 pn1 节点
docker exec -it pn1 /usr/bin/mysql -uroot -p123456
10) 查看状态
mysql> show status like 'wsrep%';
+----------------------------------+-------------------------------------------------+
| Variable_name | Value |
+----------------------------------+-------------------------------------------------+
| wsrep_local_state_uuid | 068dd5e8-cedd-11e9-904d-466e75bd8fe1 |
| wsrep_protocol_version | 9 |
| wsrep_last_applied | 16 |
| wsrep_last_committed | 16 |
| 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 | 10 |
| wsrep_received_bytes | 800 |
| 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.000000 |
| wsrep_local_recv_queue | 0 |
| wsrep_local_recv_queue_max | 2 |
| wsrep_local_recv_queue_min | 0 |
| wsrep_local_recv_queue_avg | 0.100000 |
| wsrep_local_cached_downto | 0 |
| wsrep_flow_control_paused_ns | 0 |
| wsrep_flow_control_paused | 0.000000 |
| wsrep_flow_control_sent | 0 |
| wsrep_flow_control_recv | 0 |
| 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.000000 |
| wsrep_apply_oooe | 0.000000 |
| wsrep_apply_oool | 0.000000 |
| wsrep_apply_window | 0.000000 |
| wsrep_commit_oooe | 0.000000 |
| wsrep_commit_oool | 0.000000 |
| wsrep_commit_window | 0.000000 |
| wsrep_local_state | 4 |
| wsrep_local_state_comment | Synced |
| wsrep_cert_index_size | 0 |
| wsrep_cert_bucket_count | 22 |
| wsrep_gcache_pool_size | 1592 |
| wsrep_causal_reads | 0 |
| wsrep_cert_interval | 0.000000 |
| 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 | 172.19.0.4:3306,172.19.0.3:3306,172.19.0.2: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 | 11ed51e2-cedd-11e9-b362-af453a7ac074 |
| wsrep_cluster_conf_id | 3 |
| wsrep_cluster_size | 3 |
| wsrep_cluster_state_uuid | 068dd5e8-cedd-11e9-904d-466e75bd8fe1 |
| wsrep_cluster_status | Primary |
| wsrep_connected | ON |
| wsrep_local_bf_aborts | 0 |
| wsrep_local_index | 0 |
| wsrep_provider_name | Galera |
| wsrep_provider_vendor | Codership Oy |
| wsrep_provider_version | 3.37(rff05089) |
| wsrep_ready | ON |
+----------------------------------+-------------------------------------------------+
71 rows in set (0.06 sec)
可以看到 wsrep_incoming_addresses 的值就是我们三个容器的IP地址
| wsrep_incoming_addresses | 172.19.0.2:3306,172.19.0.3:3306,172.19.0.4:3306 |
集群完整性检查:
属性 含义
wsrep_cluster_state_uuid 在集群所有节点的值应该是相同的,有不同值的节点,说明其没有连接入集群.
wsrep_cluster_conf_id 正常情况下所有节点上该值是一样的.如果值不同,说明该节点被临时”分区”了.当节点之间网络连接恢复 的时候应该会恢复一样的值.
wsrep_cluster_size 如果这个值跟预期的节点数一致,则所有的集群节点已经连接.
wsrep_cluster_status 集群组成的状态.如果不为”Primary”,说明出现”分区”或是”split-brain”脑裂状况.
节点状态检查:
属性 含义
wsrep_ready 该值为 ON,则说明可以接受 SQL 负载.如果为 Off,则需要检查 wsrep_connected
wsrep_connected 如果该值为 Off,且 wsrep_ready 的值也为 Off,则说明该节点没有连接到集群.(可能是 wsrep_cluster_address 或 wsrep_cluster_name 等配置错造成的.具体错误需要查看错误日志)
wsrep_local_state_comment 如果 wsrep_connected 为 On,但 wsrep_ready 为 OFF,则可以从该项查看原因
复制健康检查:
属性 含义
wsrep_flow_control_paused 表示复制停止了多长时间.即表明集群因为 Slave 延迟而慢的程度.值为 0~1,越靠近 0 越好,值为 1 表示 复制完全停止.可优化 wsrep_slave_threads 的值来改善
wsrep_cert_deps_distance 有多少事务可以并行应用处理.wsrep_slave_threads 设置的值不应该高出该值太多
wsrep_flow_control_sent 表示该节点已经停止复制了多少次
*wsrep_local_recv_queue_avg 表示 slave 事务队列的平均长度.slave 瓶颈的预兆. 最慢的节点的 wsrep_flow_control_sent 和 wsrep_local_recv_queue_avg 这两个值最高.这两个值较低的话,相对更好
检测慢网络问题:
属性 含义
wsrep_local_send_queue_avg 网络瓶颈的预兆.如果这个值比较高的话,可能存在网络瓶颈
冲突或死锁的数目:
属性 含义
wsrep_last_committed 最后提交的事务数目
wsrep_local_cert_failures 和 wsrep_local_bf_aborts 回滚,检测到的冲突数目
2.2 集群同步验证
1) 在节点一上创建数据库 test
mysql> create database test;
Query OK, 1 row affected (0.02 sec)
2) 节点二上查看:
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
5 rows in set (0.00 sec)
3) 在节点二上创建表
mysql> use test;
Database changed
mysql> create table sys_user(id int ,name varchar(30));
Query OK, 0 rows affected (0.11 sec)
4)在节点三上查看表结构
mysql> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| sys_user |
+----------------+
1 row in set (0.00 sec)
5) 在节点三上插入数据
mysql> insert into sys_user values(1,'a');
ERROR 1105 (HY000): Percona-XtraDB-Cluster prohibits use of DML command on a table (test.sys_user) without an explicit primary key with pxc_strict_mode = ENFORCING or MASTER
看到没有显示的主键就无法插入数据,我们修改下表结构:
alter table sys_user add primary key (id);
插入数据:
mysql> insert into sys_user values(1,'a');
Query OK, 1 row affected (0.05 sec)
6)在节点一查看表数据
mysql> select * from sys_user;
+----+------+
| id | name |
+----+------+
| 1 | a |
+----+------+
1 row in set (0.00 sec)
可以看到三个节点数据正常同步,并且都可读可写。
2.3 新增数据库节点操作
当数据库不够用时,我们通常需要增加数据库节点来分担压力,我们来演示一下新增节点的操作。
1) 创建数据卷
docker volume create --name v4
2)新增容器
docker run -di --name=pn4 --net=pxc-network -p 9003:3306 -v v4:/var/lib/mysql --privileged -e MYSQL_ROOT_PASSWORD=123456 -e CLUSTER_NAME=cluster1 -e XTRABACKUP_PASSWORD=123456 -e CLUSTER_JOIN=pn3 pxc:5.7
要注意的是,这次 CLUSTER_JOIN 连的是 pn3。
1) 进入节点4查看数据
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| test |
+--------------------+
5 rows in set (0.00 sec)
mysql> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| sys_user |
+----------------+
1 row in set (0.00 sec)
mysql> select * from sys_user;
+----+------+
| id | name |
+----+------+
| 1 | a |
+----+------+
1 row in set (0.00 sec)
可以看到之前的数据也自动同步过来了。
2.4 宕机操作
1) 将节点pn4容器关闭,造成宕机现象
docker stop pn4
2) 在节点 pn2 上做查看集群状态
mysql> show status like 'wsrep%';
......
| wsrep_local_state | 4 |
| wsrep_local_state_comment | Synced |
| wsrep_cert_index_size | 3 |
......
| wsrep_incoming_addresses | 172.19.0.4:3306,172.19.0.3:3306,172.19.0.2:3306 |
可以看到集群应该有4个节点,但是现在只有3个正常连接。
3)在节点 pn2 上做修改操作
mysql> update sys_user set name='b' where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
4) 将节点 pn4 容器启动
[root@VM_0_15_centos ~]# docker start pn4
5) 进入容器 pn4 查看修改操作是否同步
docker exec -it pn4 /usr/bin/mysq