gtid主从与传统主从


文章目录



1.主从复制

1.)普通主从复制:

普通主从复制主要是基于二进制日志文件位置的复制,因此主必须启动二进制日志记录并建立唯一的服务器ID,复制组中的每个服务器都必须配置唯一的服务器ID。如果您省略server-id(或者明确地将其设置为其默认值0),则主设备将拒绝来自从设备的任何连接。

2.) GTID 主从:

  • (1.)基本概念
    MySQL 5.6 的新特性之一,全局事务标识符(GTID)是创建的唯一标识符,并与在源(主)服务器上提交的每个事务相关联。此标识符不但是唯一的,而且在给定复制设置中的所有服务器上都是唯一的。所有交易和所有GTID之间都有一对一的映射关系 。它由服务器ID以及事务ID组合而成。这个全局事务ID不仅仅在原始服务器上唯一,在所有存在主从关系 的mysql服务器上也是唯一的。正是因为这样一个特性使得mysql的主从复制变得更加简单,以及数据库一致性更可靠。一个GTID在一个服务器上只执行一次,避免重复执行导致数据混乱或者主从不一致。

一个GTID被表示为一对坐标,用冒号(:)分隔,如下所示:GTID = source_id:transaction_id,source_id标识的源服务器。通常情况下,服务器 server_uuid用于这个目的。这transaction_id是一个序列号,由在此服务器上提交事务的顺序决定 .

3E11FA47-71CA-11E1-9E33-C80AA9429562:23

在传统的主从复制slave端,binlog是不用开启的,但是在GTID中slave端的binlog是必须开启的,目的是记录执行过的GTID(强制)。GTID用来代替classic的复制方法,不在使用binlog+pos开启复制。而是使用master_auto_postion=1的方式自动匹配GTID断点进行复制。
mysql的主从复制是十分经典的一个应用,但是主从之间总会有数据一致性(data consistency )的问题,一般情况从库会落后主库几个小时,而且在传统一主多从(mysql5.6之前)的模型中当master down掉后,我们不只是需要将一个slave提成master就可以,还要将其他slave的同步目的地从以前的master改成现在master,而且bin-log的序号和偏移量也要去查看,这是十分不方便和耗时的,但mysql5.6引入gtid之后解决了这个问题。

红色代表GTID,绿色代表传统主从:

2.gtid的生命周期

gtid的生命周期对于配置和维护基于gtid的复制至关重要。所以,请尽可能理解以下几个过程。

gtid在master和slave上是一直持久化保存(即使删除了日志,也会记录到Previous_GTID中)的。它在master和slave上的生命周期如下:

客户端发送DDL/DML给master上,master首先对此事务生成一个唯一的gtid,假如为uuid_xxx:1,然后立即执行该事务中的操作。
注意,主从复制的情况下,sync-binlog基本上都会设置为1,这表示在每次提交事务时将缓存中的binlog刷盘。所以,在事务提交前,gtid以及事务相关操作的信息都在缓存中,提交后它们才写入到binlog file中,然后才会被dump线程dump出去。

换句话说,只有提交了的事务,gtid和对应的事务操作才会记录到binlog文件中。记录的格式是先记录gtid,紧跟着再记录事务相关的操作。

  • 当binlog传送到relay log中后,slave上的SQL线程首先读取该gtid,并设置变量 gtid_next 的值为该gtid,表示下一个要操作的事务是该gtid。 gtid_next 是基于会话的,不同会话的gtid_next不同。
  • 随后slave检测该gtid在自己的binlog中是否存在。如果存在,则放弃此gtid事务;如果不存在,则将此gtid写入到自己的binlog中,然后立刻执行该事务,并在自己的binlog中记录该事务相关的操作。

注意,slave上replay的时候,gtid不是提交后才写到自己的binlog file的,而是判断gtid不存在后立即写入binlog file。

通过这种在执行事务前先检查并写gtid到binlog的机制,不仅可以保证当前会话在此之前没有执行过该事务,还能保证没有其他会话读取了该gtid却没有提交。因为如果其他会话读取了该gtid会立即写入到binlog(不管是否已经开始执行事务),所以当前会话总能读取到binlog中的该gtid,于是当前会话就会放弃该事务。总之,一个gtid事务是决不允许多次执行、多个会话并行执行的。

slave在重放relay log中的事务时,不会自己生成gtid,所以所有的slave(无论是何种方式的一主一从或一主多从复制架构)通过重放relay log中事务获取的gtid都来源于master,并永久保存在slave上。
一张图说明GTID复制
使用xtrabackup备份的方式提供gtid复制的基准数据。其中涉及到一些gtid检查、设置的操作。通过这些操作,大概可以感受的到gtid复制的几个概念。

用一张图来说明:

假如当前master的gtid为A3,已经purge掉的gtid为"1–>A1",备份到slave上的数据为1-A2部分。

如果A1 = 0,表示master的binlog没有被Purge过。slave可以直接开启gtid复制,但这样可能速度较慢,因为slave要复制所有binlog。也可以将master数据备份到slave上,然后设置 gtid_purged 跳过备份结束时的gtid,这样速度较快。

