MySQL数据库——主从复制及读写分离

MySQL数据库——主从复制及读写分离

前言、Mysql复制的应用常见场景


• 读写分离,提高查询访问性能,有效减少主数据库访问压力。

• 实时灾备,主数据库出现故障时,可快速切换到从数据库。

• 数据汇总,可将多个主数据库同步汇总到一个从数据库中,方便数据统计分析。

一、Mysql主从复制原理介绍


1.Mysql异步和半同步复制


传统的Mysql复制提供了一种简单的主-从复制方法,有一个主,以及一个或多个从。主节点执行和提交事务,然后将它们(异步地)发送到从节点,以重新执行(在基于语句的复制中)或应用(在基于行的复制中)。这是一个shared-nothing的系统,默认情况下所有server成员都有一个完整的数据副本。(5.7版本异步的性能很好,没什么延迟)

还有一个半同步复制,它在协议中添加了一个同步步骤,这意味着主节点在提交时需要等待从节点确认它已经接收到了事务,只有这样,主节点才能继续提交操作。(延时比较高,影响主的读写性能,如果要保证数据的高一致性,选择用半同步。)

在上面两张图片中,可以看到传统异步MySQL复制协议(以及半同步)的图形展示,蓝色箭头表示再不同server之间或者server与client应用之间的信息交互。

2.Mysql主从复制过程


• 开启binlog日志,从库开启relaylog日志,通过把主库的binlog传送到从库,重新解析应用到从库。

• 复制需要三个线程(dump、io、sql)完成。

• 复制是异步的过程。主从复制是异步的逻辑的sql语句级的复制。

3.主从复制前提


• 主服务器一定要打开二进制日志。

• 必须两台服务器(或者是多个实例)。

• 从服务器需要一次数据初始化。

• 如果主从服务器都是新搭建的话,可以不做初始化。

• 如果主服务器已经运行了很长时间了,可以通过备份将主库数据恢复到从库。

• 主库必须要有对从库复制请求的用户。

• 从库需要有relay-log设置,存放从主库传送过来的二进制日志show variables like'%relay%;

• 在第一次复制的时候,从库需要change master to去连接主库,

• change master信息需要存放到master.info中show variables like%master info%';

• 从库怎么知道,主库发生了新的变化?通过relay-log.info记录的已经应用过的relay-log信息,

• 在复制过程中涉及到的线程:

​ ❁ 从库会开启一个lO thread(线程),负责连接主库,请求binlog,接收binlog并写入relay-log。

​ ❁ 从库会开启一个SQL thread(线程),负责执行relay-log中的时间。

​ ❁ 主库会开启一个dump thread(线程),负责响应从IO thread的请求。

4.Mysql主从复制实现


★★流程★★:

• 通过二进制日志

• 至少两台(主,从)

• 主服务器的二进制日志“拿”到从服务器上再运行一遍

• 通过网络连接两台机器,一般都会出现延迟的状态,也可以说是异步的。

• 从库通过手工执行change master to语句链接主库,提供了连接的用户一切条件user、password、port、ip。

• 并且让从库知道,二进制日志的起点位置(file名 position号)。

• 启动从库同步服务start slave。

• 从库的IO和主库的dump线程建立链接。

• 从库根据change master to语句提供的file号和position号,IO线程向主库发起binlog的请求。

• 主库dump线程根据从库的请求,将本地binlog以events的方式发给从库IO线程。

• 从库IO线程接收binlog events,并存放到本地relay-log中,传送过来的信息,会记录到master.info中。

• 从库SQL线程应用relay-log,并且把应用过的记录到relay-log.info中,默认情况下,已经应用过的relay会自动被清理purge。

5.Mysql复制的三种核心格式


复制的工作原理是数据库修改记录到binlog日志并传递到slave,然后slave在本地还原的过程。而时间记录到binlog的格式会有所不同。

①基于语句的复制(statement based replication)

基于主库将SQL语句写入到bin log中完成复制。

②基于行数据的复制(row based replication)

基于主库将每一行数据变化的信息作为时间写入到bin log中完成日志。默认就是基于行级别的复制,因为它相对语句复制逻辑更为严谨。

③混合复制(mixed based replication)

上述两者的结合。默认情况下优先使用基于语句的复制,只有当部分语句在基于语句复制不完全的情况下才会自动切换为基于行数据的复制。

6.Mysql主从复制搭建(一主一从)


