mysql主从复制和读写分离

什么叫主从复制?

主从复制架构图和数据流向

主MySQL上的数据、新增、修改库、表、表里的数据。都会同步到从MySQL上

面试题:MySQL的主从复制模式

1、 异步复制:MySQL的默认复制就是异步复制 。工作中也一般使用异步复制。只要执行完之后,客户端提交事务主MySQL会立即把结果返回给从服务器主MySQL并不关心从MySQL是否已经接受并且处理。主一旦崩溃,主MySQL已经提交的事务可能没有传到从MySQL。

这个时候如果强行把从服务器提升为主服务器,可能导致新的主MySQL数据不完整。(情况很少见。工作中都是异步复制)

异步:类似于udp。只管发送,不管有没有收到

2、 全同步复制:主库执行完成一个事务,所有的从库都执行了该事务之后才会返回客户端因为需要等待所有从库全部执行完成性能必然下降(对数据一致性,和数据完整要求很高的场景)

3、 半同步复制:介于异步复制和全同步复制之间 。主库执行完一个客户端提交的事务之后,至少等待一个从库接受并处理完成之后才会给客户端 。半同步在一定程度上提高了数据的安全性 。和全同步复制一样,也会有一定的延迟延迟的时间一般是一个tcp/ip的往返时间(从发送到接收的时间,单位是毫秒)。半同步复制最好是在低延迟的网络中使用。

时间<1ms:round-trip time RTT

如何实现主从复制?

架构主从复制和读写分离

MySQL:主 20.0.0.50

MySQL2:从 20.0.0.60

MySQL3:从 20.0.0.70

test1:读写分离的服务器 20.0.0.20

test3:客户端 20.0.0.30

yum -y install ntp #时间同步工具

bash 复制代码
关闭五台主机的防火墙
回到三台MySQL
主从服务器的时间也要同步:
yum -y install ntp
#保证主从服务器时间必须一致

设置MySQL2和MySQL3与主MySQL同步

MySQL1:

vim /etc/ntp.conf
#在尾行添加
server 127.127.0.0
fudge 127.127.0.0 stratum 8

server 127.127.0.0
fudge 127.127.0.0 stratum 8
#数字越小,时间精确度越高,设置fudge 8 时间层级是8 最高到15.从本地获取时间源同步,不走网络。
systemctl restart ntpd

开启两台从MySQL2和MySQL3的ntp服务
/usr/sbin/ntpdate 20.0.0.50
#两台从服务器的时间源分别指向主MySQL 20.0.0.50
crontab -u root -e
*/30 * * * * /usr/sbin/ntpdate 20.0.0.50
#生产环境中一般创建一个定时任务

创建完成后查看一下三台主机的时间
date

回到主:
vim /etc/my.conf
log-bin=master-bin
#主服务器开启二进制日志
binlog_format=MIXED
#处理方式开启混合模式,如果并发量变高会自动切换成row
log-slave-updates=ture
#允许从服务器复制数据时,可以从主的二进制日志写到自己的二进制日志当中
systemctl restart mysqld

mysql -u root -p123456
#进入主数据库

grant replication slave on *.* to 'myslave'@'20.0.0.%' identified by '123456';
#给从库授权可以访问主库。创建一个用户名称叫myslave来自20.0.0.%这个网段,密码是123456.给从库授权可以访问主库
flush privileges;
#刷新一下权限
show master status;
#查看主MySQL的位置点

到从库MySQL2:
hostnamectl set-hostname
#改名从库,可做可不做

vim /etc/my.conf
server-id = 2
#id千万不能相同
relay-log=relay-log-bin
#修改日志的名称
relay-log-index=slave-relay-bin.index
#告诉你中继日志的索引名称叫这个
relay_log_recovery=1
#默认是0,1表示开启中继日志的恢复。如果从服务器出现异常或者崩溃时,从服务器会从主服务器的二进制日志正确读取和应用中继日志。起同步作用,会自动从主服务器获取,完成同步
systemctl restart mysqld
#重启从MySQL服务

到从库MySQL3:
vim /etc/my.conf
server-id = 3
#id千万不能相同
relay-log=relay-log-bin
relay-log-index=slave-relay-bin.index
relay_log_recovery=1

