MySQL主从复制与读写分离

前言:
在企业应用中,成熟的业务通常数据量都比较大
单台 MySQL 在安全性、 高可用性和高并发方面都无法满足实际的需求
配置多台主从数据库服务器以实现读写分离

一、主从复制

1. MySQL 支持的复制类型

MySQL 支持三种不同的复制方式:

  • STATEMENT(基于语句的复制):在主数据库执行 SQL 语句,并在从数据库上执行同样的语句。效率高,MySQL 默认使用此模式。
  • ROW(基于行的复制):仅复制变更的内容,而不是重新执行命令,适合复杂的事务操作。
  • MIXED(混合模式):一般默认使用基于语句的复制,在无法精确复制时切换到基于行的复制。

2. MySQL****主从复制的工作过程

两日志、三线程
( 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 上并行操作

3. MySQL 主从复制延迟的原因

  • 主数据库高并发:形成大量事务,导致同步延迟。
  • 网络延迟:主从数据库位于不同网络环境下会影响同步效率。
  • 硬件差异:主从数据库的硬件性能差异,包括 CPU、内存和硬盘 I/O。
  • 异步复制机制:MySQL 默认采用异步复制,导致延迟问题。

4. MySQL****几种主流同步方式

4.1 异步复制(Async Replication

主库将更新写入 Binlog 日志文件后,不需要等待数据更新是否已经复制到从库中,就可以继续处理更多的请求。Master 将事件写入 binlog ,但并不知道 Slave 是否或何时已经接收且已处理。在异步复制的机制的情况下,如果Master 宕机,事务在 Master 上已提交,但很可能这些事务没有传到任何的 Slave 上。假设有Master->Salve 故障转移的机制,此时 Slave 也可能会丢失事务。 MySQL 复制默认是异步复制,异步复制提供了最佳性能。

4.2 同步复制(Sync Replication

主库将更新写入 Binlog 日志文件后,需要等待数据更新已经复制到从库中,并且已经在从库执行成功,然后才能返回继续处理其它的请求。同步复制提供了最佳安全性,保证数据安全,数据不会丢失,但对性能有一定的影响。

4.3 半同步复制(Semi-Sync Replication

主库提交更新写入二进制日志文件后,等待数据更新写入了从服务器中继日志中,然后才能再继续处理其它请求。该功能确保至少有1 个从库接收完主库传递过来的 binlog 内容已经写入到自己的 relay log 里面了,才会通知主库上面的等待线程,该操作完毕。
半同步复制,是最佳安全性与最佳性能之间的一个折中。MySQL 5.5版本之后引入了半同步复制功能,主从服务器必须安装半同步复制插件,才能开启该复制功能。如果等待超时,超过rpl_semi_sync_master_timeout 参数设置时间(默认值为 10000 ,表示 10秒),则关闭半同步复制,并自动转换为异步复制模式。当master dump 线程发送完一个事务的所有事件之后,如果在rpl_semi_sync_master_timeout 内,收到了从库的响应,则主从又重新恢复为增强半同 步复制。
ACK (Acknowledge character )即是确认字符。

二、读写分离

1. 什么是读写分离?

读写分离的基本原理是将数据库的写操作(INSERT、UPDATE、DELETE)交由主数据库处理,而读操作(SELECT)则由从数据库负责。通过主从复制技术,可以将主数据库的数据变更同步到从数据库,从而实现读写操作的分离。

2. 为什么需要读写分离?

数据库写操作通常比读操作更加耗时。举例来说,写入10000条数据可能需要3分钟,而读取10000条数据仅需5秒钟。为了提升数据库性能,避免写入操作拖慢查询速度,读写分离是一种有效的优化方式。

3. 什么时候需要读写分离?

并非所有场景都需要读写分离。当系统中读操作频繁,写操作相对较少时,读写分离可以有效减轻数据库的负担,提高整体性能。通过主从复制同步数据,结合读写分离,能够大幅度提升数据库的并发处理能力。

4. 主从复制与读写分离的区别

主从复制的目的是同步主数据库的变更到从数据库,而读写分离则是为了提升数据库的负载能力。在高并发或高可用性的环境中,单一数据库服务器通常难以满足要求,因此通过主从复制加读写分离可以解决这些问题。

主从复制类似于 rsync,但 rsync 是对磁盘文件的备份,而 MySQL 主从复制是对数据库数据和操作的备份

5. MySQL 读写分离的实现方式

MySQL 读写分离的基本思路是在主服务器上执行写操作,而从服务器上执行读操作。复制机制用于将主服务器上的变更同步至从服务器。

目前常见的 MySQL 读写分离实现方式有两种:

  1. 基于程序代码实现:在代码中根据操作类型(SELECT、INSERT)进行路由分类。优点是性能较好,但需要开发人员实现,且不适合大型复杂应用。
  2. 基于中间代理层实现 :通过代理服务器接收客户端请求并转发至后端数据库。常见的工具包括:
    • MySQL-Proxy:MySQL 官方开源项目,使用 Lua 脚本进行 SQL 判断。
    • Atlas:由奇虎360开发,基于 MySQL-Proxy 进行优化,支持事务和存储过程。
    • Amoeba:由阿里巴巴团队开发,使用 Java 编写,易于使用,广泛应用于生产环境。

三、配置主从同步、读写分离

1.主从同步部署

master 服务器修改配置文件

root@master \~\]# vi /etc/my.cnf #在 mysqld 模块下修改一下内容 log_bin=master-bin # 开启二进制日志文件(之后生成的日志名为 master-bin ) log_slave-updates=true #开启从服务器日志同步 server_id = 1 #主服务器 id 为 1 (不可重复) **重启服务** \[root@master \~\]# systemctl restart mysqld **配置规则** \[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.10.%' IDENTIFIED BY '123456'; Query OK, 0 rows affected (0.00 sec) mysql\> flush privileges; **#** **刷新权限表** Query OK, 0 rows affected (0.00 sec) 规则解析: GRANT REPLICATION SLAVE ON \*.\* TO 'myslave'@'192.168.10.%' IDENTIFIED BY '123456'; 给从服务器提权,允许使用 slave 的身份复制 master 的所有数据库的所有表,并指定密码为 123456 查看 master 数据库状态 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) mysql\> # 以上可见产生了 master-bin.000001 日志文件,定位为 412

② 从服务器配置

root@slave1 \~\]# vi /etc/my.cnf log-bin=master-bin **#** **开启二进制日志文件** server_id = 22 **#** **设置server id为22,slave2 为23** relay-log=relay-log-bin **#** **从主服务器上同步日志文件记录到本地** relay-log-index=slave-relay-bin.index **#** **从主服务器上同步日志文件记录到本地** 开启从服务器功能 \[root@slave1 \~\]# mysql -uroot -p ............... mysql\> change master to master_host='192.168.10.16',master_user='myslave',master_password='123456',maste r_log_file='master-bin.000001',master_log_pos=412; Query OK, 0 rows affected, 2 warnings (0.02 sec) mysql\> start slave; Query OK, 0 rows affected (0.01 sec) 查看从服务器状态 mysql\> show slave status\\G; ##当I/O线程和SQL线程显示yes表示成功 Slave_IO_Running: Yes Slave_SQL_Running: Yes **测试数据同步**

在主服务器上创建一个数据库

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)
在两台从服务器上直接查看数据库列表

2. 读写分离

整个实验的环境 以及服务器信息
环境部署 cetos7.6
虚拟机服务环境
Master 服务器 :192.168.10.16
slave1 服务器 :192.168.10.14
Slave2 服务器 :192.168.10.15
Amoeba 服务器 :192.168.10.80 jdk1.6 、 Amoeba
客户端服务器 :192.168.10.13 mysql 测试
注:做读写分离实验之前必须有一 主 两从 环境
Amoeba 服务器配置 --
① ##安装 Java 环境##
因为 Amoeba 基于是 jdk1.5 开发的,所以官方推荐使用 jdk1.5 或 1.6 版本,高版本不建议使用。
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软件##
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 读负载均衡##

先在 Master 、 Slave1 、 Slave2 的 mysql 上开放权限给 Amoeba 访问

grant all on *.* to test@'192.168.10.%' identified by '123456';

再回到 amoeba 服务器配置 amoeba 服务:

cd /usr/local/amoeba/conf/
cp amoeba.xml amoeba.xml.bak
vim amoeba.xml # 修改 amoeba 配置文件
--30 行 --
<property name="user">amoeba</property>
--32 行 --
<property name="password">123456</property>
--115 行 --
<property name="defaultPool">master</property>
--117- 去掉注释 -
<property name="writePool">master</property>
<property name="readPool">slaves</property>
cp dbServers.xml dbServers.xml.bak
vim dbServers.xml # 修改数据库配置文件
--23 行 -- 注释掉 作用:默认进入 test 库 以防 mysql 中没有 test 库时,会报错
<!-- <property name="schema">test</property> -->
--26-- 修改
<property name="user">test</property>
--28-30-- 去掉注释
<property name="password">123456</property>
--45-- 修改,设置主服务器的名 Master
<dbServer name="master" parent="abstractServer">
--48-- 修改,设置主服务器的地址
<property name="ipAddress">192.168.10.16</property>
--52-- 修改,设置从服务器的名 slave1
<dbServer name="slave1" parent="abstractServer">
--55-- 修改,设置从服务器 1 的地址
<property name="ipAddress">192.168.10.14</property>
--58-- 复制上面 6 行粘贴,设置从服务器 2 的名 slave2 和地址
<dbServer name="slave2" parent="abstractServer">
<property name="ipAddress">192.168.10.15</property>
--65 行 -- 修改
<dbServer name="slaves" virtual="true">
--71 行 -- 修改
<property name="poolNames">slave1,slave2</property>
/usr/local/amoeba/bin/amoeba start& # 启动Amoeba软件,按ctrl+c 返回
netstat -anpt | grep java # 查看 8066 端口是否开启,默认端口为
TCP 8066
测试读写分离
#先安装数据库
yum install -y mariadb-server mariadb
systemctl start mariadb.service
在客户端服务器上测试
mysql -u amoeba -p123456 -h 192.168.10.80 -P8066
// 通过 amoeba 服务器代理访问 mysql ,在通过客户端连接 mysql 后写入的数据只有主服务会记录,然后同步给从-- 从服务器
在主服务器上:
use db_test;
create table test (id int(10),name varchar(10),address varchar(20));
在两台从服务器上:
stop slave; # 关闭同步
use db_test;
// 在 slave1 上:
insert into test values('1','zhangsan','this_is_slave1');
// 在 slave2 上:
insert into test values('2','lisi','this_is_slave2');
// 在主服务器上:
insert into test values('3','wangwu','this_is_master');
//在客户端服务器上:
use db_test;
select * from test; // 客户端会分别向 slave1 和 slave2 读取数据,显示的只有在两个从服务器
上添加的数据,没有在主服务器上添加的数据
insert into test values('4','qianqi','this_is_client'); // 只有主服务器上有此数据
// 在两个从服务器上执行 start slave; 即可实现同步在主服务器上添加的数据
start slave;

相关推荐
异世界贤狼转生码农1 小时前
MongoDB Windows 系统实战手册:从配置到数据处理入门
数据库·mongodb
QuZhengRong1 小时前
【数据库】Navicat 导入 Excel 数据乱码问题的解决方法
android·数据库·excel
码农阿豪1 小时前
Windows从零到一安装KingbaseES数据库及使用ksql工具连接全指南
数据库·windows
冷崖6 小时前
MySQL异步连接池的学习(五)
学习·mysql
时序数据说7 小时前
时序数据库市场前景分析
大数据·数据库·物联网·开源·时序数据库
听雪楼主.10 小时前
Oracle Undo Tablespace 使用率暴涨案例分析
数据库·oracle·架构
我科绝伦(Huanhuan Zhou)10 小时前
KINGBASE集群日常维护管理命令总结
数据库·database
妖灵翎幺11 小时前
Java应届生求职八股(2)---Mysql篇
数据库·mysql
HMBBLOVEPDX11 小时前
MySQL的事务日志:
数据库·mysql
weixin_4196583113 小时前
MySQL数据库备份与恢复
数据库·mysql