欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

程序员文章站 2022-03-26 15:02:37
一、MySQL集群①高可用:主主同步②可并发:主从同步(读写分离)、分库分表③自动扩容:部署机器好扩展二、分库分表分表将数据分为多个表存储进行,解决查询速度慢的问题分库将数据分为多个数据库进行存储,解决高并发插入多数据的问题分库分表将上面两者结合在一起三、MySQL复制MySQL的复制在另一篇也介绍过,可以参阅:https://blog.csdn.net/qq_41453285/article/details/104381494概念:MyS...

一、MySQL集群

  • ①高可用:主主同步
  • ②可并发:主从同步(读写分离)、分库分表
  • ③自动扩容:部署机器好扩展

二、分库分表

分表

  • 将数据分为多个表存储进行,解决查询速度慢的问题

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

分库

  • 将数据分为多个数据库进行存储,解决高并发插入多数据的问题

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

分库分表

  • 将上面两者结合在一起

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

三、MySQL复制

  • MySQL的复制在另一篇也介绍过,可以参阅:https://blog.csdn.net/qq_41453285/article/details/104381494
  • 概念:MySQL内建的复制功能是构建大型,高性能应用程序的基础。将MySQL的数据分布到多个系统上去,这种分布的机制,是通过将mysql的某一台主机的数据复制到其它主机(slave)上,并重新执行一遍来实现。复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器。主服务器将更新写入二进制日志文件,并维护文件的一个索引以跟踪日志循坏,这些日志可以记录发送到从服务器的更新。当一个从服务器连接主服务器时,它通知主服务器从服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那时起发生的任何更新,然后*并等待主服务器通知的更新

MySQL复制解决的问题

  • 数据分布(data distribution)
  • 负载平衡(load balancing)
  • 数据备份(backup),保证数据安全
  • 高可用性与容错行(high availability and failover)
  • 实现读写分离,缓解数据库压力

MySQL复制数据的方式

  • binlog_format选项:配置文件的binlog_format选项决定了MySQL复制数据时基于什么方式

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

  • MySQL目前支持三种方式:
    • 基于SQL语句的复制(statement-based replication, SBR)
    • 基于行的复制(row-based replication,RBR)
    • 混合类型的复制(mixed-based replication,MBR)
  • 详情可以参阅https://blog.csdn.net/qq_41453285/article/details/104110026中对binlog的介绍

MySQL复制的流程

  • 如下图所示:
    • ①master记录二进制日志:在每个事务更新数据完成之前,master在二进制日志(Binary log)记录这些改变。MySQL将事务串行的写入二进制日志,即使事务中的语句都是交叉执行的。在事件写入二进制日志完成后,master通知存储引擎提交事务
    • ②slave将master的Binary log拷贝到它自己的中继日志:slave开始一个工作线程——I/O线程。I/O线程在master上打开一个普通的连接,然后开始binlog dump process。Binlog dump process从master的二进制日志中读取事件,I/O线程将这些事件写入自己的中继日志(Relay log)
    • ③SQL线程处理该过程的最后一步:SQL线程从中继日志读取事件,并重放其中的事件而更新slave的数据,使其与master中的数据一致。只要该线程与I/O线程保持一致,中继日志通常会位于OS的缓存中,所以中继日志的开销很小

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

  • 此外,在master中也有一个工作线程:和其它MySQL的连接一样,slave在master中打开一个连接也会使得master开始一个线程。复制过程有一个很重要的限制——复制在slave上是串行化的,也就是说master上的并行更新操作不能在slave上并行操作

MySQL复制的模式

  • 主从复制:主库授权从库远程连接,读取binlog日志并更新到本地数据库的过程;主库写数据后,从库会自动同步过来(从库跟着主库变)
  • 主主复制:主从相互授权连接,读取对方binlog日志并更新到本地数据库的过程;只要对方数据改变,自己就跟着改变

四、主从复制

  • 主从复制的优点:
    • 主库写,从库读,降压:在从服务器可以执行查询工作(即我们常说的读功能),降低主服务器压力
    • 确保数据安全:在从主服务器进行备份,避免备份期间影响主服务器服务
    • 提升性能:当主服务器出现问题时,可以切换到从服务器

第一步(环境介绍)

  • 下面开始介绍主从复制,其中:
    • 111.229.177.161:我的一台云服务器,作为主机(Master)
    • 192.168.0.103:我的一台虚拟机,作为从机(Slave)
  • 两台主机的MySQL版本都是5.7
