MySQL主从复制和读写分离

文章目录

MySQL主从复制和读写分离

实现高可用,高并发

一、MySQL主从复制

1、MySQL主从复制原理

  • 配置主从复制是为了两台设备保持数据完整性,主从复制是slave角色复制master角色的数据

2、MySQL主从复制的工作过程

主从复制的过程

  • mysql主数据库将处理的事务(增、删、改、查)存放到二进制日志文件(mysql-bin-000001),通知存储引擎将数据存储到磁盘中
  • master的dump线程监听slave的I/O线程的请求,将二进制日志文件更新的数据发送给slave的I/O线程
  • slave的工作线程(I/O线程),会将master更新的数据复制存放到slave的中继日志文件中,然后由slave中的sql线程进行读取数据,并将数据存放到自己的二进制(类似)文件中,与master的数据保持一致

主从复制核心内容

  • 两个日志文件

    • 二进制日志文件(master)
    • 中继日志文件(slave)
  • 三个线程

    • dump线程(master):监听slave的I/O线程请求,将master中二进制日志文件中更新的数据发送给slave的I/O线程
    • I/O线程(slave):将更新的数据存放到slave的中继日志文件中
    • sql线程(slave):读取中继日志文件中的数据,并将数据存放到自己的二进制(类似)文件中,与master数据保持一致性

3、MySQL的复制类型

3.1 STATEMENT
  • 基于语句的复制。
  • 在服务器上执行sql语句,在从服务器上执行同样的语句,mysql默认采用基于语句的复制,执行效率高。
3.2 ROW
  • 基于行的复制。
  • 把改变的内容复制过去, 而不是把命令在从服务器上执行一遍。
3.3 MIXED
  • 混合类型的复制。
  • 默认采用基于语句的复制,一旦发现基于语句无法精确复制时, 就会采用基于行的复制。

4、MySQL主从复制高延迟的原因

  • master服务器高并发,形成大量事务
  • 网络延迟
  • 主从硬件设备导致 cpu主频、内存io、硬盘io
  • 本来就不是同步复制、而是异步复制

5、MySQL主从复制高延迟的解决办法

  • 从库优化Mysql参数。比如增大innodb_buffer_pool_size,让更多操作在Mysql内存中完成,减少磁盘操作。
  • 从库使用高性能主机。包括cpu强悍、内存加大。避免使用虚拟云主机,使用物理主机,这样提升了i/o方面性能。
  • 从库使用SSD磁盘,避免使用低速的机械硬盘。
  • 网络优化,避免跨机房实现同步。

6、MySQL主从复制环境配置

服务器 主机名 IP 软件版本
Master服务器 master 192.168.10.11 mysql 5.7
Slave1服务器 slave1 192.168.10.12 mysql 5.7
Slave2服务器 slave2 192.168.10.13 mysql 5.7
Amoeba服务器 amoeba 192.168.10.14 jdk1.6/Amoeba
客户端服务器 client 192.168.10.15 yum安装mariadb

7、搭建MySQL主从复制

  • 搭建之前先要关闭防火墙和核心防护
mysql 复制代码
systemctl stop firewalld
systemctl disable firewalld
#关闭防火墙

setenforce 0
#关闭防护中心
7.1 主从服务器时间同步
7.1.1 主服务器配置
mysql 复制代码
yum install -y ntp
#安装ntp

#修改配置文件
vim /etc/ntp.conf
server 127.127.10.0
#设置本地是时钟源,添加网段
fudge 127.127.10.0 stratum 8
#设置时间层级为8

service ntpd start
#开启服务

service ntpd status
#查看服务状态
7.1.2 从服务器配置

slave1与slave2都需要配置

mysql 复制代码
yum install -y ntp ntpdate
#安装服务

service ntpd start
#查看服务状态

/usr/sbin/ntpdate 192.168.10.11
#与主服务器保持时间同步
7.2 主服务器配置
mysql 复制代码
#修改配置文件
vim /etc/my.cnf
server-id=1
#定义server-id,每台主机不可相同
log-bin=master-bin
#添加主服务器开启二进制日志
binlog_format=MIXED
#复制类型使用MIXED模式
log-slave-updates=true
#添加允许从服务器更新二进制日志

server-id=1
log-bin=master-bin
binlog_format=MIXED
log-slave-updates=true

systemctl restart mysqld.service
#重启数据库

mysql -uroot -p
#登录mysql

grant replication slave ON *.* to 'myslave'@'192.168.10.%' identified by '123456';
#设置从服务器账号并授权

