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 小时前
进程的重要函数
linux·数据库
深夜吞食1 小时前
MySQL详解:数据类型、约束
数据库·mysql
Violet永存1 小时前
MySQL:undo log
数据库·mysql
琴智冰1 小时前
MySQL安装
mysql
桶将军T1 小时前
SEAFARING靶场渗透
数据库·web安全
Data 3172 小时前
经典sql题(二)求连续登录最多天数用户
大数据·数据库·数据仓库·sql·mysql
服装学院的IT男2 小时前
【Android 13源码分析】WindowContainer窗口层级-3-实例分析
android·数据库
小王是个弟弟3 小时前
HQL-计算不一样的 MUV
数据库·hive·sql
自身就是太阳3 小时前
深入理解 Spring 事务管理及其配置
java·开发语言·数据库·spring
不惑_3 小时前
初识 performance_schema:轻松掌握MySQL性能监控
数据库·mysql