一、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
docker tag percona/percona-xtradb-cluster:5.7 pxc:5.7
docker rmi percona/percona-xtradb-cluster:5.7
docker network create pxc-network
docker volume create --name v1docker volume create --name v2docker volume create --name v3

创建第一个节点

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 

2019-09-04T06:27:30.085880Z 0 [Note] InnoDB: Buffer pool(s) load completed at 190904 6:27:30

注:CLUSTER_NAME 名称不要用关键字PXC,否则无法启动。

加入第二个节点

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  

当 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  

9)进入 pn1 节点

docker exec -it pn1 /usr/bin/mysql -uroot -p123456
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.2:3306,172.19.0.3:3306,172.19.0.4: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 <info@codership.com>               || wsrep_provider_version           | 3.37(rff05089)                                  || wsrep_ready                      | ON                                              |+----------------------------------+-------------------------------------------------+71 rows in set (0.06 sec)
| 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 回滚,检测到的冲突数目
mysql> create database test;Query OK, 1 row affected (0.02 sec)
mysql> show databases;+--------------------+| Database           |+--------------------+| information_schema || mysql              || performance_schema || sys                || test               |+--------------------+5 rows in set (0.00 sec)
mysql> use test;Database changedmysql> create table sys_user(id int ,name varchar(30));Query OK, 0 rows affected (0.11 sec)
mysql> use test;Reading table information for completion of table and column namesYou can turn off this feature to get a quicker startup with -ADatabase changedmysql> show tables;+----------------+| Tables_in_test |+----------------+| sys_user       |+----------------+1 row in set (0.00 sec)
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)
mysql> select * from sys_user;+----+------+| id | name |+----+------+|  1 | a    |+----+------+1 row in set (0.00 sec)

2.3 新增数据库节点操作

当数据库不够用时,我们通常需要增加数据库节点来分担压力,我们来演示一下新增节点的操作。

创建数据卷

docker volume create --name v4
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 

进入节点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 namesYou can turn off this feature to get a quicker startup with -ADatabase changedmysql> 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 宕机操作

将节点pn4容器关闭,造成宕机现象

docker stop pn4
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 |

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
[root@VM_0_15_centos ~]# docker start pn4
docker exec -it pn4 /usr/bin/mysql -uroot -p123456

pn4 是以指定主节点形式进入 PXC 集群创建的容器,那么 pn1直接以自身为主节点启动的容器会怎么样呢?我们来演示一下:

关闭 pn1 节点

docker stop pn1
mysql> insert into sys_user values('2','c');Query OK, 1 row affected (0.01 sec)
docker start pn1
docker ps -a
CONTAINER ID        IMAGE    ......   STATUS                           NAMESfa123563e787        pxc:5.7  ......   Exited (1) About a minute ago    pn1               
docker logs pn1