flush privileges;
#刷新

show master status;
#查看状态
7.3 从服务器配置
  • slave1配置
mysql 复制代码
#修改配置文件
vim /etc/my.cnf
server-id=2
#修改id与其他主机不能相同
relay-log=relay-log-bin
#开启中继日志,从主服务器上同步日志文件记录到本地
relay-log-index=slave-relay-bin.index
#定义中继日志文件的位置和名称
relay_log_recovery=1
#重新复制时,从最后的中继日志文件开始恢复复制

server-id=2
relay-log=relay-log-bin
relay-log-index=slave-relay-bin.index
relay_log_recovery=1

systemctl restart mysqld.service
#重启数据库

mysql -uroot -p
#登录mysql

change master to master_host='192.168.10.11',master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=603;
#配置同步,注意master_log_file和master_log_pos的值要与Master查询的一致

start slave;
#开动同步,如有报错执行reset slave;

show slave status\G
#查看从服务器状态,确保IO和SQL线程都是Yes,代表同步正常。
  • slave2配置
mysql 复制代码
#修改配置文件
vim /etc/my.cnf
server-id=3
#修改id与其他主机不能相同
relay-log=relay-log-bin
#开启中继日志,从主服务器上同步日志文件记录到本地
relay-log-index=slave-relay-bin.index
#定义中继日志文件的位置和名称
relay_log_recovery=1
#重新复制时,从最后的中继日志文件开始恢复复制

server-id=3
relay-log=relay-log-bin
relay-log-index=slave-relay-bin.index
relay_log_recovery=1

systemctl restart mysqld.service
#重启数据库

mysql -uroot -p
#登录mysql

change master to master_host='192.168.10.11',master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=603;
#配置同步,注意master_log_file和master_log_pos的值要与Master查询的一致

start slave;
#开动同步,如有报错执行reset slave;

show slave status\G
#查看从服务器状态,确保IO和SQL线程都是Yes,代表同步正常。

一般Slave_IO_Running:No 的可能性有

  • 网络不通
  • my.cnf配置有问题
  • 密码、file文件名、pos偏移量不对
  • 防火墙没有关闭
7.4 验证
mysql 复制代码
create database kgc;
#master服务器创建库,slave服务器中也有新建数据库信息

二、MySQL读写分离

1、MySQL读写分离原理

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

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

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

  • 读写分离方案

    • 基于程序代码内部实现

    • 基于中间代理层实现

      • MySQL-Proxy

      • Amoeba

2、MySQL读写分离的原因

  • 因为数据库的"写"(写10000条数据可能要3分钟)操作是比较耗时的。
  • 但是数据库的"读"(读10000条数据可能只要5秒钟)。
  • 所以读写分离,解决的是,数据库的写入,影响了查询的效率。

3、MySQL读写分离的应用

  • 数据库不一定要读写分离, 如果程序使用数据库较多时,而更新少,查询多的情况下会考虑使用。
  • 利用数据库主从同步, 再通过读写分离可以分担数据库压力,提高性能。

4、MySQL主从复制与读写分离

  • 在实际的生产环境中, 对数据库的读和写都在同一个数据库服务器中,是不能满足实际需求的。无论是在安全性、高可用性还是高并发等各个方面都是完全不能满足实际需求的。因此,通过主从复制的方式来同步数据,再通过读写分离来提升数据库的并发负载能力。有点类似于rsync,但是不同的是rsync是对磁盘文件做备份,而mysql主从复制是对数据库中的数据、语句做备份。

5、搭建MySQL读写分离

5.1 amoeba服务器配置
  • 安装Java环境(amoeba仅支持jdk1.6版本)
mysql 复制代码
cd /opt
#切换目录

cp jdk-6u14-linux-x64.bin /usr/local/
#复制安装包到/usr/local/目录

cd /usr/local
#切换目录

chmod +x jdk-6u14-linux-x64.bin
./jdk-6u14-linux-x64.bin
#执行,一直按回车键,出现下列行时,输入yes,再按回车即可
Do you agree to the above license terms? [yes or no]
yes(需要输入)

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
#查看Java版本
  • 安装amoeba
mysql 复制代码
mkdir /usr/local/amoeba
#新建目录

cd /opt
#切换到有安装包的目录下

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,说明安装成功
5.2 配置 amoeba读写分离,两个 slave 读负载均衡
5.2.1 先在master、slave1、slave2 的mysql上开放权限给 amoeba 访问
  • master服务器
