把嘴给我闭上!我说个数,五分钟!搞懂-MySQL主从复制原理

即可支持一个 schema(库) 下,slave_parallel_workers个 worker 线程并发执行 relay log 中主库提交的事务。

其核心思想:

一个组提交的事务都是可以并行回放(配合binary log group commit);

slave 机器的 relay log 中 last_committed 相同的事务(sequence_num不同)可以并发执行。其中,变量 slave-parallel-type 可以有两个值:

  1. DATABASE 默认值,基于库的并行复制方式
  2. LOGICAL_CLOCK,基于组提交的并行复制方式

MySQL 5.7 开启 MTS 很简单,只需要在 Slave 从数据库的 my.cnf 文件中如下配置即可:

slave

slave-parallel-type=LOGICAL_CLOCK
slave-parallel-workers=8 #一般建议设置4-8,太多的线程会增加线程之间的同步开销
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON

当然多线程带来的并行复制方案也有很多实现难点,比如事务都是有序执行的,如果并行回放会不会存在执行数据错乱的问题。这些问题就不在本节解释,大家有兴趣可以继续深究。

新一代主从复制模式 - GTID 复制模式

在传统的复制里面,当发生故障,需要主从切换,需要找到 Binlog 和 位点信息,恢复完成数据之后将主节点指向新的主节点。在 MySQL 5.6 里面,提供了新的数据恢复思路,只需要知道主节点的 IP、端口以及账号密码就行,因为复制是自动的,MySQL 会通过内部机制 GTID自动找点同步。

基于 GTID 的复制是 MySQL 5.6.5 后新增的复制方式。

GTID (global transaction identifier) 即全局事务 ID,一个事务对应一个 GTID,保证了在每个在主库上提交的事务在集群中有一个唯一的 ID。

GTID复制原理

在原来基于日志的复制中,从库需要告知主库要从哪个偏移量进行增量同步, 如果指定错误会造成数据的遗漏,从而造成数据的不一致。

而基于 GTID 的复制中,从库会告知主库已经执行的事务的 GTID 的值,然后主库会将所有未执行的事务的 GTID 的列表返回给从库,并且可以保证同一个事务只在指定的从库执行一次,通过全局的事务 ID 确定从库要执行的事务的方式代替了以前需要用 Binlog 和 位点确定从库要执行的事务的方式

基于 GTID 的复制过程如下:

  1. master 更新数据时,会在事务前产生 GTID,一同记录到 Binlog 日志中。
  2. slave 端的 I/O 线程将变更的 Binlog,写入到本地的 relay log 中,读取值是根据gitd_next变量,告诉我们 slave 下一个执行哪个 GTID。
  3. SQL 线程从 relay log 中获取 GTID,然后对比 slave 端的 Binlog 是否有记录。如果有记录,说明该 GTID 的事务已经执行,slave 会忽略。
  4. 如果没有记录,slave 就会从 relay log 中执行该 GTID 的事务,并记录到 Binlog。
  5. 在解析过程中会判断是否有主键,如果没有就用二级索引,如果没有二级索引就用全部扫描。
GTID 组成

GTID = source_id:transaction_id

source_id 正常即是 server_uuid,在第一次启动时生成(函数 generate_server_uuid),并持久化到 DATADIR/auto.cnf 文件里。

transaction_id 是顺序化的序列号(sequence number),在每台 MySQL 服务器上都是从 1 开始自增长的序列,是事务的唯一标识。

GTID 生成

GTID 的生成受 gtid_next 控制。

在 Master 上,gtid_next 是默认的 AUTOMATIC,即 GTID 在每次事务提交时自动生成。它从当前已执行的 GTID 集合(即 gtid_executed)中,找一个大于 0 的未使用的最小值作为下个事务 GTID。在实际的更新事务记录之前将 GTID 写入到 Binlog。

在 Slave 上,从 Binlog 先读取到主库的 GTID(即 set gtid_next 记录),而后执行的事务采用该 GTID。

GTID 的好处
  1. GTID 使用 master_auto_position=1 代替了 Binlog 的主从复制方案,相比 Binlog 方式更容易搭建主从复制。
  2. GTID 方便实现主从之间的 failover(主从切换),不用一步一步的去定位 Binlog日志文件和查找 Binlog 的位点信息。
GTID 模式复制局限性
  1. 在一个事务里面混合使用引擎,如 Innodb(支持事务)、MyISAM(不支持事务), 造成多个 GTIDs 和同一个事务相关联出错。

  2. CREATE TABLE…..SELECT 不能使用,该语句产生的两个 Event。 在某一情况会使用同一个 GTID(同一个 GTID 在 slave 只能被使用一次):

  • event one:创建表语句 create table
  • event two :插入数据语句 insert
  1. CREATE TEMPORARY TABLE and DROP TEMPORARY TABLE 不能在事务内使用 (启用了 –enforce-gtid-consistency 参数)。

  2. 使用 GTID 复制从库跳过错误时,不支持 sql_slave_skip_counter 参数的语法。