systemctl restart mysqld
#重启从MySQL服务

现在两台从MySQL都修改完成
mysql -u root -p123456
mysql -u root -p123456
#两台从MySQL都进入MySQL
两个从服务器都要:
CHANGE master to CHANGE master to master_host='20.0.0.50',master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=自己的号码;

start slave;

show slave status\G
#纵向查看

进入工具验证一下
连接三台服务器
create database kgc;
#创建库
查看一下是否同步实现主从复制。
create table test (name varchar(10));
#创建一个表测试一下
在表内写一点数据测试一下
主从服务完成!

在从上创建一个库
create database kgc1;
#主从复制是单向的只能从主复制到从服务器

Slave_IO_Running:yes #负责和主库的io通信。获取主库的io通信

Slave_SQL_Running:yes #负责自己的sql进程。写入从库

Slave_IO_Running:no #如果这里出问题,可能是配置文件错了、密码写错了、防火墙没有关

主从复制是单向的只能从主复制到从服务器

主从复制总结

主从复制的工作过程:

1、 主节点的数据记录发生变化都会记录在二进制日志

2、 slave节点会在一定时间内对主库的二进制文件进行探测。探测是否发生变化。如果有变化从库会开启一个IO的线程。请求主库的二进制事件。

3、 主库会给每一个I/O的线程启动一个dump线程,用于发送二进制事件给从库。从库通过I/O线程获取跟新,slave_sql负责将更新写入到从库本地,实现主从一致。

主从复制的问题:

1、 只能在主库上发生变化,然后同步到从。从库的更新不会同步到主

2、复制的过程是串行化过程,在从库上复制是串行的。主库的并行更新不能在从库上并行操作。

3、 主从复制的设计目的:就是为了在主库上写,在从库上查。读写分离,实现高可用。

如何实现读写分离?

要实现读写分离必须要先实现主从复制

读写分离:所有的写入操作都在主库,从库只负责读。(select)如果有更新,是从主库复制到从库。

为什么要有读写分离?

1、 数据库在写入数据时,比较耗时(MySQL写一万条数据需要3分)

2、 数据库在读的时候,速度很快(读一万条数据需要4.96秒)

3、 读写分离之后,数据库的写入和读取时分开的。哪怕写入的数据量比较大,但是不影响查询的效率。

什么场景下需要读写分离?

数据库不是一定需要读写分离的。只有在某些程序在使用数据库过程中,更新少,但是查询角度,这种情况可以考虑读写分离。

如果读和查的需求差不多,也可以考虑读写分离。

生产库一般都会做读写分离。

测试库一般不管。

在工作中,数据库的读写不会在同一个库中完成。既不安全,也不能满足高可用,也不能实现高并发。工作中都会做读写分离。

MySQL读写分离的原理:

1、 根据脚本实现。在代码中实现路由分类。select insert进行路由分类。这种方式时最多的。性能好,在代码中就可以实现,不需要额外的硬件设备。缺点:开发实现的,跟我们无关。如果大型的复杂的应用,涉及改动的代码非常多。

2、 基于中间代理层实现:mysql-proxy自带的开源项目,基于自带的lua脚本。这些lua脚本不是现成的,要自己写,不熟悉他的内置变量写不出来。

atlas 360内部自己使用的代理工具:不对外公开。每天的读写请求承载量可以到几十亿条,还支持事务,还支持存储过程。

3、 Amoeba 是由java开发的一个开源软件。不支持事务也不支持存储过程。但是Amoeba还是用的最多的,功能比较强大的软件。

Amoeba来实现读写分离

架构主从复制和读写分离

MySQL:主 20.0.0.50

MySQL2:从 20.0.0.60

MySQL3:从 20.0.0.70

test1:读写分离的服务器 Amoeba 20.0.0.20

test3:客户端 20.0.0.30

jdk1.5开发的,官方推荐使用1.5或者1.6

读写分离架构图和数据流向

bash 复制代码
配置读写分离:
java -version
#查看java版本

cd /opt
#拖入两个文件
cp jdk /usr/local
cd usr/local
chmod +x jdk
./
ctrl+c
yes