mysql 复制代码
grant all on *.* to xxxx@'192.168.10.%' identified by '123456';
#主服务器自定义用户xxxx,并给amoeba开放权限可以访问
  • slave服务器
mysql 复制代码
grant all on *.* to xxxx@'192.168.10.%' identified by '123456';
#从服务器自定义用户xxxx,并给amoeba开放权限可以访问
5.2.2 再对amoeba服务器进行配置
mysql 复制代码
cd /usr/local/amoeba/conf/
#切换目录

cp amoeba.xml amoeba.xml.bak
#备份配置文件

#修改配置文件
vim amoeba.xml
30                                         <property name="user">amoeba</property>
#修改30行
32                                         <property name="password">123456</property>
#修改32行
115                 <property name="defaultPool">master</property>
#修改115行
117                 <!-- -->
118                 <property name="writePool">master</property>
119                 <property name="readPool">slaves</property>
120
#取消117行-120行注释,并进行修改

cp dbServers.xml dbServers.xml.bak
#备份配置文件

#修改配置文件
vim dbServers.xml
 22                         <!-- mysql schema
 23                         <property name="schema">test</property>
 24                         -->
#注释掉23行,默认进入test库,防止mysql中没有test库时报错
 26                         <property name="user">xxxx</property>
#修改26行,使用之前创建的授权用户
 28                         <!--  mysql password -->
 29                         <property name="password">123456</property>
 30
#取消28行-30行注释,修改密码为之前创建授权用户的密码
 45         <dbServer name="master"  parent="abstractServer">
#修改45行,主服务器名为master
 48                         <property name="ipAddress">192.168.10.11</property>
#修改48行,主服务器地址
 52         <dbServer name="slave1"  parent="abstractServer">
#修改52行,从服务器1名为slave1
 55                         <property name="ipAddress">192.168.10.12</property>
#修改55行,从服务器1的地址
 58         <dbServer name="slave2"  parent="abstractServer">
 59                 <factoryConfig>
 60                         <!-- mysql ip -->
 61                         <property name="ipAddress">192.168.10.13</property>
 62                 </factoryConfig>
 63         </dbServer>
#复制上面slave1的6行配置信息,修改58行,从服务器2名为slave2,修改61行,从服务器2的地址
 65         <dbServer name="slaves" virtual="true">
#修改65行,slaves
 71                         <property name="poolNames">slave1,slave2</property>
#修改71行,slave1,slave2

/usr/local/amoeba/bin/amoeba start&
#后台启动amoeba,按ctrl+c返回

ss -natp |grep java
#查看8066端口是否开启,默认端口tcp8066
5.3 客户端服务器测试读写分离
  • 客户端服务器(地址:192.168.10.15)
mysql 复制代码
yum install -y mariadb-server mariadb
#安装

systemctl start mariadb.service
#开启服务

mysql -u amoeba -p123456 -h 192.168.10.14 -P8066
#通过amoeba服务器代理访问mysql,在通过客户端连接mysql后写入的数据只有主服务会记录,然后同步给从服务器。
#这里通过192.168.10.14主机的8066端口使用用户amoeba登录mysql。

show databases;
#查看数据库信息

use luck;
#切换数据库

show tables;
#查看库中表的信息(没有表)

create table luck(id int,name char(10));
#创建表luck

show tables;
#查看库中表的信息,此时luck表存在
  • master服务器(地址:192.168.10.11)
mysql 复制代码
show databases;
#查看数据库信息

use luck;
#切换数据库

show tables;
#查看库中表的信息,master服务器有luck表
  • slave1服务器(地址:192.168.10.12)
mysql 复制代码
show databases;
#查看数据库信息

use luck;
#切换数据库

show tables;
#查看库中表的信息,slave1服务器有luck表
  • slave2服务器(地址:192.168.10.13)
mysql 复制代码
show databases;
#查看数据库信息

use luck;
#切换数据库

show tables;
#查看库中表的信息,slave2服务器有luck表

总结:客户端服务器做出修改,所有服务器数据都会同步

5.4 关闭slave功能,在主从服务器中插入数据
  • slave1服务器(地址:192.168.10.12)
mysql 复制代码
stop slave;
#关闭slave

insert into luck values(1,'slave1');
#在luck表中插入数据

select * from luck;
#查看luck表的数据
  • slave2服务器(地址:192.168.10.13)
mysql 复制代码
stop slave;
#关闭slave

insert into luck values(2,'slave2');
#在luck表中插入数据

select * from luck;
#查看luck表的数据
  • master服务器(地址:192.168.10.11)