mysql --version

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

  • 查看Master的数据库,其有一个test数据库,数据库内有一个student表
show databases;

use test;

show tables;

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

  • 下面我们就将Master端的这个test数据库同步到Slave端

第二步(设置Master端配置文件)

  • 第一步(Master):设置master的数据库配置文件
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
  • 修改的内容有:
    • server-id:Master服务ID(此处我以IP地址的最后3位表示,随意你如何更改,但是不要与其他主机的server-id重复)
    • log-bin:开启binlog,并指定binlog的存储位置
    • binlog-do-db:binlog同步的数据库,此处我们设置为test,也就是binlog中只记录test数据库的信息(可选项)
    • binlog-ignore-db:不同步哪些数据库,此处我们设置为mysql(可选项)

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

  • 还有其他很多参数,例如:
    • sync_binlog:默认值为0表示每执行一个事务就将binlog的内容同步到磁盘(可选项)
    • binlog_checknum:跳过现有的采用checksum的事件,mysql5.6.5以后的版本中binlog_checksum=crc32,而低版本都是binlog_checksum=none(可选项)
    • binlog_format:bin-log日志文件格式,设置为MIXED可以防止主键重复(可选项)
    • 关于这些参数就不详细介绍了,详细介绍可以参阅:https://blog.csdn.net/qq_41453285/article/details/104110026
  • 第二步(Master):之后重启数据库
sudo service mysql restart

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

第三步(Master创建新用户)

  • 下面我们在Master上创建一个用户,做复制来用,因为Slave复制时需要制定用户
  • 第一步(Master):在Master上创建一个名为replication的用户,密码为123456
# 创建用户
create user replication@'%' identified by '123456';

# 授权replication用户所有权限, 并且任何地址(%)登录的replication都可以使用
# 如何要指定IP地址才可以使用这个权限,可以把%改为指定的IP
grant all privileges on *.* to replication@'%' identified by '123456' with grant option;

# 刷新权限
flush privileges;

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

  • 备注:
    • 上面我们授予了replication用户所有权限
    • 如果我们只想授予replication复制的权限,可以将上面的grant命令设置为下面的格式,将all privileges改为“relication slave,relication client”即可
    • 下面我们“主主演示案例”中就是用下面的格式演示
    • 关于授权详情可以参阅:https://blog.csdn.net/qq_41453285/article/details/104055973
grant replication slave,replication client on *.* to replication@'%' identified by '123456' with grant option;
  • 第二步(Master):查看授权
show grants;

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

第四步(复制前的准备工作)

  • 说明:
    • 因为Master端的test数据库中有数据,而Slave端没有,如果直接进行复制,那么Master与Slave的数据就会不一致,因此为了保持数据一致,我们先将Master中的数据导出来,然后导入Slave中,之后再进行测试
    • 如果是新建的数据库,那么可以不进行这一步(根据你的实际需求进行)
  • 第一步(Master):输入下面的锁定Master数据库,放置在备份数据的时候有新写入数据(这一步是可选的,你也可以不做这一步,此处我们为了好玩锁定罢了,下面我们需要调用unlock tables解锁)
flush tables with read lock;

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

  • 第二步(Master):重新开启一个Master的命令行,备份test数据库,保存到当前目录下,名为test_backup.sql
mysqldump -uroot -p --databases test > ./test_backup.sql

ls ./test_backup.sql

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

  • 先不解锁Master数据库,等下复制流程建立完成之后再解锁数据库
  • 第三步(Slave):将Master端导出的那个test_backup.sql上传到Slave端,然后在进入Slave端数据库创建一个test数据库,再导入刚才那个test_backup.sql
# 先创建数据库, 要不然下面导入的时候会出错
create database test;

# 导入数据库文件
source ./test_backup.sql

show databases;

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

第五步(设置Slave端配置文件)

  • 第一步(Slave):设置slave的数据库配置文件
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
  • 修改的内容有:
    • bind-address:因为我这个数据库是新安装的,所以把bin-address注释掉
    • server-id:Slave服务ID(此处我以IP地址的最后3位表示,随意你如何更改,但是不要与其他主机的server-id重复)
    • log-bin:开启binlog,并指定binlog的存储位置
    • replicate-do-db:指定要同步哪些数据库,此处我们设置为test(可选的。可以指定多个数据库;如果忽略这个参数,那么就复制所有数据库,除replication-ignore-db指定的除外)
    • replicate-ignore-db:忽略复制哪些数据库(可选的)

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

  • 备注:如果只想针对数据库的某些表进行复制同步,那么可以使用replicate-wild-do-table指定。例如:
# 对test1数据库进行复制
relicate-do-db = test1
# 只对test1数据库的student表进行复制
replicate-wild-do-table = test1.student;

# 对test2数据库进行复制
relicate-do-db = test2
# 只对test2数据库的student表进行复制
replicate-wild-do-table = test2.student;
  • 第二步(Slave):重启MySQL
# 不知道为啥我那台机器没有restart, 所以只能用下面的方式重启了
sudo service mysql stop

sudo service mysql start

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

第六步(开始复制)

  • 第一步(Master):Master端数据库输入下面的命令,查看当前使用的binlog文件名字是什么,并且当且写入的索引为多少。可以看到分别为“mysql-bin.000002”和“154”
show master status;

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

  • 第二步(Slave):Slave进入数据库,输入下面的命令请求复制Master端,各个参数意义如下:
    • master_host:要复制的数据库主机的地址
    • master_user:复制操作中指定的用户,就是我们上面在Master中创建的replication
    • master_password:用户的密码
    • master_log_file:要复制的Master的binlog文件名,就是上面我们在Master中看到的mysql-bin.000002(一定要与上面的一直,否则命令出错)
    • master_log_pos:对应的SQL执行的偏移位置,就是上面我们在Master中看到的154(一定要与上面的保持一致,否则命令出错)
stop slave;

change master to master_host='111.229.177.161',master_user='replication',master_password='123456',master_log_file='mysql-bin.000002',master_log_pos=154;

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

  • 第三步(Slave):输入下面的命令开始同步
start slave;

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

  • 第四步(Slave):然后查看Slave端的状态
show slave status\G

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

  • 第五步(Master):因为在上面的“第四步”中我们锁定了Master不可以写入数据,只可以读,现在我们复制配置好了,因此来到Master端,输入下面的命令解锁数据库
unlock tables;

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

第七步(测试)

  • 第一步(Master、Slave):上面我们已经复制已经配置好了,在开始向Master写入数据之前,查看一下两者的数据是否一致,结果一致
use test;

select * from student;

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

  • 第二步(Master):来到Master中,删除id为2的那一条数据,然后新增一条数据
delete from student where id =2;

insert into student values(4,'Python', 20);

select * from student;

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

  • 第三步(Slave):来到Slave端,可以看到也接收到了这个数据,说明复制成功

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

第八步(停止复制)

  • 第一步(Slave):输入下面的命令停止复制,然后查看状态,可以看到两个线程都停止工作了
stop slave;

show slave status\G

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

  • 第二步(Master):现在我们来到Master端,删除id为3的数据
delete from student where id=3;

select * from student;

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

  • 第三步(Slave):来到Slave端查看,发现数据并没有删除,因为早已经断开复制关系了

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

五、主主复制

  • 主主复制解决的问题与应用场景:
    • 根据主从复制的原理我们知道,一般来说Master执行写入操作,Slave只执行读操作,但是如果Slave执行了写操作,那么就会造成Master与Slave的数据不一致
    • 主主复制就是两台主机之前一起同步数据,两台机器上的数据都可以保持一直

主主复制中的“自增长重复”问题

  • 因为两台机器之间可以互相写入数据,因此可能会出现自增长重复问题
  • 场景分析:
    • 有一个test表,其有一个ID字段为auto_increment类型
    • 停掉A机器,B在ID字段上插入一条数据,导致ID加1
    • 停掉B机器,A在ID字段上插入一条数据,导致ID也加1
    • 然后同时启动A和B,发现主键ID重复,因此报错
  • 解决方法:
    • MySQL提供了两个配置文件选项,一个为auto_increment_offset,另一个为auto_increment_increment
      • auto_increment_offset:表示自增长字段的值从多少开始
      • auto_increment_increment:自增长字段每次递增的值
    • 因此,我们可以在A和B两台机器中这样配置选项,从而导致不会出现“自增长重复问题”,例如:
      • 在A中将auto_increment_offset设置为1、将auto_increment_increment设置为2。这样的话,其自增长值就为1、3、5......以此类推
      • 在B中将auto_increment_offset设置为2、将auto_increment_increment设置为2。这样的话,其自增长值就为2、4、6......以此类推
# A中的配置
auto_increment_offset = 1
auto_increment_increment = 2