mv jdk/ jdk1.6

vim /etc/profile

source /etc/profile

java -version
#java环境配置完成

安装Amoeba
cd /opt
mkdir /usr/local/amoeba
tar -xf amoeba tar.gz -C /usr/local/amoeba
chmod -R 755 /usr/local/amoeba
./usr/local/amoeba/bin/amoeba
#出现start|stop表示安装成功

回到主MySQL和两个从MySQL都要配置
grant all on *.* to 'amoeba'@'20.0.0.%' identified by '123456';
flush privileges;

回到Amoeba客户端
cd /usr/local/amoeba/conf/
ls
amoeba.xml:配置用户信息
dbServers.xml:配置数据库信息
cp amoeba.xml amoeba.xml.bak.2023.11.13

vim amoeba.xml
set nu
#11行查看一下端口号8066
"user">amoeba
#到30行修改
"passord">123456
#到32行插入密码
name="defaultPool">master
#到115行
"writePool">master
"readPool">slaves
#到117行去掉注释 删除<!--和-->

cp dbServers.xml dbServers.xml.bak.2023.11.13
#备份一下

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">amoeba</property>

--28-30--去掉注释
<property name="password">123456</property>

--45--修改,设置主服务器的名Master
<dbServer name="master"  parent="abstractServer">

--48--修改,设置主服务器的地址
<property name="ipAddress">192.168.233.21</property>

--52--修改,设置从服务器的名slave1
<dbServer name="slave1"  parent="abstractServer">

--55--修改,设置从服务器1的地址
<property name="ipAddress">192.168.233.22</property>

--58--复制上面6行粘贴,设置从服务器2的名slave2和地址
<dbServer name="slave2"  parent="abstractServer">
<property name="ipAddress">192.168.233.23</property>

--65行--修改
<dbServer name="slaves" virtual="true">

--71行--修改
<property name="poolNames">slave1,slave2</property>



/usr/local/amoeba/bin/amoeba start &
#启动amoeba并且后台运行amoeba

netstat -antp | grep java
#查看端口是否启动看看端口

到客户端查看测试
systemctl restart mariadb

natstat -antp | grep mariadb

回到主从服务器打开查询日志记录
vim /etc/my.conf
general_log=ON
general_log_file=
#开启日志记录

systemctl restart mysqld
#三台MySQL都重启mysql服务

tail -f /usr/log/mysql/data/mysql
#打开三台MySQL的日志

回到客户端连接amoeba服务器来测试

mysql -u amoeba -p123456 -h20.0.0.20 -P8066
#登录amoeba指定端口20.0.0.20 -P指定端口8066
use kgc;
show tables;
insert into test values('test2')
#插入一条新的数据
回到三台MySQL查看报文是否有写入数据

回到客户端
select * from test;
回到从MySQL服务器查看日志是否有查询记录

回到客户端
select * from test;
回到从MySQL服务器查看日志是否有查询记录
#两次查询还可以实现轮询

读写分离实验完成!

Slave_IO_Running:no如何处理?

1、 网络问题。ping一下主机是否能通

2、 配置文件错误 my.conf配置文件写错了

3、 CHANGE master to CHANGE master to master_host='20.0.0.50',master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=自己的号码; 指定主和从的时候,可能是文件名错误,也可能是位置偏移量不对。

4、 防火墙和安全机制问题

MySQL的主从复制模式问题

1、 异步复制:MySQL的默认复制就是异步复制 。工作中也一般使用异步复制。只要执行完之后,客户端提交事务主MySQL会立即把结果返回给从服务器主MySQL并不关心从MySQL是否已经接受并且处理。主一旦崩溃,主MySQL已经提交的事务可能没有传到从MySQL。

这个时候如果强行把从服务器提升为主服务器,可能导致新的主MySQL数据不完整。(情况很少见。工作中都是异步复制)

异步:类似于udp。只管发送,不管有没有收到

2、 全同步复制:主库执行完成一个事务,所有的从库都执行了该事务之后才会返回客户端因为需要等待所有从库全部执行完成性能必然下降(对数据一致性,和数据完整要求很高的场景)