mysql 复制代码
insert into luck values(3,'master');
#luck表中插入数据

select * from luck;
#查看luck表信息
  • 客户端服务器(192.168.10.15)
mysql 复制代码
select * from luck;
#客户端查询luck表信息

总结:由于从服务器关闭了slave功能,所以客户端无法查询到master服务器修改的数据,并且客户端以轮询的方式显示slave1与slave2中的数据

5.5 关闭slave功能后,客户端写入数据
  • 客户端服务器(地址:192.168.10.15)
mysql 复制代码
insert into luck values(4,'client');
#在luck表中插入数据

select * from luck;
#客户端以轮询的方式只显示slave1与slave2中的数据
  • master服务器(地址:192.168.10.11)
mysql 复制代码
select * from luck;
#查看luck表中数据,显示客户端与master服务器的数据
  • slave1服务器(地址:192.168.10.12)
mysql 复制代码
select * from luck;
#查询luck表的信息,只会显示本机插入的数据,不会显示客户端插入的数据
  • slave2服务器(地址:192.168.10.13)
mysql 复制代码
select * from luck;
#查询luck表的信息,只会显示本机插入的数据,不会显示客户端插入的数据

总结:客户端服务器的修改操作是对于Master服务器进行的,因此Master服务器上可以看到客户端服务器所做的insert操作。由于客户端服务器的select操作是对从服务器进行的,而从服务器关闭了slave功能,无法获取更新,因此客户端服务器本身以及从服务器都无法查看更新操作。

5.6 从服务器开启slave功能
  • slave1服务器(地址:192.168.10.12)
mysql 复制代码
start slave;
#开启slave功能

select * from luck;
#查看luck表信息,除了slave2的数据不显示,master和客户端的数据都显示
  • slave2服务器(地址:192.168.10.13)
mysql 复制代码
start slave;
#开启slave功能

select * from luck;
#查看luck表信息,除了slave1的数据不显示,master和客户端的数据都显示
  • master服务器(地址:192.168.10.11)
mysql 复制代码
select * from luck;
#查看luck表信息,不会显示从服务器的数据
  • 客户端服务器(地址:192.168.10.15)
mysql 复制代码
select * from luck;
##查看luck表信息,客户端以轮询的方式,显示两个从服务器的内容

总结:从服务器开启slave服务后可以从Master服务器上获取更新,但是从服务器上更新的数据不会被Master服务器看到。

客户端再次插入数据
  • 客户端服务器(地址:192.168.10.15)
mysql 复制代码
insert into luck values(5,'client002');
#在luck表中插入数据

select * from luck;
#查询luck表中数据,客户端以轮询的方式,显示两个从服务器的内容
  • master服务器(地址:192.168.10.11)
mysql 复制代码
select * from luck;
#表中会显示客户端新插入的数据
  • slave1服务器(地址:192.168.10.12)
mysql 复制代码
select * from luck;
#查询luck表的信息,slave1会显示客户端新插入的数据
  • slave2服务器(地址:192.168.10.13)
mysql 复制代码
select * from luck;
#查询luck表的信息,slave2会显示客户端新插入的数据

总结:客户端服务器上的数据修改,会同步到所有服务器中。

相关推荐
大拇指的约定1 小时前
数据库(MySQL):使用命令从零开始在Navicat创建一个数据库及其数据表(三),单表查询
数据库·mysql·oracle
银氨溶液2 小时前
MySql数据引擎InnoDB引起的锁问题
数据库·mysql·面试·求职
unix2linux4 小时前
Parade Series - SHA256
linux·python·mysql·shell
沐言人生5 小时前
Android10 Framework—Init进程-8.服务端属性文件创建和mmap映射
android
沐言人生5 小时前
Android10 Framework—Init进程-9.服务端属性值初始化
android·android studio·android jetpack
沐言人生5 小时前
Android10 Framework—Init进程-7.服务端属性安全上下文序列化
android·android studio·android jetpack
追光天使5 小时前
【Mac】和【安卓手机】 通过有线方式实现投屏
android·macos·智能手机·投屏·有线
小雨cc5566ru6 小时前
uniapp+Android智慧居家养老服务平台 0fjae微信小程序
android·微信小程序·uni-app
hefaxiang6 小时前
【MYSQL】mysql约束---自增长约束(auto_increment)
数据库·mysql
计算机学姐6 小时前
基于微信小程序的调查问卷管理系统
java·vue.js·spring boot·mysql·微信小程序·小程序·mybatis