环境部署

master:192.168.222.20

slave:192.168.222.10

端口:3306

主服务器master配置

#配置my.cnf文件
[root@master ~]# vim /etc/my.cnf
[mysqld]
…………
server-id = 1
log-bin=master-bin				#添加,主服务器开启二进制日志
binlog_format = MIXED
log-slave-updates=true			#添加,允许slave从master复制数据时可以写入到自己的二进制日志

#重启mysqld
[root@master ~]# systemctl restart mysqld
[root@master ~]# mysql -u root -p
#Mysql授权远程主机登录
mysql> GRANT REPLICATION SLAVE ON *.* TO 'myslave'@'192.168.222.%' IDENTIFIED BY '111';	 #给从服务器授权
mysql> FLUSH PRIVILEGES; 						#刷新权限

在这里插入图片描述

从服务器slave配置

[root@slave ~]# vim /etc/my.cnf
…………
server-id = 2								#修改,注意id与Master的不同,两个Slave的id也要不同
relay-log=relay-log-bin						#添加,开启中继日志,从主服务器上同步日志文件记录到本地
relay-log-index=slave-relya-bin.index		#添加,定义中继日志文件的位置和名称,一般和relay-log在同一目录
relay_log_recovery = 1                      #选配项
#当 slave 从库宕机后,假如 relay-log 损坏了,导致一部分中继日志没有处理,则自动放弃所有未执行的 relay-log,并且重新从 master 上获取日志,这样就保证了relay-log 的完整性。默认情况下该功能是关闭的,将 relay_log_recovery 的值设置为 1 时, 可在 slave 从库上开启该功能,建议开启。
#重启服务
[root@slave ~]# systemctl restart mysqld
#进入数据库
[root@slave ~]# mysql -u root -p
mysql> CHANGE master to master_host='192.168.222.20',master_user='myslave',master_password='111',master_log_file='master-bin.000004',master_log_pos=604;					#配置同步,注意 master_log_file 和 master_log_pos 的值要与Master查询的一致

mysql> start slave;						#启动同步,如有报错执行 reset slave;
mysql> show slave status\G					#查看 Slave 状态
//确保 IO 和 SQL 线程都是 Yes,代表同步正常。
Slave_IO_Running: Yes				#负责与主机的io通信
Slave_SQL_Running: Yes				#负责自己的slave mysql进程

在这里插入图片描述
在这里插入图片描述

如果出现不是YES那么如何排查?

Slave_IO线程相对比较简单,一般不容易出错。如果显示为No,则有可能以下原因导致:
    * 网络问题(检查网络连接是否有问题)
    * 权限问题,例如在配置slave同步时因为slave访问master没有权限导致
    * master上的binlog文件误删或者其他问题导致的master库突然停止更新binlog日志。解决方案是找到同步的点和binlog文件,重新change master
 
相对的Slave_SQL线程就比较容易出错。例如人为的在从库插入一条数据,造成的主从库不一致。但此时两个线程的状态仍然是正常的,主库插入数据时,到从库同步时,从库会出现主键重复的错误。此时Slave_SQL_Running的状态变为No
 
而Last_SQL_Error, Last_SQL_Error_Timestamp会记录错误的原因和发生的时间

Slave_SQL_Running线程报错之后,会停止后续的SQL执行,因为向后执行会导致错误修复的难度增加
-- 先停止slave
stop slave;
 
-- 跳过执行语句数量
-- 此时需要查看错误日志去修复报错信息
set global sql_slave_skip_counter=1;
 
-- 开始slave
start slave;
 
-- 然后再检查一下 slave status

验证主从复制效果

在主数据库建表插入数据查看从数据库是否完成复制。

在这里插入图片描述

二、Mysql读写分离


1.读写分离原理


• 只在主服务器上写,只在从服务器上读。

• 主数据库处理事务性查询,从数据库处理SELECT查询。

• 数据库复制用于将事务性查询的变更同步到集群中的从数据库。

在这里插入图片描述

2.读写分离方案


• 基于程序代码内部实现

• 基于中间代理层实现

​ ▶MySQL Proxy——MySQL官方

​ ▶Atlas——奇虎360

​ ▶DBProxy——美团点评

​ ▶Amoeba——早期阿里巴巴

​ ▶cober——阿里巴巴

​ ▶MyCat——阿里巴巴

3.Amoeba+M+S集群搭建