3、 半同步复制:介于异步复制和全同步复制之间 。主库执行完一个客户端提交的事务之后,至少等待一个从库接受并处理完成之后才会给客户端 。半同步在一定程度上提高了数据的安全性 。和全同步复制一样,也会有一定的延迟延迟的时间一般是一个tcp/ip的往返时间(从发送到接收的时间,单位是毫秒)。半同步复制最好是在低延迟的网络中使用。

主从复制延迟问题

1、 网络延迟

2、 主从硬件设备(cpu主频。内存的IO、硬件的IO)

3、 同步复制而不是异步复制

解决方案:

1、 硬件方面:主库一般不需要动的太多,从库的硬件配置要更好。提升随机写的性能。例如:硬盘可以考虑换成固态的,升级cpu的核数,扩展一下内存。尽量使用物理机(不要用云服务器)。

2、 从网络层面解决问题:主从服务器都配置在一个局域网内,尽量避免跨网段或者跨机房。

3、 架构方面:读写分离,把写入控制设置在主库,从库负责读。减轻从库的负载,降低从库的压力。

4、 MySQL的配置方面:从配置文件的角度实现性能最大化。

bash 复制代码
如果追求安全性的配置:
innodb_flush_log_at_trx_commit=1
#每次事务提交时都会刷新事务日志以却表持久性。这是最高级别的数据安全性,但是会影响性能,默认就是1.(只要安全就这样配)
#0就是事务提交时不会立刻刷新,而是每秒刷新1次。可以提高性能,但是发生故障会导致数据丢失。
#2就是事务提交时,事务日志不会写入硬盘而是保存在系统缓存,不会进行刷新。有一定的安全性和性能。内存要求比较高。
#生产中默认就是1

sync_binlog=1
#1是默认值,也就是每次提交事务之后。直接把二进制日志刷新到磁盘。以确保日志的持久性。会占用比较高的性能,但是安全性高。(只要安全就这样配)
#0会把二进制日志写入到缓存,也不会刷新日志。故障发生也会丢失数据,同时对内存的要求也提高了
#3表示每3个事务执行一次刷新到磁盘。可以提高性能,但是一旦发生崩溃,数据会大量丢失。


追求性能化:
sync_binlog=0 (不建议)
innodb_flush_log_at_trx_commit=2 (不建议)
logs-slave-updates=0 (强烈不建议)
#从库的更新不会写入二进制日志。(强烈不建议)
innodb_buffer_pool_size 300M 500G
#innodb存储引擎缓冲池的大小,设置的数据越高,可以提高innodb的性能。更多的数据和索引都可以缓存在内存中。可以减少磁盘的访问次数。对系统内存要求比较高。

建议舍弃掉一部分性能,追求安全方面。数据无价。

如果Slave_IO_Running:no 排查思路是什么?

答:85%配置文件问题。

show slave status\G 能看到的信息有哪些呢

1、 I/O和sql的线程状态信息

2、 master服务器的ip地址、端口、事务开始的位置

3、 最近一次的错误信息和错误的位置

4、 最近一次的I/O报错的信息

5、 最近一次sql的报错信息

相关推荐
在路上走着走着几秒前
openEuler安装OpenGauss5.0
数据库·gaussdb
午言若5 分钟前
MYSQL 架构
c++·mysql
余~~1853816280023 分钟前
矩阵碰一碰发视频源码技术解析,支持OEM
数据库·microsoft
罗政39 分钟前
PDF书籍《手写调用链监控APM系统-Java版》第9章 插件与链路的结合:Mysql插件实现
java·mysql·pdf
张声录11 小时前
【ETCD】【实操篇(十五)】etcd集群成员管理:如何高效地添加、删除与更新节点
数据库·etcd
天乐敲代码1 小时前
Etcd静态分布式集群搭建
数据库·分布式·etcd
chengma_0909091 小时前
MySQL 数据库连接数查询、配置
数据库·mysql
林农1 小时前
C05S14-MySQL高级语句
linux·mysql·云计算
TDengine (老段)1 小时前
两分钟掌握 TDengine 全部写入方式
大数据·数据库·时序数据库·tdengine·涛思数据