如果A1 != 0,表示master上的binlog中删除了一部分gtid。此时slave上必须先从master处恢复purge掉的那部分日志对应的数据。上图中备份结束时的GTID为A2。然后slave开启复制,唯一需要考虑的是"是否需要设置 gtid_purged 跳过一部分gtid以避免重复执行"。

备份数据到slave上,方式可以是mysqldump、冷备份、xtrabackup备份都行。由于gtid复制的特性,所需要的操作都很少,也很简单,前提是理解了"gtid的生命周期"。

3.基于gtid复制的好处

从上面可以看出,gtid复制的优点大致有:

  • 保证同一个事务在某slave上绝对只执行一次,没有执行过的gtid事务总是会被执行。
  • 不用像传统复制那样保证binlog的坐标准确,因为根本不需要binlog以及坐标。
  • 故障转移到新的master的时候很方便,简化了很多任务。
  • 很容易判断master和slave的数据是否一致。只要master上提交的事务在slave上也提交了,那么一定是一致的。

当然,MySQL提供了选项可以控制跳过某些gtid事务,防止slave第一次启动复制时执行master上的所有事务而导致耗时过久。

虽然对于row-based和statement-based的格式都能进行gtid复制,但建议采用row-based格式。

1.)GTID的工作原理:

1、当一个事务在主库端执行并提交时,产生GTID,一同记录到binlog日志中。
2、binlog传输到slave,并存储到slave的relaylog后,读取这个GTID的这个值设置gtid_next变量,即告诉Slave,下一个要执行的GTID值。
3、sql线程从relay log中获取GTID,然后对比slave端的binlog是否有该GTID。
4、如果有记录,说明该GTID的事务已经执行,slave会忽略。
5、如果没有记录,slave就会执行该GTID事务,并记录该GTID到自身的binlog,在读取执行事务前会先检查其他session持有该GTID,确保不被重复执行。
6、在解析过程中会判断是否有主键,如果有就用二级索引,如果没有就用全部扫描。

4.MySQL基于GTID主从复制配置

4.1 主服务器配置

//修改主配置文件
vim /etc/my.cnf
[mysqld]
basedir = /usr/local/mysql
datadir = /opt/data
socket = /tmp/mysql.sock
port = 3306
pid-file = /opt/data/mysql.pid
user = mysql
log-bin = mysql-bin
server-id = 1
log-error = /var/log/mysqld.log
binlog-format = row
log-slave-updates = true
enforce-gtid-consistency = true
gtid-mode = on
//重启服务
service mysqld restart
//进入mysql
mysql
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000007 | 154 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

mysql> show global variables like '%uuid%';
+---------------+--------------------------------------+
| Variable_name | Value |
+---------------+--------------------------------------+
| server_uuid | 91284b51-76b6-11e9-bc39-000c291926d0 |
+---------------+--------------------------------------+
1 row in set (0.01 sec)

mysql> show global variables like '%gtid%';
+----------------------------------+-------+
| Variable_name | Value |
+----------------------------------+-------+
| binlog_gtid_simple_recovery | ON |
| enforce_gtid_consistency | ON |
| gtid_executed | |
| gtid_executed_compression_period | 1000 |
| gtid_mode | ON |
| gtid_owned | |
| gtid_purged | |
| session_track_gtids | OFF |
+----------------------------------+-------+
8 rows in set (0.00 sec)
grant replication slave on *.* to root@'192.168.43.%' identified by '123456'; //ip段与账号密码
flush privileges; //刷新权限

4.2 从服务器配置

//将当前sql文件拷贝到从服务器,这里使用scp命令
.
//拷贝完之后,进入从服务器Mysql终端,创建目标数据库,然后倒入到从库
mysql < all.sql
//配置主配置文件
vim /etc/my.cnf
[mysqld]
basedir = /usr/local/mysql
datadir = /opt/data
socket = /tmp/mysql.sock
port = 3306
pid-file = /opt/data/mysql.pid
user = mysql
server-id = 3
relay-log = relay-log-bin
log-error = /var/log/mysqld.log
binlog-format = row
log-slave-updates = true
enforce-gtid-consistency = true
gtid-mode = on
read_only = on
//重启服务
service mysqld restart
//进入mysql
mysql
//使用change master配置主从
change master to master_host='192.168.136.142',master_user='root',master_passwrd='1',master_auto_position=154,master_auto_file='mysql-bin.000007';
//配置完成启动slave
start slave;

4.3 验证

主服务器:

mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| aaa |
| mysql |
| performance_schema |
| sys |
| wang |
+--------------------+
6 rows in set (0.00 sec)

mysql> create database bbb;
Query OK, 1 row affected (0.00 sec)

mysql>

从服务器:

mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| aaa |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)

mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| aaa |
| bbb |
| mysql |
| performance_schema |
| sys |
+--------------------+
6 rows in set (0.00 sec)