MySQL高可用集群方案之PXC

MySQL高可用集群方案之PXC

运维军团 536 阅读

1. 前言

在之前的公众号文章《 在游戏运维实战中摸索前行的“异地双活”架构 》中,我们向大家介绍了我们游戏中对“异地双活”架构的实践历程。

其中为了实现DB层的多点写入及数据强一致性,我们结合实际的业务场景测试对比了Percona Xtradb Cluster和MySQL Cluster。

我们选择最新版的sysbench 0.5版本来测试数据库性能。南北机器分别并发20、60、100个进程进行压测。以下是压测对比的结果:

从测试结果上看,大数量和大并发的场景下,MySQL Cluster集群的整体性能都越优于Percona Xtradb Cluster集群。这需要得益于MySQL Cluster基于内存的引擎NDB。但NDB引擎耗内存、易崩溃、运维成本巨大。而反观Percona Xtradb Cluster,节点与传统MySQL实例基本无异,日常运维也是差不多的。在性能方面我们可以借助SSD+RAID10提高IO性能,异地机房借助专线以降低网络抖动。基于实际场景,我们允许集群本身有一定的性能牺牲,然后借助底层硬件的提升来弥补,最终我们采用了Percona Xtradb Cluster。

今天,笔者向大家具体介绍Percona Xtradb Cluster,以及我们的经验总结。

2. 集群介绍

PerconaXtradb Cluster是一种完全开源的MySQL高可用解决方案,它将Percona Server、Percona XtraBackup与Galera库集成在一起,以实现同步多主复制的MySQL集群。

  • Multi-master的架构,数据多点写入并自动同步到集群。
  • 本地执行查询,所有节点都具备完整的数据副本,查询涉及本地数据。
  • 基于验证的复制机制,数据写入需要集群所有节点验证通过了才会提交,保证了数据的强一致性。
  • 去中心化架构,集群节点可自由伸缩,脱离集群的节点可以将其转为普通MySQL实例的角色提供服务。

PerconaXtradb Cluster作为一种出色的MySQL高可用解决方案,满足了现有业务架构的需求,但其劣势也是很明显,在使用前一定要摸清其短板。Percona Xtradb Cluster主要有以下限制:

  • 集群的复制只支持 InnoDB 引擎。
  • 集群吞吐量取决了性能最差的节点。
  • 不支持InnoDB fake changes和XA事务。
  • 不允许大事务,事务提交的最大行数及大小受制于变量: wsrep_max_ws_rows 和wsrep_max_ws_size variables。
  • 不支持锁表:LOCK TABLES、UNLOCK TABLES,不支持锁表函数: GET_LOCK()、RELEASE_LOCK()
  • 乐观锁并发控制,事务提交时仍可能在该阶段被中止。

3. 基础概念

除了摸清短板,要想玩好Percona Xtradb Cluster,还需要对集群的基础概念有一定的了解才好办。本节,笔者先给大家讲讲Percona Xtradb Cluster的一些重要基础概念。

3.1 常见术语

  • IST:数据增量同步,节点加入集群的数据同步方式
  • SST:数据全量同步,节点加入集群的数据同步方式
  • write-sets:事务写集
  • Donor节点:新节点加入集群时,集群会投票选出Donor节点提供新节点所需的数据

3.2 主要端口

  • 3306:节点对外提供服务的端口
  • 4567:节点间相互通信及复制的端口
  • 4444: SST使用的端口,Joiner节点以SST方式加入集群时启用该端口接受数据(Donor节点会启动随机端口主动来连接4444端口)
  • 4568: IST使用的端口,Joiner节点以IST方式加入集群时启用该端口接受数据(Donor节点会启动随机端口主动来连接4568端口)

3.3  grastate.dat

grastate.dat是节点状态记录文件,它一个非常重要的文件。节点故障恢复的第一步就是恢复这个文件,节点重新加入集群第一个需要关注的也是这个文件。这个文件位于数据目录下。该文件的内容如下:

  • uuid:节点所属集群的uuid
  • seqno:节点正常关闭时最后提交的事务编号,如果集群非正常关闭或者正在运行状态,seqno的值为-1
  • safe_to_bootstrap:集群最后一个关闭的节点的值为1,其它为0

节点重新加入集群时,会从grastat.dat中的seqno开始做IST。若这个文件不存在或者损坏了,那么意味着节点将会以SST的方式加入集群,这是我们最不愿见到的。

3.4  GCache

GCache是一种环形缓冲区,主要由内存、内存映射文件和物理文件组成。在节点运行期间,GCache缓存着最新的写集。Donor节点可以直接将GCache中最新增量数据给Joiner节点,实现Joiner节点快速加入集群。

