MySQL主从复制原理
复制类型
MySQL支持三种复制类型:
- 基于语句的复制(STATEMENT):默认方式,记录SQL语句
- 基于行的复制(ROW):记录行数据变更
- 混合类型复制(MIXED):根据场景自动选择前两种方式
核心工作流程
主从复制通过两日志、三线程实现数据同步:
-
关键日志
- 主库二进制日志(binlog)
- 从库中继日志(relay log)
-
核心线程
- Dump线程:主库发送binlog事件
- I/O线程:从库接收并写入relay log
- SQL线程:从库重放relay log事件
两日志、三线程:
(1)在每个事务更新数据完成之前,Master 在二进制日志(Binary log)记录这些改变。写入二进制日志完成后,Master 通知存储引擎提交事务。
(2)Slave 将 Master 的复制到其中继日志(Relay log)。首先slave 开始一个工作线程(I/O),I/O线程在 Master 上打开一个普通的连接,然后开始 Binlog dump process。Binlog dump process 从 Master 的二进制日志中读取事件,如果已经跟上 Master,它会睡眠并等待 Master 产生新的事件,I/O线程将这些事件写入中继日志。
(3)SQL slave thread(SQL从线程)处理该过程的最后一步,SQL线程从中继日志读取事件,并重放其中的事件而更新 Slave 数据,使其与 Master 中的数据一致,只要该线程与 I/O 线程保持一致,中继日志通常会位于 OS 缓存中,所以中继日志的开销很小。
复制过程有一个很重要的限制,即复制在 Slave 上是串行化的,也就是说 Master 上的并行更新操作不能在 Slave 上并行操作。
复制延迟优化
常见延迟原因:
- 主库高并发事务堆积
- 网络传输延迟
- 硬件性能差异(CPU/内存/磁盘IO)
优化方案:
- 增大从库
innodb_buffer_pool_size - 使用SSD磁盘提升IO性能
- 避免跨机房部署
- 采用并行复制机制
同步机制对比
异步复制
- 特点:主库提交事务后立即响应,不等待从库确认
- 优势:性能最佳
- 风险:主库故障可能导致数据丢失
同步复制
- 特点:主库需等待所有从库执行完成
- 优势:数据零丢失
- 缺点:性能影响显著
半同步复制
- 特点:主库等待至少一个从库接收binlog(默认等待10秒)
- 平衡点:在数据安全性和性能间取得折中
- 退化机制:超时后自动降级为异步复制
增强半同步复制
- 改进点:在事务提交前等待ACK确认
- 核心优势:完全避免数据不一致问题
- 配置参数 :
rpl_semi_sync_master_wait_point = AFTER_SYNC
读写分离实现
基于主从复制架构:
- 写操作:定向到主库执行
- 读操作:分发至多个从库负载均衡
典型实现方案:
- 使用中间件(如MyCat、ProxySQL)
- 应用层代码路由
- 数据库连接池配置
注意事项:
- 需处理主从同步延迟导致的"脏读"问题
- 重要业务查询可强制走主库
- 定期监控复制延迟状态
主从复制实验
整个实验的环境 以及服务器信息
- 环境部署 cetos7.9
- 虚拟机服务环境
Master服务器:192.168.73.129 mysql5.7
slave1服务器:192.168.73.128 mysql5.7
Slave2服务器:192.168.73.130 mysql5.7 - Amoeba服务器:192.168.73.131 (预备机器) jdk1.6 mycat 二次开发
主从服务器时间同步
master服务器配置
环境前准备部署
① 安装ntp、修改配置文件
bash
[root@master ~]# yum -y install ntpdate ntp #安装ntp软件
[root@master ~]# ntpdate ntp1.aliyun.com #时间同步
② 开启NTP服务、关闭防火墙和增强性安全功能
bash
[root@master ~]# systemctl start ntpd
[root@master ~]# systemctl stop firewalld.service
[root@master ~]# setenforce 0
两台SLAVE服务器配置
① 安装ntp、ntpdate服务
bash
[root@localhost ~]# yum install ntp ntpdate -y
② 开启ntp服务,关闭防火墙、增强性安全功能
③ 时间同步master服务器
bash
[root@localhost ~]# ntpdate 192.168.73.129
配置主从同步
① master服务器修改配置文件
bash
[root@master ~]# vi /etc/my.cnf
#在mysqld模块下修改一下内容
#开启二进制日志文件(之后生成的日志名为master-bin)
log_bin=master-bin
#开启从服务器日志同步
log_slave-updates=true
#主服务器id为1(不可重复)
server_id = 1
--------》wq
bash
重启服务
[root@master ~]# systemctl restart mysqld
bash
配置规则
[root@master ~]# mysql -uroot -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
mysql> GRANT REPLICATION SLAVE ON *.* TO 'myslave'@'192.168.73.%' IDENTIFIED BY '123456';
Query OK, 0 rows affected (0.00 sec)
#刷新权限表
mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
给从服务器提权,允许使用slave的身份复制master的所有数据库的所有表,并指定密码为123456
查看master数据库状态
bash
mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000001 | 412 | | | |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
② 从服务器配置 128和130设置都是一样的
bash
[root@slave1 ~]# vi /etc/my.cnf
#开启二进制日志文件
log-bin=master-bin
#设置server id为22,slave2 为23
server_id = 22
#从主服务器上同步日志文件记录到本地
relay-log=relay-log-bin
#定义relay-log的位置和名称(index索引)
relay-log-index=slave-relay-bin.index
--------》wq
bash
开启从服务器功能
[root@slave1 ~]# mysql -uroot -p
...............
mysql> change master to master_host='192.168.73.129',master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=412;
Query OK, 0 rows affected, 2 warnings (0.02 sec)
#412为主服务器master-bin.000001日志文件,定位为412
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
查看从服务器状态
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.73.129
Master_User: myslave
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: master-bin.000001
Read_Master_Log_Pos: 412
Relay_Log_File: relay-log-bin.000002
Relay_Log_Pos: 284
Relay_Master_Log_File: master-bin.000001
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
.......
1 row in set (0.00 sec)
#确保Slave_IO_Running: Yes、Slave_SQL_Running: Yes
测试数据同步
在主服务器上创建一个数据库
bash
mysql> create database work;
Query OK, 1 row affected (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
| work |
+--------------------+
5 rows in set (0.00 sec)
在两台从服务器上直接查看数据库列表
bash
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| test |
| work |
+--------------------+
5 rows in set (0.00 sec)
以上,主从同步复制配置完成
MySQL 读写分离
读写分离
读写分离,基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。
原因:
因为数据库的"写"(写10000条数据可能要3分钟)操作是比较耗时的。
但是数据库的"读"(读10000条数据可能只要5秒钟)。
所以读写分离,解决的是,数据库的写入,影响了查询的效率。
MySQL 读写分离原理
读写分离就是只在主服务器上写,只在从服务器上读。基本的原理是让主数据库处理事务性操作,而从数据库处理 select 查询。数据库复制被用来把主数据库上事务性操作导致的变更同步到集群中的从数据库。
读写分离实验
整个实验的环境 以及服务器信息
- 环境部署 cetos7.6
- 虚拟机服务环境
Master服务器:192.168.73.129
slave1服务器:192.168.73.128
Slave2服务器:192.168.73.130
Amoeba服务器:192.168.73.131 mysql 测试
注:做读写分离实验之前必须有一 主 两从 环境
搭建 MySQL读写分离
Amoeba服务器配置----
① ##安装 Java 环境##
bash
cd /opt/
cp jdk-6u14-linux-x64.bin /usr/local/
cd /usr/local/
chmod +x jdk-6u14-linux-x64
./jdk-6u14-linux-x64.bin
//按yes,按enter
mv jdk1.6.0_14/ /usr/local/jdk1.6
vim /etc/profile
export JAVA_HOME=/usr/local/jdk1.6
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
export PATH=$JAVA_HOME/lib:$JAVA_HOME/jre/bin/:$PATH:$HOME/bin
export AMOEBA_HOME=/usr/local/amoeba
export PATH=$PATH:$AMOEBA_HOME/bin
source /etc/profile
java -version
② ##安装 Amoeba软件##
bash
mkdir /usr/local/amoeba
tar zxvf amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba/
chmod -R 755 /usr/local/amoeba/
/usr/local/amoeba/bin/amoeba
//如显示amoeba start|stop说明安装成功
③ ##配置 Amoeba读写分离,两个 Slave 读负载均衡##
bash
#先在Master、Slave1、Slave2 的mysql上开放权限给 Amoeba 访问
grant all on *.* to test@'192.168.73.%' identified by '123456';
bash
#再回到amoeba服务器配置amoeba服务:
cd /usr/local/amoeba/conf/
cp amoeba.xml amoeba.xml.bak
vim amoeba.xml #修改amoeba配置文件
bash
cp dbServers.xml dbServers.xml.bak
vim dbServers.xml #修改数据库配置文件
bash
/usr/local/amoeba/bin/amoeba start& #启动Amoeba软件,按ctrl+c 返回
netstat -anpt | grep java #查看8066端口是否开启,默认端口为TCP 8066
测试读写分离
#先安装数据库
```bash
yum install -y mariadb-server mariadb
systemctl start mariadb.service
在客户端服务器上测试
bash
mysql -u amoeba -p123456 -h 192.168.73.80 -P8066
//通过amoeba服务器代理访问mysql ,在通过客户端连接mysql后写入的数据只有主服务会记录,然后同步给从--从服务器
在主服务器上:
bash
use db_test;
create table test (id int(10),name varchar(10),address varchar(20));
在两台从服务器上:
bash
stop slave; #关闭同步
use db_test;
//在slave1上:
bash
insert into test values('1','zhangsan','this_is_slave1');
//在slave2上:
bash
insert into test values('2','lisi','this_is_slave2');
//在主服务器上:
bash
insert into test values('3','wangwu','this_is_master');
//在客户端服务器上:
bash
use db_test;
select * from test;
bash
insert into test values('4','qianqi','this_is_client'); //只有主服务器上有此数据