GTID 主从复制实战

1.Master 主数据库上的操作

在 my.cnf 文件中配置 GTID 主从复制

[root@mysql-master ~]# cp /etc/my.cnf /etc/my.cnf.bak
[root@mysql-master ~]# >/etc/my.cnf
[root@mysql-master ~]# cat /etc/my.cnf
[mysqld]
datadir = /var/lib/mysql
socket = /var/lib/mysql/mysql.sock

symbolic-links = 0

log-error = /var/log/mysqld.log
pid-file = /var/run/mysqld/mysqld.pid

#GTID:
server_id = 1
gtid_mode = on
enforce_gtid_consistency = on

#binlog
log_bin = mysql-bin
log-slave-updates = 1
binlog_format = row
sync-master-info = 1
sync_binlog = 1

#relay log
skip_slave_start = 1

配置后,重启 MySQL 服务:

[root@mysql-master ~]# systemctl restart mysqld

登录 MySQL,并查看 Master 状态, 发现多了一项 Executed_Gtid_Set

mysql> show master status;
±------------------±---------±-------------±-----------------±------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
±------------------±---------±-------------±-----------------±------------------+
| mysql-bin.000001 | 154 | | | |
±------------------±---------±-------------±-----------------±------------------+
1 row in set (0.00 sec)

mysql> show global variables like ‘%uuid%’;
±--------------±-------------------------------------+
| Variable_name | Value |
±--------------±-------------------------------------+
| server_uuid | 317e2aad-1565-11e9-9c2e-005056ac6820 |
±--------------±-------------------------------------+
1 row in set (0.00 sec)

查看确认 GTID 功能打开:

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)

查看确认 Binlog 日志功能打开:

mysql> show variables like ‘log_bin’;
±--------------±------+
| Variable_name | Value |
±--------------±------+
| log_bin | ON |
±--------------±------+
1 row in set (0.00 sec)

授权 slave 复制用户,并刷新权限:

mysql> flush privileges;
Query OK, 0 rows affected (0.04 sec)

mysql> show grants for slave@‘172.23.3.66’;
±------------------------------------------------------------------------------+
| Grants for slave@172.23.3.66 |
±------------------------------------------------------------------------------+
| GRANT REPLICATION SLAVE, REPLICATION CLIENT ON . TO ‘slave’@‘172.23.3.66’ |
±------------------------------------------------------------------------------+
1 row in set (0.00 sec)

再次查看 master 状态:

mysql> show master status;
±------------------±---------±-------------±-----------------±-----------------------------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
±------------------±---------±-------------±-----------------±-----------------------------------------+
| mysql-bin.000001 | 622 | | | 317e2aad-1565-11e9-9c2e-005056ac6820:1-2 |
±------------------±---------±-------------±-----------------±-----------------------------------------+
1 row in set (0.00 sec)

这里需要注意一下:
启动配置之前,同样需要对从服务器进行初始化。对从服务器初始化的方法基本和基于日志点是相同的,只不过在启动了 GTID 模式后,在备份中所记录的就不是备份时的二进制日志文件名和偏移量了,而是记录的是备份时最后的 GTID 值。
需要先在主数据库机器上把目标库备份一下,假设这里目标库是 slave_test:

mysql> CREATE DATABASE slave_test CHARACTER SET utf8 COLLATE utf8_general_ci;
Query OK, 1 row affected (0.02 sec)

mysql> use slave_test;
Database changed
mysql> create table user (id int(10) PRIMARY KEY AUTO_INCREMENT,name varchar(50) NOT NULL);
Query OK, 0 rows affected (0.27 sec)

mysql> insert into slave_test.user values(1,“xiaoming”),(2,“xiaohong”),(3,“xiaolv”);
Query OK, 3 rows affected (0.06 sec)
Records: 3 Duplicates: 0 Warnings: 0

mysql> select * from slave_test.user;
±—±---------+
| id | name |
±—±---------+
| 1 | xiaoming |
| 2 | xiaohong |
| 3 | xiaolv |
±—±---------+
3 rows in set (0.00 sec)

把 slave_test 库备份出来:

[root@mysql-master ~]# mysqldump --single-transaction --master-data=2 --triggers --routines --databases slave_test -uroot -p123456 > /root/user.sql

这里有个版本上的问题:

MySQL 5.6 使用 mysqldump 备份时,指定备份的具体库,使用 --database

MySQL 5.7 使用 mysqldump 备份时,指定备份的具体库,使用--databases。

