MySQL 5.6新特性:基于GTID的同步方式

目录:

[图片上传失败…(image-114f7d-1618587087549)]

背景

在我们之前的文章中,无论是【MySQL主从集群原理+实战】还是【MySQL+Keepalived主从高可用集群原理+实战】采用的都是MySQL的传统复制方式:基于binlog文件名和偏移量的方式,即形如如下命令:

CHANGE MASTER TO
MASTER_HOST='172.17.0.11',
MASTER_USER='repl',
MASTER_PASSWORD='repl',
MASTER_LOG_FILE='mysql-bin-master.000001',
MASTER_LOG_POS=154;

其中MASTER_LOG_FILE就是我们所说的binlog文件名,MASTER_LOG_POS就是binlog偏移量

假设Master宕机以后,选一个Slave作为新的Master,那么原来的Master变成了Slave,它要挂载在现在新的Master上,那么MASTER_LOG_FILE和MASTER_LOG_POS应该咋填?不可能填现在的吧,因为新的Master还在接受写请求,数据已经超过了原来的Master了

如果填小了可能会出现数据重复,填大了可能出现数据丢失,这个工作应该让MySQL自己来做,那么这就是GTID做的事情。

GTID是什么?

GTID全称为Global Transaction Identifier,即全局事务标识,它在整个集群中都是唯一的,表现形式为

GTID = server_uuid:transaction_id

server_uuid即我们之前提到的$MYSQL_HOME/data/auto.cnf,集群中的每台实例都是唯一的,删掉该文件后会重新生成,transaction_id就是一个整型数字

如下表示的是Master为 3E11FA47-71CA-11E1-9E33-C80AA9429562、事务id为23的一个GTID

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

还可以范围表示,如下表示1到100的事务

3E11FA47-71CA-11E1-9E33-C80AA9429562:1-100

GTID也是基于binlog的,在binlog中的表现形式如下,每一个GTID都表示一个已经被提交的事务

image

这样Slave就可以通过GTID来标识哪些事务是同步过的,哪些是没同步过的,具体的做法是Salve把自己同步过的GTID放到gtid_executed中,然后比较新来的GTID是否在gtid_executed中,如果在,说明已经同步过了,不需要再次同步,否则需要进行同步。

Slave也可以通过COM_BINLOG_DUMP_GTID协议将自己的执行过的GTID发送给Master,Master再返回Slave没有同步过的GTID集合,总之,比较这个动作可以在Slave上进行,也可以在Master上进行。

局限性

因为GTID是基于事务的,所以MySQL只允许能够保障事务安全,并且能够被日志记录的SQL语句被执行,像create table … select 和 create temporary table语句,以及同时更新事务表和非事务表的SQL语句或事务都不允许执行,这个如下,on表示开启GTID事务的一致性,即上面的非事务一致性的语句执行会报错!

enforce-gtid-consistency = on

简单主从同步

环境准备

我们以为之前设置过的简单主从为例,环境为

docker run -dit  --name m1 --privileged centos /usr/sbin/init
docker run -dit  --name m2 --privileged centos /usr/sbin/init

ip地址分别如下,以m1作为Master,m2作为Slave

m1 172.17.0.10
m2 172.17.0.11

MYSQL_HOME变量定义,每台都定义下,后面的命令都依赖MYSQL_HOME

# 定义变量
MYSQL_VERSION=5.7.24
MYSQL_HOME=/usr/local/mysql-$MYSQL_VERSION

重置配置

如果哪个步骤出问题了,需要重新来,可以通过下面的方法重置

  • 删除所有的库,分开执行
mysql -uroot -p  -e "show databases" | grep -vE 'mysql|information_schema|performance_schema|test|sys|Database' | awk '{ print "drop database "$1";" }' > drop.sql && cat drop.sql

mysql -uroot -p < drop.sql
  • 重置Slave
STOP SLAVE;
RESET SLAVE;
  • 重置Master,binlog将会重新开始
RESET MASTER;

Master配置

主要关注gtid和binlog的配置

# 先用-15优雅杀掉进程
ps aux  | grep -v grep | grep  mysql | awk '{ print $2 }' | xargs kill -15
sleep 1