2019-09-04T07:21:56.412918Z 0 [ERROR] WSREP: It may not be safe to bootstrap the cluster from this node. It was not the last one to leave the cluster and may not contain all the updates. To force cluster bootstrap with this node, edit the grastate.dat file manually and set safe_to_bootstrap to 1 .
2019-09-04T07:21:56.412922Z 0 [ERROR] WSREP: Provider/Node (gcomm://) failed to establish connection with cluster (reason: 7)
2019-09-04T07:21:56.412929Z 0 [ERROR] Aborting

翻译成中文:

2019-09-04T07:21:56.412918Z 0 [错误] WSREP:从此节点引导群集可能不安全。 它不是离开群集的最后一个,可能不包含所有更新。 要使用此节点强制群集引导,请手动编辑grastate.dat文件并将safe_to_bootstrap设置为1。
2019-09-04T07:21:56.412922Z 0 [错误] WSREP:提供者/节点(gcomm://)无法与群集建立连接(原因:7)
2019-09-04T07:21:56.412929Z 0 [错误]中止

错误提示很明显了,因为 pn1 节点不是最后一个离开集群的不能再以主节点的形式启动了,如果要以主节点的形式启动必须调整 grastate.dat文件中的 safe_to_bootstrap 参数为 1。

但是要注意的是因为集群中其他节点并没有关闭,这样启动的容器跟之前的集群就没有关系了数据也不会同步,我们来验证下看看:

查看数据卷存放的路径

docker volume inspect v1[    {        "CreatedAt": "2019-09-05T09:22:22+08:00",        "Driver": "local",        "Labels": {},        "Mountpoint": "/var/lib/docker/volumes/v1/_data",        "Name": "v1",        "Options": {},        "Scope": "local"    }]
[root@VM_0_15_centos ~]# cd /var/lib/docker/volumes/v1/_data[root@VM_0_15_centos _data]# lltotal 323444-rw-r----- 1 1001 1001        56 Sep  5 08:34 auto.cnf-rw------- 1 1001 1001      1680 Sep  5 08:34 ca-key.pem-rw-r--r-- 1 1001 1001      1120 Sep  5 08:34 ca.pem-rw-r--r-- 1 1001 1001      1120 Sep  5 08:34 client-cert.pem-rw------- 1 1001 1001      1676 Sep  5 08:34 client-key.pem-rw-r----- 1 1001 1001         2 Sep  5 08:34 fa123563e787.pid-rw-r----- 1 1001 1001 134219048 Sep  5 09:22 galera.cache-rw-r----- 1 1001 1001       113 Sep  5 09:21 grastate.dat-rw-r----- 1 1001 1001      1300 Sep  5 08:34 ib_buffer_pool-rw-r----- 1 1001 1001  79691776 Sep  5 09:15 ibdata1-rw-r----- 1 1001 1001  50331648 Sep  5 09:15 ib_logfile0-rw-r----- 1 1001 1001  50331648 Sep  5 08:34 ib_logfile1-rw-r----- 1 1001 1001  12582912 Sep  5 08:38 ibtmp1-rw-r----- 1 1001 1001     34751 Sep  5 08:38 innobackup.backup.logdrwxr-x--- 2 1001 1001      4096 Sep  5 08:34 mysqldrwxr-x--- 2 1001 1001      4096 Sep  5 08:34 performance_schema-rw------- 1 1001 1001      1676 Sep  5 08:34 private_key.pem-rw-r--r-- 1 1001 1001       452 Sep  5 08:34 public_key.pem-rw-r--r-- 1 1001 1001      1120 Sep  5 08:34 server-cert.pem-rw------- 1 1001 1001      1676 Sep  5 08:34 server-key.pemdrwxr-x--- 2 1001 1001     12288 Sep  5 08:34 sysdrwxr-x--- 2 1001 1001      4096 Sep  5 09:07 test-rw-r--r-- 1 1001 1001       143 Sep  5 09:22 version_info-rw-r----- 1 1001 1001   3932160 Sep  5 09:15 xb_doublewrite
vim grastate.dat
# GALERA saved stateversion: 2.1uuid:    068dd5e8-cedd-11e9-904d-466e75bd8fe1seqno:   20safe_to_bootstrap: 1
docker start pn1
docker exec -it pn1 /usr/bin/mysql -uroot -p123456

我们可以直接将 pn1 容器删除,以加入节点的形式重新创建容器,并且因为我们之前已经将容器的数据挂载到数据卷了,所以数据也不会存在丢失的风险,我们来操作下:

删除 pn1容器

docker stop pn1docker rm pn1
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 -e CLUSTER_JOIN=pn2 pxc:5.7  

3)进入容器,查看数据是否同步

docker exec -it pn1 /usr/bin/mysql -uroot -p123456

更多相关文章

  1. 发现 developer.android.com 官网的一个单词错误:
  2. 背部如何画好?动漫人物背部画法步骤
  3. android 命令(adb shell)进入指定模拟器或设备
  4. Android--WebView+HTML+Javascript
  5. Android绘制简单折线图的步骤
  6. Android(安卓)Junit 单元测试步骤
  7. Android(安卓)TextToSpeech语音播放文本
  8. Android中LiveData+Room+Paging简单实现步骤
  9. android sdk支持ant自动构建jar步骤

随机推荐

  1. 关于android:layout_weight属性使用注意
  2. Android动态换肤(二、apk免安装插件方式)
  3. Android(安卓)Activity基础概念
  4. 共享Android开发手册
  5. Android事件分发
  6. Android(安卓)Studio学习之安装插件
  7. Android中gravity的各种效果图
  8. Android(安卓)Service
  9. 通用(任何android机型)Root教程(完整版!附砖
  10. Xamarin.Android使用教程之创建第一个And