然后把备份的/root/user.sql 文件拷贝到 slave 从数据库服务器上。

[root@mysql-master ~]# rsync -e “ssh -p20” -avpgolr /root/user.sql

到这里主库的操作结束,包含 GTID 的备份数据已经 copy 到从库,下面来进行从库的操作。

2.从库操作

在 my.cnf 文件中配置 GTID 主从复制

与主服务器配置大概一致,除了 server_id 不一致外,从服务器还可以在配置文件里面添加read_only=on ,使从服务器只能进行读取操作,此参数对超级用户无效,并且不会影响从服务器的复制。

[root@mysql-slave1 ~]# >/etc/my.cnf
[root@mysql-slave1 ~]# vim /etc/my.cnf
[mysqld]
datadir = /var/lib/mysql
socket = /var/lib/mysql/mysql.sock

symbolic-links = 0

log-error = /var/log/mysqld.log
pid-file = /var/run/mysqld/mysqld.pid

#GTID:
server_id = 2
gtid_mode = on
enforce_gtid_consistency = on

#binlog
log_bin = mysql-bin
log-slave-updates = 1
binlog_format = row
sync-master-info = 1
sync_binlog = 1

#relay log
skip_slave_start = 1
read_only = on

配置完成后,重启mysql服务。

[root@mysql-slave1 ~]# systemctl restart mysql

接着将主数据库目标库的备份数据 user.sql导入到从数据库里。

[root@mysql-slave1 ~]# ls /root/user.sql
/root/user.sql
[root@mysql-slave1 ~]# mysql -p123456

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

mysql> source /root/user.sql;

mysql> select * from slave.test;
±—±---------+
| id | name |
±—±---------+
| 1 | xiaoming |
| 2 | xiaohong |
| 3 | xiaolv |
±—±---------+
3 rows in set (0.00 sec)

在从数据库里,使用 change master 配置主从复制:

mysql> stop slave;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> change master to master_host=‘172.23.3.66’,master_user=‘slave1’,master_password=‘123456’,master_auto_position=1;
Query OK, 0 rows affected, 2 warnings (0.26 sec)

mysql> start slave;
Query OK, 0 rows affected (0.02 sec)

mysql> show slave status \G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 172.23.3.66
Master_User: slave1
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000001
Read_Master_Log_Pos: 1357
Relay_Log_File: mysql-slave1-relay-bin.000002
Relay_Log_Pos: 417
Relay_Master_Log_File: mysql-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes


Executed_Gtid_Set: 317e2aad-1565-11e9-9c2e-005056ac6820:1-5
Auto_Position: 1

由此,Master 和 Slave 节点已经配置了主从同步关系。接下来你可以自行在主库插入一条数据观察从库是否同步过来。

使用 GTID 添加从库有两种方式

直接同步主库所有GTID

如果主库一开始就开启了 GTID,那么可以直接获取主库的所有GTID来同步至从库。但是如果主库 Binlog 日志太多,那么相应同步的时间也会变长。这种方式适用于小数据量的同步。

使用这种方式来同步相应的命令为:

mysql>change master to master_host=‘xxxxxxx’,master_user=‘xxxxxx’,master_password=‘xxxxx’,MASTER_AUTO_POSITION=1;
mysql> start slave;
mysql> stop slave io_thread; #重启 io 线程,刷新状态
mysql> start slave io_thread;

当使用 MASTER_AUTO_POSITION 参数的时候,MASTER_LOG_FILEMASTER_LOG_POS 参数不能使用。
如果想要从 GTID 配置回 pos,再次执行这条语句,不过把 MASTER_AUTO_POSITION 置为 0。

通过设定范围进行同步

通过指定 GTID 的范围,然后通过在 slave 设置 @@GLOBAL.GTID_PURGED 从而跳过备份包含的 GTID 。

这种方案适用于数据量比较大一次同步需要耗费巨量时间的数据。但同时也有操作复杂的问题,需要你记住每次同步的范围。

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

1200页Java架构面试专题及答案

小编整理不易,对这份1200页Java架构面试专题及答案感兴趣劳烦帮忙转发/点赞

百度、字节、美团等大厂常见面试题

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!
3032d36.jpg" alt=“img” style=“zoom: 33%;” />

1200页Java架构面试专题及答案

小编整理不易,对这份1200页Java架构面试专题及答案感兴趣劳烦帮忙转发/点赞

[外链图片转存中…(img-ECUHiiDn-1712444199315)]

[外链图片转存中…(img-J8GPQn7Q-1712444199315)]

百度、字节、美团等大厂常见面试题

[外链图片转存中…(img-OGqin5dd-1712444199315)]

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门即可获取!

  • 15
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值