在这里插入图片描述

3.1准备环境

Amoba服务器:192.168.10.21 jdk1.6、Amoeba

Master数据库:192.168.10.10 MySQL5.7

Slave1数据库 :192.168.10.12 MySQL5.7

Slave2数据库 :192.168.10.17 MySQL5.7

Amoba服务器配置

#因为 Amoeba 基于是 jdk1.5 开发的,所以官方推荐使用 jdk1.5 或 1.6 版本,高版本不建议使用。
#将jdk-6u14-linux-x64.bin 和 amoeba-mysql-binary-2.2.0.tar.gz.0 上传到/opt目录下。

[root@amoeba ~]# cd /opt/
[root@amoeba opt]# cp jdk-6u14-linux-x64.bin /usr/local/

[root@amoeba opt]# cd /usr/local/

[root@amoeba local]# chmod +x jdk-6u14-linux-x64.bin 

[root@amoeba local]# ./jdk-6u14-linux-x64.bin
按空格到最后一行
按yes,按enter

[root@amoeba local]# mv jdk1.6.0_14/ /usr/local/jdk1.6

[root@amoeba local]# vim /etc/profile  ##存放的是jdk环境变量
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

[root@amoeba local]# source /etc/profile  # 刷新环境变量
[root@amoeba local]# java -version # 查看java jdk

##安装 Amoeba软件##
[root@amoeba local]# mkdir /usr/local/amoeba
[root@amoeba local]# tar zxvf /opt/amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba/

[root@amoeba local]# chmod -R 755 /usr/local/amoeba/

[root@amoeba local]# /usr/local/amoeba/bin/amoeba
##如显示amoeba start|stop 说明安装成功

服务器上配置 Amoeba读写分离,两个 Slave 读负载均衡

mysql> grant all on *.* to 'test'@'192.168.222.%' identified by '111';
#在一主两从上都要配置,amoeba详单与一个用户,可以操作每个数据库的操作
#amoeba服务器配置
[root@amoeba local]# cd /usr/local/amoeba/conf/

[root@amoeba conf]# cp amoeba.xml amoeba.xml.bak
[root@amoeba conf]# vim amoeba.xml				#修改amoeba配置文件

#30修改
<property name="user">amoeba</property>

#32修改
<property name="password">abc123</property>

#115修改
<property name="defaultPool">master</property>

#117去掉注释–
<property name="writePool">master</property>
<property name="readPool">slaves</property>
[root@amoeba conf]# cp dbServers.xml dbServers.xml.bak
[root@amoeba conf]# vim dbServers.xml			#修改数据库配置文件
--23行--注释掉  作用:默认进入test库 以防mysql中没有test库时,会报错
<!-- <property name="schema">test</property> -->
--26--修改
<property name="user">test</property>
--28-30--去掉注释
<property name="password">123.com</property>
--45--修改,设置主服务器的名Master
<dbServer name="master"  parent="abstractServer">
--48--修改,设置主服务器的地址
<property name="ipAddress">192.168.10.10</property>
--52--修改,设置从服务器的名slave1
<dbServer name="slave1"  parent="abstractServer">
--55--修改,设置从服务器1的地址
<property name="ipAddress">192.168.10.12</property>
--58--复制上面6行粘贴,设置从服务器2的名slave2和地址
<dbServer name="slave2"  parent="abstractServer">
<property name="ipAddress">192.168.10.17</property>
--65行--修改
<dbServer name="slaves" virtual="true">
--71行--修改
<property name="poolNames">slave1,slave2</property>
[root@amoeba conf]# /usr/local/amoeba/bin/amoeba start &	#启动Amoeba软件,按ctrl+c 返回
[root@amoeba conf]# netstat -anpt | grep java				#查看8066端口是否开启,默认端口为TCP 8066

测试读写分离

做下面的实验时,记得在从服务器上把所有的同步关掉!!

#在一台其他机器上使用yum快速安装MySQL虚拟客户端
[root@client ~]# yum install -y mariadb-server mariadb
[root@client ~]# systemctl start mariadb.service
#测试:
#通过amoeba服务器代理访问mysql ,在通过客户端连接mysql后写入的数据只有主服务会记录,然后同步给从服务器
[root@client ~]# mysql -u amoeba -pabc123 -h 192.168.10.21 -P8066

END

猜你喜欢

转载自blog.csdn.net/tu464932199/article/details/126415732