MySQL高级(三)复制架构、主从复制

第七章 MySQL复制架构

第一节 概述

1.1 数据拓展

  • 热备份:数据库在运行的过程中,对数据进行备份操作。相对的,还有冷备份,冷备份需要停机,然后对数据进行备份操作。
  • 多活:所谓的多活,就是让数据库机器节点会存在多个,避免单点情况的出现。
  • 故障切换:当一台数据库物理机出现异常状况时,可以自动的切换到其他物理机上。
  • 读写分离:当存在多台数据库物理机,将读写操作分别交给不同的机器完成。
  • 负载均衡:假设当存在多台数据库物理机接收读请求时,多个请求会均匀的分配到不同的机器上,避免大量请求压在某一台机器上。

1.2 常见架构

没有百分百的完美架构,只有适合的架构

理解mysql的分库分表,先了解mysql的架构设计,在mysql架构中,经常会使用到的就是读写分离,此设计理念的基础上常见架构有: 一主一从或多从、主主复制、级联复制、主主与级联复制结合。

一主一从或多从: 一个mysql数据库主节点,一个或者多个从节点.主节点与从节点进行数据同步

主主复制: 两个mysql主节点,主节点与主节点之间进行数据同步

级联复制: 类似一主多从架构,但是从节点分级同步

主主与级联复制结合: 双主节点同步,同时从节点分级同步

第二节 主从模式

1、主从简介

主从模式是使用的最多的MySQL高可用架构。

存在一台master作为写机,一个或多个slave作为读机,实现读写分离。之所以这么设计是因为在实际的情况下,读的请求量一般是远远大于写请求。架构图如下

img

优点:

读与写的节点分离,数据写入master节点后,再由master节点将数据复制到slave节点上

缺点:

  • master是单点存在的,如果要对master进行停机维护,无法接收写请求
  • master需要将写入数据复制到各个slave节点,复制是有一定的时间延迟的,因此有可能出现查询数据不一致
  • 对master进行停机维护,需将某一个slave提升为新的master节点,选举规则需要进行自定义
  • 当slave被提升为新的master后,可能会造成新的master节点与旧master的数据不一致

2、 主从搭建

①创建 docker 容器
# 搜索 MySQL 镜像
docker search mysql

# 下载 MySQL 镜像
docker pull docker.io/mysql:5.7

# 安装 MySQL 容器
# 服务一
# -p 参数格式:宿主机端口号:容器内程序的端口号
# -e MYSQL_ROOT_PASSWORD 给 MySQL 的 root 用户设置密码
# -v 参数指定宿主机内的目录,用来给 docker 容器设定配置文件等等
docker run --name mysqlm1 
-p 10000:3306 
--privileged=true 
-it 
-e MYSQL_ROOT_PASSWORD=123456 
-e MYSQL_USER=user
-e MYSQL_PASSWORD=pass 
-v /lyruse/mysqlm1/conf:/etc/mysql/conf.d 
-v /lyruse/mysqlm1/data/:/var/lib/mysql 
-v /lyruse/mysqlm1/logs/:/var/log/mysql 
-d mysql:5.7

#服务二
docker run --name mysqls1 
-p 20000:3306 
--privileged=true 
-it 
-e MYSQL_ROOT_PASSWORD=123456 
-e MYSQL_USER=user  
-e MYSQL_PASSWORD=pass 
-v /lyruse/mysqls1/conf:/etc/mysql/conf.d 
-v /lyruse/mysqls1/data/:/var/lib/mysql 
-v /lyruse/mysqls1/logs/:/var/log/mysql 
-d mysql:5.7

img

②配置 docker 容器

在两台机器上新增配置文件

[1]主机

由于我们映射了目录,所以在宿主机中编辑配置文件即可。my.cnf 这个配置文件原本没有,需要我们自己手动创建。

宿主机中的路径为 /lyruse/mysqlm1/conf/my.cnf

# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html