GCache的使用顺序:优先使用内存,再使用映射文件,都用完了同时还是没有PURGE出空间来,则使用物理文件。

GCache的大小决定了节点可以离开集群多长时间重新以IST的方式加入集群。

3.5  重要的状态变量

  • wsrep_local_state_comment:节点当前的状态
  • wsrep_cluster_status:集群当前的状态
  • wsrep_local_cached_downto:当前节点gcache中缓存的最小事务编号
  • wsrep_last_committed :当前节点已提交的事务编号

4.基本维护

4.1 新集群的启动方式

第一个节点先初始化,再以bootstrap方式启动:

# 初始化 /usr/local/mysql/bin/mysqld --initialize --datadir=/data/database/mysql/ --basedir=/usr/local/mysql/ --user=mysql # 启动 /usr/local/mysql/bin/mysqld_safe --defaults-file=/etc/my.cnf--wsrep-new-cluster &

其他的节点无需初始化,直接按普通MySQL实例的方式启动,会自动加入集群。

4.2  集群全部关机后如何启动

原则:维护前最后关闭的节点,维护后以bootstrap的方式第一个启动

/usr/local/mysql/bin/mysqld_safe –defaults-file=/etc/my.cnf –wsrep-new-cluster&

Q:怎么知道哪个节点是最后关闭的?

A:从前面我们可以知道,grastate.dat文件中的safe_to_bootstrap字段,集

最后一个关闭的节点的值为1,其它为0。因此可以根据grastate.dat文件判断。

4.3  节点重启

节点不管以哪种方式离开集群,需要以IST的方式重新加入集群,都受到GCache大小的限制。在重新加入集群时,都不可直接启动节点,需要检查grastate.dat文件和对比集群中其他节点的“wsrep_local_cached_downto”状态,已确定是否能IST加入,具体我们在后面细说。

4.4  节点备份

使用xtrabackup/innobackupex进行全库备份时,加上–galera-info参数,备份会生成xtrabackup_galera_info文件。做故障恢复或者新节点加入时,可以直接利用这个文件重建grastate.dat。

xtrabackup_galera_info文件内容包含了集群UUID和备份时节点最新提交的事务编号,如下:

bf26341f-43cb-11e8-a863-62c0eb4d9e79:529045

5.常见故障处理

PerconaXtradb Cluster集群节点数推荐是3个节点,我们线上也采用3节点的部署方案。这里笔者就以3节点的集群作为说明。

5.1  节点进入非主模式

PerconaXtradb Cluster为了保证数据一致性,当某个节点脱离集群,或者发生脑裂时,节点数小于50%的子集群会进入非主模式拒绝对外提供服务。

如上图所示,AB两个节点故障宕机,集群只剩C节点,而C节点与另外两个节点失联认为自己脱离了集群而进入非主模式,这时候C节运行正常,但不允许执行任何SQL,如下报错:

ERROR 1047 (08S01): WSREP has not yet prepared node for applicationuse

这时候紧要急恢复业务,可以先让C节点允许访问,然后再恢复AB两个节点。可以在C上执行:

SET GLOBAL wsrep_provider_options=‘pc.bootstrap=true’;

这样就可以让C节点对外提供正常的读写服务了。

5.2 节点互相失联

如上图所示,因中间交换机的故障导致ABC三个节点相互失联,所有节点都进入非主模式,所有节点正常运行却都不可访问。为了紧急恢复业务,我们需要优先紧急恢复其中一个节点提供服务。但是这三个节点都正常运行,我们恢复哪个节点提供服务呢?从前面的介绍可以知道,节点的状态变量wsrep_last_committed 表示当前节点已提交的事务编号,我们可以让已提交事务最新的节点恢复服务:

5.3  节点宕机恢复思路

由于集群每个节点都有相同的数据副本,我们并不担心节点故障宕机会导致数据丢失。我们需要思考的是,节点故障宕机后如何正确恢复并重新加入集群。

对于故障节点,我们可以用xtrabackup/innobackupex拉取数据做IST加入集群,或者借助备份,甚至任性点清空故障节点的数据目录直接启动做SST加入。不过,相信不管是运维还是DBA,都希望直接利用本地已有的数据做IST恢复吧。

本小节,我们先给出故障节点如何以IST的方式重新加入集群的思路,后面做具体的实践。思路如下:

  • 恢复grastate.dat文件
  • 确定能否以IST的方式加入集群,既找到donor节点
  • 不存在合适的donor(无法IST),先追binlog,再IST

5.4  恢复grastate.dat文件