# B中的配置
auto_increment_offset = 2
auto_increment_increment = 2
  • 下面开始主主复制实战演示

第一步(环境介绍)

  • 现在我们有两台机器:
    • 192.168.0.101(就当做是Master吧)
    • 192.168.0.102(就当做是Slave吧)
  • 两台主机的MySQL版本都是5.7
mysql --version

架构师进阶:04---集群专题之(MySQL集群:主从复制、主主复制)

第二步(配置Master的配置文件)

  • 修改MySQL配置文件
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
  •  修改的内容有:
    • server-id:Master服务ID(此处我以IP地址的最后3位表示,随意你如何更改,但是不要与其他主机的server-id重复)
    • log-bin:开启binlog,并指定binlog的存储位置
    • binlog-ignore-db:不同步哪些数据库,此处我们设置为mysql(可选项)
    • 此处我们没有设置binlog-do-db参数,表示复制所有数据库
    • auto-increment-offset:在上面介绍过了,此处从1开始
    • auto-increment-increment:在上面介绍过了
server-id = 101
log-bin = /var/log/mysql/mysql-bin.log
log-ignore-db= mysql, information_schema
auto-increment-increment = 2
auto-increment-offset = 1
  • 修改的内容有:配置完成之后重启服务器
sudo service mysql restart

 

第三步(配置Slave的配置文件)

  • 修改MySQL配置文件
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
  • 修改的内容有:
    • server-id:Master服务ID(此处我以IP地址的最后3位表示,随意你如何更改,但是不要与其他主机的server-id重复)
    • log-bin:开启binlog,并指定binlog的存储位置
    • binlog-ignore-db:不同步哪些数据库,此处我们设置为mysql(可选项)
    • 此处我们没有设置binlog-do-db参数,表示复制所有数据库
    • auto-increment-offset:在上面介绍过了,此处从2开始
    • auto-increment-increment:在上面介绍过了
server-id = 102
log-bin = /var/log/mysql/mysql-bin.log
log-ignore-db= mysql, information_schema
auto-increment-increment = 2
auto-increment-offset = 2
  • 修改的内容有:配置完成之后重启服务器
sudo service mysql restart

第四步(在Master上创建用户并授权)

  • 下面我们在Master上创建一个新用户,名为repl,密码为123456,用来做复制使用
# 创建用户
create user repl@'%' identified by '123456';

# 为repl用户授予relication slave,relication client两个权限
grant relication slave,relication client on *.* to repl@'%' identified by '123456' with grant option;

# 刷新权限
flush privileges;
  • 输入下面的命令查看权限表
show grant;

第五步(在Slave上创建用户并授权)

  • 与上面一样的,下面我们在Slave上创建一个新用户,名为repl,密码为123456,用来做复制使用
# 创建用户
create user repl@'%' identified by '123456';

# 为repl用户授予relication slave,relication client两个权限
grant relication slave,relication client on *.* to repl@'%' identified by '123456' with grant option;

# 刷新权限
flush privileges;
  • 输入下面的命令查看权限表
show grant;

第六步(锁定两台机器)

  • 为了防止在复制之前有新的数据写入,我们将两台机器同时用下面的命令锁定
flush tables with read lock;

第七步(Slave开启复制操作)

  • 第一步(Master):Master查看一下当前Master的状态,结果为
    • File为master-bin.000001
    • Position为158
show master status;
  • 第二步(Slave):先解锁Slave端,下面开始复制
unlock tables;
  • 第三步(Slave)输入下面的命令开始请求复制
slave stop;

change master to master_host='192.168.0.101',master_user='repl',master_password='123456',master_log_file='master-bin.000001',master_log_pos=158;

start slave;
  • 第四步(Slave)查看当前复制状态
show slave status;

第八步(Master开启复制操作)

  • 第一步(Slave):Slave查看一下当前Master的状态,结果为
    • File为master-bin.000001
    • Position为256
show master status;
  • 第二步(Master):先解锁Master端,下面开始复制
unlock tables;
  • 第三步(Master)输入下面的命令开始请求复制
slave stop;

change master to master_host='192.168.0.102',master_user='repl',master_password='123456',master_log_file='master-bin.000001',master_log_pos=256;

start slave;
  • 第四步(Master)查看当前复制状态
show slave status;

第九步(演示)

  • 在两端分别操作数据库,都会相应的更改

本文地址:https://blog.csdn.net/qq_41453285/article/details/107182830