[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M

character_set_server=utf8
init_connect='SET NAMES utf8'

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

lower_case_table_names=1
#指定主机号,不允许出现重复
server-id=134
#开启binlog
log-bin=mysql-bin
auto_increment_increment=2
auto_increment_offset=1

#rpl_semi_sync_master_enabled=1
#rpl_semi_sync_master_timeout=10000
[2]从机

/lyruse/mysqls1/conf/my.cnf

# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html

[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M

character_set_server=utf8
init_connect='SET NAMES utf8'

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

lower_case_table_names=1
#指定主机号,不允许出现重复
server-id=130
#开启binlog
log-bin=mysql-bin
auto_increment_increment=2
auto_increment_offset=1

#rpl_semi_sync_master_enabled=1
#rpl_semi_sync_master_timeout=10000

❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤

修改 my.cnf 后记得重启 MySQL 容器!否则配置不会生效!

[root@demo conf]# docker restart mysqlm1
mysqlm1
[root@demo conf]# docker restart mysqls1
mysqls1

❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤

③配置 master

在master的docker容器中添加MySQL权限,开启备份机复制,并且设置备份用户信息

#在134服务中进入 MySQL 容器
docker exec -it mysqlm1 /bin/bash

#登录到 MySQL
mysql -u root -p
EnterPassword:123456

#==================== 在 MySQL 中的操作 ===========================
#添加权限
GRANT REPLICATION SLAVE,FILE,REPLICATION CLIENT ON *.* TO 'repluser'@'%' IDENTIFIED BY '123456';

#刷新权限
FLUSH PRIVILEGES;

#退出MySQL
quit;
#================================================================

#退出docker容器
exit

#重启容器
docker restart mysqlm1

#查看m1的binlog信息(需要进入 docker 容器,然后再登录 MySQL 执行)
show master status;

img

④配置 slave

在slave中进入到MySQL容器,设置master信息,用于标注当前slave的master是谁

img

#语法
change master to master_host='通过宿主机访问master的ip',master_port=docker对外暴露的宿主机master的端口号,master_user='repluser',master_password='123456',master_log_file='master中的binlob文件',master_log_pos=master中的position位置信息;
#命令
change master to master_host='192.168.119.129',master_port=10000,master_user='repluser',master_password='123456',master_log_file='mysql-bin.000002',master_log_pos=154;

img

完成后,还需要开启slave中的IOSQL线程,这两个线程主要用于slave中进行数据备份。

  • IO 线程:从日志文件中读取数据,其中最关键的就是用来同步数据的 SQL 语句
  • SQL 线程:执行从日志文件中读取到的 SQL 语句

可以先查看slave中这两个线程的状态

show slave status\G;

img

我们发现在slave中,这两个线程是关闭的,需要将这两个线程进行开启

#开启(在 docker容器中登录 MySQL 后执行)
start slave;

img

到此,mysql主从复制就已经搭建完毕

⑤测试
[1]查看主从相关信息

查看slave中的binlog是否已经开启

show global variables like "%log%";

img

查看master、slave中的进程信息

# m1和s1分别输入
show processlist;

m1节点内容

img

s1节点内容

img

[2]数据库同步测试

在m1节点创建一个数据库

img

在s1节点中查看数据库

img

[3]表同步测试

在m1中创建一张表

DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(50) DEFAULT NULL,
`password` varchar(50) DEFAULT NULL,
`address` varchar(50) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;

img

在s1中查看表

[4]数据同步测试

在m1中新增一条数据

INSERT INTO `t_user` VALUES ('1', 'zhangsan', '123', '北京');

在s1中查看数据

[5]反向同步数据

在s1中新增一条数据

INSERT INTO `t_user` VALUES ('2', 'lisi', '123', '上海');

img

在m1中查看数据

img

结论:从服务中新增数据无法同步到主服务中去,主从同步是单向的!

[6]数据修复

如果因为各种原因,发现 slave 中的数据和 master中不一致,可以参考下面的步骤恢复(下面的步骤相当于在 slave 中推倒重来):

  • 停止 slave 相关复制线程

    stop slave;

  • 删除 slave 中同步过来的数据库

    drop database db_hr;

  • 重新设定主从关系

    change master to master_host=‘192.168.119.129’,master_port=10000,master_user=‘repluser’,master_password=‘123456’,master_log_file=‘mysql-bin.000002’,master_log_pos=154;

  • 重新启动 slave 中的相关复制线程

    start slave;

3、主从复制原理

  • 异步操作:不需要等待
  • 同步操作:需要等待
①异步复制
[1]流程
  • 在主服务器写操作举例:insert 语句。
  • 事务提交到master,master确认修改已保存。
  • master接收到应用事务提交请求后,更新内部的binlog日志,让mysql引擎执行事务操作,并返回给客户端执行结果信息。同时在master中会存在一个事件监听,其会一直监听着master中binlog日志文件的改变,一旦发现日志文件发生改变,触发dump线程
  • dump线程被触发后,通知slave中的IO线程:现在有事务操作要进行同步
  • slave中IO线程接收到通知后,会从slave中relay-log.info文件中获取slave中的binlog日志文件和pos位置信息。接着会把这部分信息发送给master的dump线程。发送信息的含义是:告诉master,我上次读取到了哪里,这次还从上次读取到的位置继续读取。
  • master的dump线程收到这些信息后,会根据slave发送的binlog日志文件和pos位置,将最新的binlog日志和pos位置后面的内容同步给slave的IO线程
  • slave的IO线程接收到这些信息后,会将这部分内容同步到slave中的relay-bin文件中
  • 当relay-bin文件发生改变后,触发slave线程执行sql操作【异步】
  • 当slave向relay-bin写入完成后,会向master返回一个ACK消息,同步成功。
  • 对于这一系列的操作,可以发现master和slave在进行同步时是以异步的方式完成的,master写入完binlog后,会马上通过引擎进行事务提交并向客户端返回响应,对于与slave同步的操作,则是异步完成的。
[2]评价
  • 优点
    • 效率高
  • 缺点
    • 可能出现数据不一致
②半同步复制
[1]简介

img

半同步复制与异步复制的工作流程大体相似

不同点:当master中的binlog日志写入完成后,其不会马上通过引擎进行事务提交,而会处于等待,等到slave同步完成向master返回ACK通知后,才会唤醒等待,继续向下执行。

等待的时长,默认为10秒,但该时间可以配置。尽量的避免了主从数据不一致,但造成吞吐量的降低。

兜底方案:使用半同步复制进行备份时slave节点挂掉了,那么当master等待10秒后,仍然会进行引擎提交,同时会将半同步复制切换为异步复制。等到slave节点重启后,又会自动的从异步复制切换到半同步复制。

[2]搭建

进入MySQL容器,加载lib,主从节点都要配置,因为主从节点间会存在切换。

# 这两条 install 命令需要在 m1 中都执行一遍,然后在 s1 中也都执行一遍
install plugin rpl_semi_sync_master soname 'semisync_master.so';
install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
#查看插件信息
show plugins;

img

启动半同步:

#先启用从库,再启用主库

从库:set global rpl_semi_sync_slave_enabled= 1;   # 1:启用,0:禁止

主库:
     set global rpl_semi_sync_master_enabled= 1;   # 1:启用,0:禁止
     set global rpl_semi_sync_master_timeout=10000;   # 单位为ms

从库重启IO Thread

stop slave io_thread;
start slave io_thread;

主库查看启动状态

#查询状态信息
show global status like "%sync%";

img

#查询参数信息
show global variables like '%sync%';

img

半同步复制效果测试

  • 正常的向master中添加数据,slave可以进行正常数据更新

  • 关闭slave的IO,再次向master中添加数据

# 从库执行操作:关闭 I/O 线程
stop slave io_thread;

# 主库插入数据
INSERT INTO `t_user` VALUES ('3', 'ding', '111', '武汉');

此时复制机制会由半同步复制转换为异步复制,当再次向master中添加数据,不会再次出现等待

  • slave中重新开启IO Thread
start slave io_thread;

异步复制会再次转换为半同步复制,可以查看master中打印日志信息:

在slave IO Tthread关闭这段时间内的数据,会同步到slave中,不会出现数据丢失

img

第三节 主主复制

1、简介

对于主从复制来说,其内部会存在一台master以及一台或多台slave。但有一个非常明显的问题,master是单点存在。一旦master宕机,则无法进行数据的写入。为了解决这个问题,可以使用主主复制架构。

主主复制架构两个实例互为主从。并进行读写分离,架构图如下:

img

在此架构中,两台master会进行双向复制,为什么这么做呢? 因为假设现在负责写的master宕机了,那么写的工作则会交给之前负责读的服务器来完成,相当于它即负责写又负责读。等到原先负责写的master恢复了,其在继续负责写工作。 反之亦然。因此才需要两者间进行双向复制。

缺点: 读请求的并发量过大,服务可能产生宕机, 主主复制架构直接使用的情况较少。

2、主主搭建

①创建容器
docker run --name mysqlm2 -p 30000:3306 --privileged=true -it -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_USER=user  -e MYSQL_PASSWORD=pass -v /lyruse/mysqlm2/conf:/etc/mysql/conf.d -v /lyruse/mysqlm2/data/:/var/lib/mysql -v /lyruse/mysqlm2/logs/:/var/log/mysql -d mysql:5.7

docker run --name mysqlm3 -p 40000:3306 --privileged=true -it -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_USER=user  -e MYSQL_PASSWORD=pass -v /lyruse/mysqlm3/conf:/etc/mysql/conf.d -v /lyruse/mysqlm3/data/:/var/lib/mysql -v /lyruse/mysqlm3/logs/:/var/log/mysql -d mysql:5.7
②配置

/lyruse/mysqlm2/conf/my.cnf

# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html

[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M

character_set_server=utf8
init_connect='SET NAMES utf8'

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

lower_case_table_names=1
#指定主机号,不允许出现重复
server-id=1341
#开启binlog
log-bin=mysql-bin
auto_increment_increment=2
auto_increment_offset=1

#rpl_semi_sync_master_enabled=1
#rpl_semi_sync_master_timeout=10000

/lyruse/mysqlm3/conf/my.cnf

# For advice on how to change settings please see
# http://dev.mysql.com/doc/refman/5.7/en/server-configuration-defaults.html

[mysqld]
#
# Remove leading # and set to the amount of RAM for the most important data
# cache in MySQL. Start at 70% of total RAM for dedicated server, else 10%.
# innodb_buffer_pool_size = 128M
#
# Remove leading # to turn on a very important data integrity option: logging
# changes to the binary log between backups.
# log_bin
#
# Remove leading # to set options mainly useful for reporting servers.
# The server defaults are faster for transactions and fast SELECTs.
# Adjust sizes as needed, experiment to find the optimal values.
# join_buffer_size = 128M
# sort_buffer_size = 2M
# read_rnd_buffer_size = 2M

character_set_server=utf8
init_connect='SET NAMES utf8'

# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0

lower_case_table_names=1
#指定主机号,不允许出现重复
server-id=666
#开启binlog
log-bin=mysql-bin
auto_increment_increment=2
auto_increment_offset=1

#rpl_semi_sync_master_enabled=1
#rpl_semi_sync_master_timeout=10000

❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤

修改 my.cnf 后记得重启 MySQL 容器!

❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤❤

添加slave的相关配置, 虽然是主主模式,也要添加从用户(供从机访问的用户)。由于 m2 和 m3 都有可能作为从机访问对方(此时对方是主机),所以在 m2 和 m3 都需要创建 repluser 用户。

#添加权限
GRANT REPLICATION SLAVE,FILE,REPLICATION CLIENT ON *.* TO 'repluser'@'%' IDENTIFIED BY '123456';
#刷新权限
FLUSH PRIVILEGES;

#在m2/m3服务器上运行
show master status;

#执行主主关联(参考 m2 的状态设置 m3;参考 m3 的状态设置 m2)
#设置m2。因为m2要去连m3,所以这里要设置m3的IP地址和端口号。
change master to master_host='192.168.119.129',master_port=40000,master_user='repluser',master_password='123456',master_log_file='mysql-bin.000001',master_log_pos=629;

#设置m3。因为m3要去连m2,所以这里要设置m2的IP地址和端口号。
change master to master_host='192.168.119.129',master_port=30000,master_user='repluser',master_password='123456',master_log_file='mysql-bin.000001',master_log_pos=629;

#主主同步生效:也就是说m2和m3都需要执行
start slave;

查看master 129的进程列表:show processlist;

img

slave131的进程列表:show processlist;

img

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值