目录
7.1 分别在两台centos7系统上安装mysql 5.7(Windows系统)
1、简介
随着互联网技术的发展,在实际的生产环境中,由单台MySQL数据库服务器已经逐渐不能满足实际的需求。此时,数据库集群就很好的解决了这个问题。采用MySQL分布式集群,能够搭建一个高并发、负载均衡的集群服务器。在此之前,我们必须要保证每台MySQL服务器里的数据同步。数据同步,我们可以通过MySQL内部配置就可以轻松完成,主要有【主从复制和主主复制】。
MySQL数据库本身提供的主从复制功能,可以方便的实现数据的多处自动备份,从而实现数据库的拓展。多个数据备份,不仅可以加强数据的安全性;通过实现读写分离还可以进一步提升数据库的负载能力,从而分担主数据库的压力。
下图就描述了一个在多个数据库之间进行主从复制与读写分离的物理模型:
在【一主多从】的数据库架构体系中,多个从服务器采用异步方式感知主数据库的变化。
业务服务器在执行写或者修改数据库的操作 都是在主服务器上进行的;读数据库的操作 则是在各个从服务器上进行的(主服务器也可以提供读能力)。
2、为什么要做主从复制
主从复制可以实现【对数据库进行备份】和实现【读写分离】:
(1)对数据库进行备份:为了避免服务的不可用,以及保障数据的安全可靠性,我们至少需要部署两台或者两台以上的服务器来存储数据库数据。也就是说,我们需要将数据复制多份 部署在多台不同的服务器上,即使有一台服务器出现故障了,其他服务器依然可以继续提供服务。
(2)读写分离:MySQL自身提供了主从复制功能。主从复制,是指服务器分为主服务器和从服务器,主服务器负责读和写,从服务器只负责读,从而分担主服务器的压力。
3、MySQL主从复制的原理是什么
3.1 MySQL主从复制架构
3.1.1 一主多从架构
3.1.2 多主多从架构
3.2 MySQL主从复制的图解与执行流程
根据上图,分析一下MySQL主从复制原理(从库=slave节点,主库=master节点,binlog文件=记录SQL操作的二进制文件):
- 当master主服务器上的数据发生改变时(包括 新增、删除、修改、建库建表 等各种写操作),master主服务器会将数据改变写入到binlog日志文件中。
- salve从服务器会在一定时间间隔内对master主服务器上的binlog日志文件进行探测,探测其是否发生过改变。如果探测到master主服务器上的binlog日志文件发生了改变,则slave从服务器会开启一个 I/O Thread 请求master主服务器上的binlog日志文件。(注意:slave会告诉master从哪一个binlog日志文件中读取、从什么偏移量开始、到什么位置结束)。
- 同时,master主服务器也会开启一个 I/O Thread,用于向slave从服务器推送slave从服务器所需要的binlog日志文件内容。
- slave从服务器将接收到的binlog日志文件内容保存到自己本地的中继日志文件(relay log)中。
- 并且,salve从服务器将启动一个 SQL Thread 从中继日志文件中读取二进制日志,在本地回放,使得slave从服务器上的数据和master主服务器保持一致。
- 最后,I/O Thread 和 SQL Thread 都将进入睡眠状态,以等待下一次被唤醒,以此循环往复。
=====================主从复制的另一个文本解释=============================
(1)从库不断的试探主库的binlog文件。如果该binlog文件有更新,则从库会启动IO线程,并发送请求到主库中 以获取主库binlog文件的内容。
(2)向主库中写数据,包括 新增、删除、修改、建库建表 等写操作,主库都会将 “写操作对应的SQL命令” 记录到主库binlog文件中,并更新binlog文件的偏移量。
(3)如果从库试探到主库binlog文件的偏移量和自己本地记录的偏移量不一致,则表示主库中有数据更新,那么,从库将启动IO线程向主库请求从某个偏移量开始的、到binlog文件结束位置 之间的所有数据,这个数据其实就是一批SQL命令数据。
(4)主库将根据从库请求的偏移量来推送命令数据到从库中,从库接收到命令数据之后,会更新从库中之前所记录的偏移量位置,并且,将这些命令数据写入到自己的中继日志文件中,然后,唤醒SQL线程,同时让当前的IO线程挂起,进入休眠等待。
(5)从库的SQL线程将根据偏移量来读取中继日志文件中的命令数据。从库的SQL线程拿到命令数据之后,在从库中进行回放,也即 在从库中执行一遍主库的SQL命令,回放结束之后,将当前的SQL线程挂起,进入休眠等待。以此循环往复。
3.3 MySQL主从复制的基本原则
- 每个Slave服务器只能挂在一个Master服务器下。
- 每个Master服务器上可以挂载多个Slave服务器。
- 每个Slave服务器只能有一个唯一的Server-ID。
4、MySQL主从复制的方式
MySQL主从复制,主要有以下3种方式:
- 同步复制:master的变化,必须等待 slave-1、slave-2、...、slave-n 同步完成之后才能返回。
- 异步复制:master只需要完成自己的数据库操作即可,至于slaves是否收到二进制日志、slaves是否同步完成,master则不关心。这种方式也是MySQL的默认设置。
- 半同步复制:master只保证slaves中的一个操作成功就返回,其他slaves则不管。这个功能,是由Google为MySQL引入的。
本文说的是在 centos 7 系统上,实现的 MySQL5.7 数据库的主从复制。
5、MySQL主从复制的最大问题:主从延时
MySQL主从复制的最大问题就是 主从延时。
(1)通过MySQL主从复制的实现原理可以知道:MySQL的主从复制,可以保证master主服务器和slave从服务器上的数据库数据一致,但是,在时间上肯定是有延迟的,即 slave从服务器上的数据是滞后的。
(2)为什么会出现这样的问题?主要是因为 master主服务器上的数据库操作可以并发执行,但是,slave从服务器只能从 中继日志 relay log 中一条一条的读取、回放。
(3)如果master主服务器上的写操作很频繁,slave从服务器就很可能就跟不上了,于是就出现了主从延时。
主从延时的原理和解决方案,可以参见这些博客:
https://www.cnblogs.com/cnmenglang/p/6393769.html、如何实现主从复制、如何解决主从延时问题?、MySQL主从延时解决方案
6、MySQL主从复制的实战
6.1 一主三从架构图
6.2 环境说明(本文搭建一主一从架构)
- 在Windows系统上安装两个CentOS7虚拟机
- MySQL 5.7
- Master_IP:192.168.17.130
- Slave_IP:192.168.17.132
- 注意:MySQL版本号最好一致,为了方便学习测试,建议关闭防火墙。
6.3 实现MySQL主从复制需要进行的配置
(1)master主服务器:
- 开启二进制日志 binlog
- 配置唯一的server-id
- 获得master服务器的binlog文件名及偏移位置
- 创建一个用于slave服务器和master服务器通信的用户账号,并授权
(2)slave从服务器:
- 配置唯一的server-id
- 使用master服务器分配的用户账号来读取master服务器的binlog文件
- 启动slave服务器
7、开始搭建主从复制
7.1 分别在两台centos7系统上安装mysql 5.7(Windows系统)
具体的安装步骤可以参考:https://blog.csdn.net/qq_15092079/article/details/81629238
(1)本文中的两台服务器的IP地址分别为:主服务器(192.168.17.130),从服务器(192.168.17.132)。
(2)分别在这两个服务器上创建test数据库,以备后面测试。
7.2 master主服务器的配置
7.2.1 在master中,配置文件my.cnf
找到主库
的配置文件 my.cnf( 或者 my.ini ),我的在 /etc/my.cnf,在 [mysqld] 部分插入如下:Bin-log配置选项参数详解
[mysqld]
server-id=3307
log_bin=master-bin
binlog_do_db=test
#备注:
#编辑my.cnf文件
[root@localhost mysql]# vim /etc/my.cnf
#server-id:设置服务器的唯一标识
#log_bin:启动MySQL二进制日志,即数据同步语句,从数据库会一条一条的执行这些语句。
#binlog_do_db:指定记录二进制日志的数据库,即需要复制的数据库名,如果复制多个数据库,重复设置这个选项即可。
#binlog_ignore_db:指定不记录二进制日志的数据库,即不需要复制的数据库名,如果有多个数据库,重复设置这个选项即可。
#其中需要注意的是,binlog_do_db和binlog_ignore_db为互斥选项,一般只需要一个即可。
7.2.2 在master中,创建从服务器的用户和权限
#进入mysql数据库
[root@localhost mysql]# mysql -u root -p
Enter password:
#创建从数据库的masterbackup用户和权限
mysql> grant replication slave on *.* to masterbackup@'192.168.17.%' identified by '123456';
#刷新权限
mysql> flush privileges;
#退出mysql
mysql> exit;
#备注:
#192.168.17.%通配符:表示0-255的IP都可访问主服务器,正式环境请配置指定从服务器IP
#若将 192.168.17.% 改为 %:则任何ip均可作为其从数据库来访问主服务器
7.2.3 在master中,重启MySQL服务器
[root@localhost mysql]# service mysql restart
Shutting down MySQL.... SUCCESS!
Starting MySQL. SUCCESS!
7.2.4 在master中,查看主服务器状态
#进入mysql数据库
[root@localhost mysql]# mysql -u root -p
Enter password:
#查看主服务器状态
mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000001 | 154 | test | | |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
(1)记录上图结果中 File 和 Position 的值。(2)注意:
执行完此步骤后,不要再操作主服务器,防止主服务器的状态值变化。
7.3 slave从服务器的配置
7.3.1 在slave中,配置文件my.cnf
#编辑my.cnf文件
[root@localhost mysql]# vim /etc/my.cnf
#在[mysqld]中添加:
[mysqld]
server-id=3308
relay-log=slave-relay-bin
#replicate-do-db=test
#备注:
#server-id:服务器唯一标识,如果有多个从服务器,每个服务器的server-id都不能重复,跟IP一样是唯一标识,如果你没设置server-id或者设置为0,则从服务器不会连接到主服务器。
#relay-log:启动MySQL二进制日志,可以用来做数据备份和崩溃恢复;或主服务器挂掉了,将此从服务器作为其他从服务器的主服务器。
#replicate-do-db:指定同步的数据库,如果复制多个数据库,重复设置这个选项即可。若在master端不指定binlog-do-db,则在slave端可用replication-do-db来过滤。
#replicate-ignore-db:不需要同步的数据库,如果有多个数据库,重复设置这个选项即可。
#其中需要注意的是,replicate-do-db和replicate-ignore-db为互斥选项,一般只需要一个即可。
7.3.2 在slave中,重启MySQL服务
[root@localhost mysql]# service mysql restart
Shutting down MySQL.... SUCCESS!
Starting MySQL. SUCCESS!
7.3.3 在slave中,连接master主服务器
#进入mysql数据库
[root@localhost mysql]# mysql -u root -p
Enter password:
#连接master主服务器
mysql> change master to master_host='192.168.17.130',master_port=3306,master_user='masterbackup',master_password='123456',master_log_file='master-bin.000001',master_log_pos=154;
#备注:
#master_host:对应主服务器的IP地址。
#master_port:对应主服务器的端口。
#master_log_file:对应show master status显示的 File列:master-bin.000001。
#master_log_pos:对应show master status显示的 Position列:154。
7.3.4 在slave中,启动slave数据同步
#启动slave数据同步
mysql> start slave;
#停止slave数据同步(若有需要)
mysql> stop slave;
7.3.5 在slave中,查看slave信息
mysql> show slave status\G;
只有当看到 Slave_IO_State: Waiting for master ot send event 、Slave_IO_Running: YES、Slave_SQL_Running: YES 才表明MySQL的主从复制架构搭建正常!
7.4 MySQL主从复制的测试
(1)在master主服务器上登陆MySQL,且进入test数据库、创建tb_test表、且插入一条数据:提示:这里最好用数据库管理工具(如nacicat、sequel pro)来操作。
#显示所有的数据库
show databases;
#使用之前创建好的test数据库
use test;
#创建tb_test表
create table tb_test(ID varchar(36) primary key comment '主键ID', MEMO varchar(500) not null comment '信息');
#插入一条数据
insert into tb_test(ID,MEMO) values('1','one test');
#提交
commit;
(2)在slave从服务器上登陆MySQL,且进入test数据库,你会发现从数据库中,也出现了tb_test表,且表中还有 one test 数据存在,证明数据同步成功:
至此,一主一从的MySQL主从复制架构就实现了。
7.5 常用语句
-- 查看master的状态,尤其是当前的日志及位置
show master status;
-- 查看slave的状态
show slave status;
-- 暂停master
stop master;
-- 暂停slave,相当于终止从服务器的IO线程和SQL线程
stop slave;
-- 重置slave状态
reset slave;
-- 启动master和slave
start master;
start slave;
-- 在主服务器的客户端上查看主从复制的binlog日志文件内容:
show binlog events in 'mysql-bin.0000001'\G
7.6 解决错误
若在MySQL主从复制的过程中,出现其中一条语句同步失败了,则后面的语句也肯定不能够同步成功了。
例如:主库有一条数据,而从库并没有这一条数据,然而,在主库执行了删除这一条数据的操作,那么,从库没有这一条数据就肯定删除不了,从而报错了。在此时,从数据库的数据同步就失败了,因此,后面的同步语句就无法继续执行。这里提供有两种解决方法:
(1)在slave从数据库中,使用 SET 全局 sql_slave_skip_counter 来跳过事件,跳过这一个错误,然后执行从下一个事件组开始:
#在从数据库上操作
mysql > stop slave;
mysql > set global sql_slave_skip_counter=1;
mysql > start slave;
(2)在slave从数据库中,重新连上master主数据库。这种操作会直接跳过中间的那些同步语句,可能会导致一些数据未同步过去的问题,但这种操作也是最后的绝招。最好就是 令slave从数据库与master主数据库的数据结构和数据都一致了之后,再来恢复主从复制的操作:
#在从数据库上操作
mysql > stop slave;
mysql> change master to master_host='192.168.17.130',master_port=3306,master_user='masterbackup',master_password='123456',master_log_file='master-bin.000001',master_log_pos=2050;
mysql > start slave;
#备注
#master_log_file和master_log_pos可能会不同,需要在主数据库中 show master status 来查看。
7.7 总结
至此,MySQL数据库的【一主一从架构】主从复制功能就完成了。至于读写分离,我们可以通过程序来实现,这里简单讲解一下实现思想。
可以在master主服务器上创建一个数据库用户(出于安全,根据需求给予相应的权限)主要用于写操作,在程序中通过这一用户连接主数据库,只用于写操作。
在slave从服务器上创建一个数据库用户(出于安全,只给予读select的权限)主要用于读操作,在程序中通过这一用户连接从数据库, 只用于读操作。
当然,也可以找一个组件来完成MySQL的代理,实现SQL语句的路由,这样就不需要我们在程序上关注哪个数据库是写、哪个数据库是读的了。比如下面的第8节。
8、读写分离实战-待更新
8.1 读写分离的实现方式
8.2 使用Mycat实现读写分离
8.3 使用ShardingSphere实现读写分离
99、参考
(1)https://blog.csdn.net/cmm0401/article/details/107303433
(2)https://blog.csdn.net/weixin_51616026/article/details/114000971
(3)https://blog.csdn.net/mocas_wang/article/details/111593382
(4)https://blog.csdn.net/why15732625998/article/details/80463041
(5)https://www.cnblogs.com/cnmenglang/p/6393769.html
(6)如何实现 MySQL 的读写分离?如何解决 MySQL 主从同步的延时问题:https://zhuanlan.zhihu.com/p/60455737
(7)MySQL主从复制实现:https://blog.csdn.net/qq_15092079/article/details/81672920