# 修改配置
cat > /etc/my.cnf <<EOF
[mysqld]
user=mysql
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
datadir=$MYSQL_HOME/data
server-id=1       # server id唯一

# gtid
gtid_mode=on                 #开启gtid模式
enforce_gtid_consistency=on  #强制gtid一致性,开启后对于特定create table不被支持

# binlog
log-bin=master-mysql-bin   # 启用Binary Log
expire_logs_days=5  # 设置binlog5天后清理,默认不清理
log-slave-updates=1 # 作为slave时,记录slave的日志到binlog中   
binlog_format=row   #强烈建议,其他格式可能造成数据不一致

[mysqld_safe]
log-error=$MYSQL_HOME/logs/mysqld.log
pid-file=$MYSQL_HOME/pids/mysqld.pid

[client]
default-character-set=utf8mb4
EOF

# 启动
/etc/init.d/mysqld start

# 查看启动日志
tail -f $MYSQL_HOME/logs/mysqld.log

创建同步用户

DROP USER 'repl'@'%';
CREATE USER 'repl'@'%' IDENTIFIED BY 'repl';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
flush privileges;

Slave配置

主要关注gtid和binlog的配置

# 先用-15优雅杀掉进程
ps aux  | grep -v grep | grep  mysql | awk '{ print $2 }' | xargs kill -15
sleep 1

# 修改配置
cat > /etc/my.cnf <<EOF
[mysqld]
user=mysql
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
datadir=$MYSQL_HOME/data
server-id=2       # server id唯一
read_only=1       # Slave只读

# gtid
gtid_mode=on                 #开启gtid模式
enforce_gtid_consistency=on  #强制gtid一致性,开启后对于特定create table不被支持

# binlog
log-bin=slave-mysql-bin   # 启用Binary Log
expire_logs_days=5  # 设置binlog5天后清理,默认不清理
log-slave-updates=1 # 作为slave时,记录slave的日志到binlog中   
binlog_format=row   #强烈建议,其他格式可能造成数据不一致

[mysqld_safe]
log-error=$MYSQL_HOME/logs/mysqld.log
pid-file=$MYSQL_HOME/pids/mysqld.pid

[client]
default-character-set=utf8mb4
EOF

# 启动
/etc/init.d/mysqld start

# 查看启动日志
tail -f $MYSQL_HOME/logs/mysqld.log

设置主从同步

挂载Slave到Master上,如果Master上已经有数据了,需要先同步数据到Slave上,需要注意的是此时要锁住Master避免写操作,具体参考【MySQL主从集群原理+实战】的【配置主从集群(异步)】章节,此处不再赘述

STOP SLAVE;
RESET SLAVE;

CHANGE MASTER TO
MASTER_HOST='172.17.0.10',
MASTER_USER='repl',
MASTER_PASSWORD='repl',
MASTER_AUTO_POSITION = 1;

START SLAVE;

SHOW SLAVE STATUS\G;

我们对比下和以前的设置语句有什么不同

CHANGE MASTER TO
MASTER_HOST='172.17.0.10',
MASTER_USER='repl',
MASTER_PASSWORD='repl',
MASTER_LOG_FILE='mysql-bin-master.000001',
MASTER_LOG_POS=154;

主要是不用指定MASTER_LOG_FILE和MASTER_LOG_POS参数了,不要找点了,找点的事情给MySQL自己去做吧,他可以帮你准确的找到正确的点!

测试

随便给点SQL测试下,在Master上执行DML语句,在Slave上如果能看到同步的数据说明主从同步设置成功!

-- Master执行
create database tom;
use tom;
create table `user`(
    `id` int comment 'id',
    `name` varchar(50) comment '姓名'
);
insert into user values (1,'Tom'),(2,'Jerry');

-- Slave执行
use tom;
select*from  user;

如果Master宕机了,一部分数据没有同步到,如果是经典的主从复制的话需要去Master上找点,重新挂载Slave上去,因为此时binlog已经更新了,如下图,binlog从000002开始了

mysql> show master status;
+
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

代码狂魔v

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值