从前面对grastate.dat文件的说明可以知道,节点重启时需要从grastate.dat中读取seqno做IST。因此,故障恢复的第一步就是恢复grastate.dat文件。

恢复具体步骤:

1、直接启动服务,生成wsrep_recovery日志。

这时候启动会启动失败,因为mysqld进程因为找不到seqno而进行recovery,终端会打印如下内容:

mysqld_safe WSREP: Running position recovery with–log_error=‘/data/database/mysql/wsrep_recovery.5UKe8s’

2、借助wsrep_recovery日志,找到seqmo:

grep “Recovered” /data/database/mysql/wsrep_recovery.5UKe8s2018–04–03T08:18:54.534461Z 0 [Note] WSREP: Recovered position: bf26341f-43cb-11e8-a863-62c0eb4d9e79: 529045

3、重建grastate.dat文件:

# GALERA saved state version: 2.1uuid:    bf26341f-43cb-11e8-a863-62c0eb4d9e79 seqno:   529045safe_to_bootstrap: 0

到现在,一个宕机节点的grastate.dat文件就恢复好了。目前这个节点的状态如同一个正常关机的节点一样。但这不代表启动就一定会以IST的方式加入集群。

5.5  确定Donor节点

从集群中确定一个节点为donor节点,目的就是为了让重新加入集群的节点能从donor节点获得增量数据,以IST的方式加入集群。

1、查看集群现有节点gcache中最小事务编号:

2、 哪个节点gcache缓存中最小事务编号小于新加入节点的seqno,说明该节点的gcache缓存有故障节点宕机期间产生的所有事务。由上面的两个截图可以看出30.0.0.226(pxc-node-0)可以确定为donor节点。

3、指定donor节点启动:

/usr/local/mysql/bin/mysqld_safe --defaults-file=/etc/mysql.cnf--wsrep_sst_donor=pxc-node-0 &

到此,一个故障节点就恢复了,IST加入集群这个过程会非常快。但如果故障节点停机过长,或者数据量过大导致gcache不足以缓存停机期间的write-sets,那么就找不到donor节点而无法做IST。怎么办?

5.6  Binlog追数据

对于停机时间较长的节点,可能集群所有节点gcache缓存的write-sets都小于停机期间产生的write-sets,这时候停机节点将无法直接IST加入集群。不过可以借助binlog追数据,使停机节点的数据尽可能靠近集群,再做IST。

1、 借助已恢复的seqno找到其他节点的binlog的start-position:

如果停机期间,集群生成了多个binlog,那么就需要借助mysqlbinlog工具定位到具体的binlog文件。这里假设是mysql-bin.0000015:

mysqlbinlog -vv  mysql-bin.0000015| grep -A5 “Xid = 529045”

这里用到的特性就是Xid的值,也就是GTID值的后半部分,在集群中同一个事务对应的Xid值是完全一样并且有序的,只要找到Xid的值,就可以在其它节点中找到对应位置及相关信息。

2、导出binlog:

mysqlbinlog –skip-gtids=true  –start-position=388603320 -vv   mysql-bin.0000015  >  data.sql

这里需要借助–skip-gtids=true参数使解析出来的文件中就不包含“SET@@SESSION.GTID_NEXT=”,否则可能会binlog导入失效。

3、非主模式启动节点

这里让故障节点以非主模式启动,是为了和集群保持一致的uuid,同时又能独立启动以导入binlog。如下操作:

grastate.dat文件做如下修改:

safe_to_bootstrap: 1

独立启动:

/usr/local/mysql/bin/mysqld_safe --defaults-file=/etc/my.cnf   --wsrep-cluster-address="gcomm://" &

关闭非主模式,导入数据:

mysql> SET GLOBAL wsrep_provider_options='pc.bootstrap=true'; mysql> source data.sql ;

这里除了要导入data.sql,还需要导入mysql-bin.0000015之后的binlog,让故障节点尽可能追近集群。

关闭实例并还原grastate.dat配置:

safe_to_bootstrap: 0

4、正常启动实例

通过binlog,故障节点已经恢复到最接近集群的状态了。如果担心,也可以再检查是当前状态是否满足以IST方式加入集群,毕竟导binlog的过程也是很花时间的。

6.总结

文章对Percona Xtradb Cluster的介绍,比较浅显,更深入的探索,是需要结合业务场景进行钻研。

站在业务的角度,Percona Xtradb Cluster多点写入、数据强一致的特点确实十分诱人。站在运维的角度,Percona Xtradb Cluster需要花一番功夫:节点的性能、中间链路的稳定性、集群调优等,都是不小的一笔运维成本。展望未来,我们对Percona Xtradb Cluster仍需不断深入实践,从游戏的异地双活,再到平台级的多活。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值