为什么需要主从复制?
-
在业务复杂的系统中,有这么一个情景,有一句sql语句需要锁表,导致暂时不能使用读的服务,那么就很影响运行中的业务,使用主从复制,让主库负责写,从库负责读,这样,即使主库出现了锁表的情景,通过读从库也可以保证业务的正常运作。
-
做数据的热备
-
架构的扩展。业务量越来越大,I/O访问频率过高,单机无法满足,此时做多库的存储,降低磁盘I/O访问的频率,提高单个机器的I/O性能。
什么是mysql的主从复制?
MySQL 主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点。MySQL 默认采用异步复制方式,这样从节点不用一直访问主服务器来更新自己的数据,数据的更新可以在远程连接上进行,从节点可以复制主数据库中的所有数据库或者特定的数据库,或者特定的表。
mysql复制原理
-
master服务器将数据的改变记录二进制binlog日志,当master上的数据发生改变时,则将其改变写入二进制日志中;
-
slave服务器会在一定时间间隔内对master二进制日志进行探测其是否发生改变,如果发生改变,则开始一个I/OThread请求master二进制事件
-
同时主节点为每个I/O线程启动一个dump线程,用于向其发送二进制事件,并保存至从节点本地的中继日志中,从节点将启动SQL线程从中继日志中读取二进制日志,在本地重放,使得其数据和主节点的保持一致,最后I/OThread和SQLThread将进入睡眠状态,等待下一次被唤醒。
也就是说
- 从库会生成两个线程,一个I/O线程,一个SQL线程;
- I/O线程会去请求主库的binlog,并将得到的binlog写到本地的relay-log(中继日志)文件中;
- 主库会生成一个log dump线程,用来给从库I/O线程传binlog;
- SQL线程,会读取relay log文件中的日志,并解析成sql语句逐一执行;
MySQL主从形式:
mysql主从同步延时分析
mysql的主从复制都是单线程的操作,主库对所有DDL和DML产生的日志写进binlog,由于binlog是顺序写,所以效率很高,slave的sql thread线程将主库的DDL和DML操作事件在slave中重放。DML和DDL的IO操作是随机的,不是顺序,所以成本要高很多,另一方面,由于sql thread也是单线程的,当主库的并发较高时,产生的DML数量超过slave的SQL thread所能处理的速度,或者当slave中有大型query语句产生了锁等待,那么延时就产生了。
解决方案:
-
业务的持久化层的实现采用分库架构,mysql服务可平行扩展,分散压力。
-
单个库读写分离,一主多从,主写从读,分散压力。这样从库压力比主库高,保护主库。
-
服务的基础架构在业务和mysql之间加入memcache或者redis的cache层。降低mysql的读压力。
-
不同业务的mysql物理上放在不同机器,分散压力。
-
使用比主库更好的硬件设备作为slave,mysql压力小,延迟自然会变小。
-
使用更加强劲的硬件设备
参考原址:https://zhuanlan.zhihu.com/p/96212530
部署
-
Windows系统的 MySQL配置文件在:你安装MySQL的目录下的 my.ini 文件下
-
Linux系统的 MySQL配置文件在:/etc/my.cnf
-
Docker-MySQL镜像的在:/etc/mysql/my.cnf
这里我们使用 linux环境 和 Docker来实现主从复制 一主多从(也就一个从)
当然 你也可以在一台服务器上部署多台 MySQL
部署准备:
-
Linux 上安装好 mysql
https://blog.csdn.net/weixin_44685869/article/details/103937654 -
docker拉取 MySQL镜像 并 生成容器
docker pull mysql:5.7 docker run -p 3307:3306 --name mysql02 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7 # -dit是启动新的实例,这样的话就没法保存 使用它的目的就是为了避免 刚启动容器就以外的退出 # 我们还可以在后面加上 tail -f xxx.log /bin/bash 防止意外退出 docker start mysql02
正式开工
-
在主 数据库配置
vim /etc/my.cnf [mysqld] server_id = 1 # 数据库编号 binlog-do-db=mysql01 # 选择备份的数据库 # binlog-do-db=test1 log-bin=mysql-bin # 通过bin日志 方式实现主从复制 # binlog-ignore-db=mysql # 忽略主从 的数据库
修改完重启 MySQL
service mysqld restart
-
重启后 进入MySQL查看是否生效
mysql> show variables like 'server_id'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | server_id | 1 | +---------------+-------+ 1 row in set (0.00 sec)
-
Master数据库创建数据同步用户,授予用户 slave REPLICATION SLAVE权限和REPLICATION CLIENT权限,用于在主从库之间同步数据。
创建一个允许从服务器来访问的用户(主服务器):
mysql> create user 'slave'@'%' identified by 'mysql'; mysql> grant replication slave, replication client on *.* to 'slave'@'%'; mysql> flush privileges; or mysql> grant replication slave on *.* to 'root'@'%' identified by 'mysql'; mysql> flush privileges;
说明:
root: Slave 使用的帐号 identified by 'root': Slave 使用的密码 %: Slave 数据库IP ,%代表所有的IP
如果你用的是两台服务器,那么你的 从服务器 也需要开启
-
master端,通过
show master status;
显示信息。mysql> show master status\G *************************** 1. row *************************** File: mysql-bin.000002 Position: 154 Binlog_Do_DB: mysql01 Binlog_Ignore_DB: Executed_Gtid_Set: 1 row in set (0.00 sec) mysql> mysql> show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000002 | 154 | mysql01 | | | +------------------+----------+--------------+------------------+-------------------+ 1 row in set (0.00 sec)
两种方法查看都是一个意思,只不过是查看的内容格式不一样
参数 | 描述 |
---|---|
File | MySQL bin-log文件 |
Position | 因为之前我们用过MySQL,所以 bin-log日志是有内容呢。开启同步需要用到 154行以后的内容 |
Binlog_Do_DB | 你的从数据库 |
Binlog_Ignore_DB | 不被主从的 数据库 |
Executed_Gtid_Set | 执行事务集合 |
使用Navicat 查看机器是否可以远程连接。
主机器OK,下面开始配置从机器
-
进入dockerMySQL容器,也就是我们的 从机器
[root@izbp1izjo7pl5ccghnbdiuz ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 446d7cf1606c mysql:5.7 "docker-entrypoint.s…" 15 hours ago Up 15 hours 3306/tcp, 33060/tcp, 127.0.0.1:3307->3636/tcp mysql02 [root@izbp1izjo7pl5ccghnbdiuz ~]# [root@izbp1izjo7pl5ccghnbdiuz ~]# docker exec -it 446d7cf1606c bash
-
修改 配置文件
vim /etc/mysql/my.cnf
vim 异常 请 ↓
docker容器中 bash: vi: command not found,docker apt-get 异常 Temporary failure resolving[mysqld] ## 设置server_id,注意要唯一 server-id=2 ## 开启二进制日志功能,以备Slave作为其它Slave的Master时使用 log-bin=mysql-slave-bin ## relay_log配置中继日志 relay_log=edu-mysql-relay-bin
配置完成后也需要重启mysql服务和docker容器,
service mysqld restart docker restart mysql02
-
在Slave 中进入 mysql,执行
CHANGE master to master_host='47.96.158.77', master_user='slave', master_password='mysql', master_port=3306, master_log_file='mysql-bin.000001', master_log_pos= 154, master_connect_retry=60;
-
进入 从机器的 mysql,开启主从复制,查看同步信息
start slave # 开启从机器 show slave status \G;
看见 yes就代表 一切ok了。 -
最后测试
测试主从复制方式就十分多了,最简单的是在Master创建一个数据库,然后检查Slave是否存在此数据库。
master:
slave:
当然我们也可以进行添加数据的测试,在主机器 上添加数据,从机器是 完全同步的。
但是,从机器上添加的数据 主机是不同步的
时间 | 主机 | 从机 |
---|---|---|
t1 | use test create table user(id int(4), name varchar(10)); insert user values (111,‘zhangsan’) select * from user; 结果:一条 |
此时数据完全同步 |
t2 | select * from user 结果:一条数据 |
|
t3 | insert user values (111,‘liis’) 结果:两条数据 |
|
t4 | select * from user 结果:一条数据 |
docker 部分参考 https://www.cnblogs.com/songwenjie/p/9371422.html