Bootstrap

mysql的主从复制和读写分离

目录

主从复制

主从复制的模式

1.异步模式

2.全同步模式

3.半同步模式

主从复制的延迟

主从复制的延迟的原因

解决方案

双一设置

性能化设置

主从复制如何实现

安装步骤

读写分离

实验步骤

面试题


主从复制

主从复制的模式

1.异步模式

mysql的默认模式:主库在更新完事务之后会立即吧结果返回给从服务器,并不关心从库是否接收到,以及从库是否处理成功

出现的问题:网络问题可能没有同步,或者其他因素的影响导致同步失败

异步模式特点:效率高

2.全同步模式

主库在更新完事务之后,立即把结果返回到从库,所有的从库执行完毕之后才能继续下一个同步。特点:安全   

缺点:性能受到影响

3.半同步模式

介于异步和全同步之间,主库更新完事务之后,也是同步到从库,同步完成之后有一个等待时间,等待时间是一个tcp/ip的往返时间,一般都是5毫秒左右

特点:既在一定程度上保证了效率,也在一定程度上保证了数据的完整性

半同步复制最好在低延时的网络中使用。

主从复制的特点:主可以复制到从,从不可以复制到主

主从复制的延迟

主从复制的延迟的原因

1.网络问题,防火墙的原因

2.硬件设备问题,cpu、内存和磁盘出了问题

3.配置文件问题

解决方案

(1)硬件方面
从库配置更好的硬件,提升随机写的性能。比如原本是机械盘,可以考虑更换为ssd固态。
升级核心数更强的cpu、加大内存。避免使用虚拟云主机,使用物理主机

(2)网络方面 
将从库分布在相同局域网内或网络延迟较小的环境中。
尽量避免跨机房,跨网域进行主从数据库服务器的设置

(3)架构方面
在事务当中尽量对主库读写,其他非事务中的读在从库。
消除一部分延迟带来的数据库不一致。增加缓存降低一些从库的负载。 

(4)mysqld服务配置方面 
该配置设置针对mysql主从复制性能优化最大化,安全性并不高。
如果从安全的角度上考虑的话,就要设置双一设置
 

双一设置

配置文件当中进行设置的方式提高数据的安全性。

前提:数据库的存储引擎要是innodb

innodb_flush_log_at_trx_commit=1

每次提交都会刷新事务日志,确保事务的持久性,但会影响性能

0: 事务提交时不刷新事务日志,而是每秒进行一次日志刷新。这可以提高性能,
但在发生故障时可能会导致数据丢失。

1: 默认值。每次事务提交时都会刷新事务日志,以确保事务持久性。
这提供了最高级别的数据安全性,但可能会影响性能。

2: 事务提交时将事务日志写入操作系统缓存,但不进行物理刷新。
这提供了一定的数据安全性和性能。
 

sync_binlog=1

每次提交事务,将二进制日志的内容保存到磁盘,确保日志的持久性,提高了安全性

0: 二进制日志写入操作系统缓存,但不进行物理刷新。这提供了最高性能,
但在发生故障时可能会导致数据丢失。

1: 默认值。每次事务提交时,将二进制日志刷新到磁盘,以确保日志的持久性。
这提供了较高级别的数据安全性。

N: 每次事务提交时,将二进制日志刷新到磁盘,但最多每 N 个事务执行一次物理刷新。
这在某些情况下可以提高性能,但在发生故障时可能会导致少量数据丢失。
 

性能化设置

sync_binlog=10

最多提交几次事务会进行磁盘刷新,日志内容保存到磁盘

innodb_flush_log_at_trx_commit=2

每次更新都保存在内存中,不进行刷新(不推荐用)

innodb_buffer_pool_siza=60M

控制innodb缓冲池的大小,增大可以提高数据库的性能,但是占用的是系统内存,配置的时候要注意合理化使用

主从复制如何实现

实现是基于mysql的二进制日志,根据主库的二进制文件的标志位,实现主和从的同步。

主从服务器之间,服务器的时间要同步

架构:

三台服务器

192.168.233.70 mysql 主

192.168.233.80 mysql 从

192.168.233.90 mysql 从

安装步骤

1.安装ntpdate(主从都要安装) 

yum -y install ntpdate -y

然后查看时间是否一致

2.配置主的配置文件

vim /etc/my.cnf 添加

log-bin=master-bin

binlog_format=MIXED

log-slave-updates=true

允许从服务器从主库复制数据时可以写入从库自己的二进制日志当中

然后重启服务systemctl restart mysqld

3.进入主的数据库

mysql -u root -p123456

CREATE USER 'myslave'@'192.168.233.%' IDENTIFIED WITH mysql_native_password BY '123456';

 GRANT REPLICATION SLAVE ON *.* TO 'myslave'@'192.168.233.%';

 FLUSH PRIVILEGES;

show master status;

4.配置从1 的配置文件

vim /etc/my.cnf

relay-log=relay-log-bin

#从服务器上获取二进制日志的开头,开启从库的二进制日志
relay-log-index=slave-relay-bin.index

#二进制日志的索引文件的名称
relay_log_recovery=1

#配置从服务器在启动时是否执行二进制日志的回复操作(和主库同步),1表示开启

然后重启服务systemctl restart mysqld

5.配置从2 的配置文件

vim /etc/my.cnf

relay-log=relay-log-bin
relay-log-index=slave-relay-bin.index
relay_log_recovery=1

然后重启服务systemctl restart mysqld

6.进入从1和从2的数据库(两个一样的操作)

mysql -u root -p123456

CREATE USER 'myslave'@'192.168.233.%' IDENTIFIED WITH mysql_native_password BY '123456';

GRANT REPLICATION SLAVE ON *.* TO 'myslave'@'192.168.233.%';

FLUSH PRIVILEGES;

CHANGE master to master_host='192.168.233.70',master_user='myslave',master_password='123456',master_log_file=master-bin.000001',master_log_pos=857;

start slave;

show slave status\G;

查看I/O是否都是yes

Slave_IO_Running: Yes

从库和主机的读写通信是否正常

 Slave_SQL_Running: Yes

slave mysql进程状态是否正常

如果报错

可以一直重试

如果I/O不是yes呢,你如何排查?
首先排查网络问题,使用ping 命令查看从服务器是否能与主服务器通信
再查看防火墙和核心防护是否关闭(增强功能)
接着查看从服务slave是否开启
两个从服务器的server-id 是否相同导致只能连接一台
master_log_file master_log_pos的值跟master值是否一致

读写分离

主从架构当中,主库负责写,从库只负责读

数据流向图

读写分离的方式:

1.代码实现 开发人员纯靠代码完成,涉及到数据库的二次开发,性能好,不需要额外的硬件设备

2.中间层代理  代理服务器。在客户端和主从架构之间有一个代理服务器。代理服务器收到客户端的请求之后通过客户端的sql语句来进行判断,读转到从,写转到主

Amoeba:读写分离最常见的客户端代理软件。java代码开发的一个软件

架构:

三台服务器

192.168.233.70 mysql 主

192.168.233.80 mysql 从

192.168.233.90 mysql 从

192.168.233.10 jdk1.6 Amoeba 代理服务器

192.168.233.20 mysql  maridb 客户端

实验步骤

1.在10代理服务器

安装 Amoeba和java

然后一直按空格  再输入yes 跳出来点击取消

mv jdk1.6.0-14/ 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

cd /opt

mkdir /usr/local/amoeba

tar -xf amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba

chmod -R 755 /usr/local/amoeba/

安装成功

2.在主、从1、从2创建用户并赋权

mysql -u root -p123456

CREATE USER 'myslave'@'192.168.233.%' IDENTIFIED WITH mysql_native_password BY '123456';

GRANT REPLICATION SLAVE ON *.* TO 'myslave'@'192.168.233.%';

FLUSH PRIVILEGES;

3.在10代理服务器

cd /usr/local/amoeba/conf/

cp amoeba.xml amoeba.xml.bak.2024.07.23

vim amoeba.xml

--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.70</property>

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

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

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

4.在客户端

yum install -y mariadb-server mariadb
systemctl start mariadb.service

5.在主、从1、从2

vim /etc/my.cnf

general_log=ON
general_log_file=/usr/local/mysql/data/mysql_general.log
 

然后重启systemctl restart mysqld

6.在客户端

mysql -u amoeba -p123456 -h 192.168.233.10 -P8066

7.在主、从1、从2

8.在客户端

实验结果

查看日志

如果在客户端创建表主从都有写

如果在客户端查询表 主不查询,两个从有查询记录

面试题

1.主从同步复制原理

  1. 当主库数据发生变更时,写入本地Bin Log文件
  2. 从库IO线程发起dump主库Bin Log文件的请求
  3. 主库IO线程推送Bin Log文件到从库中
  4. 从库IO线程把Bin Log内容写入本地的Relay Log文件中
  5. 从库SQL线程读取Relay Log文件内容
  6. 从库SQL线程重新执行一遍SQL语句

2、读写分离你们使用什么方式?   amoeba 代理 mycat 代码 sql_proxy
通过amoeba代理服务器,实现只在主服务器上写,只在从服务器上读;
主数据库处理事务性查询,从数据库处理select 查询;
数据库复制被用来把事务查询导致的变更同步的集群中的从数据库

3、如何查看主从同步状态是否成功
在从服务器上内输入 show slave status\G 查看主从信息查看里面有IO线程的状态信息,还有master服务器的IP地址、端口事务开始号。
当 Slave_IO_Running和Slave_SQL_Running都是YES时 ,表示主从同步状态成功

4、如果I/O不是yes呢,你如何排查?
首先排查网络问题,使用ping 命令查看从服务器是否能与主服务器通信
再查看防火墙和核心防护是否关闭(增强功能)
接着查看从服务slave是否开启
两个从服务器的server-id 是否相同导致只能连接一台
master_log_file master_log_pos的值跟master值是否一致

5、show slave status能看到哪些信息(比较重要)
IO线程的状态信息
master服务器的IP地址、端口、事务开始的位置
最近一次的错误信息和错误位置
最近一次的I/O报错信息和ID
最近一次的SQL报错信息和id

6、主从复制慢(延迟)会有哪些可能?怎么解决?
主服务器的负载过大,被多个睡眠或 僵尸线程占用  导致系统负载过大,从库硬件比主库差,导致复制延迟
主从复制单线程,如果主库写作并发太大,来不及传送到从库,就会到导致延迟
慢sql语句过多
网络延迟
 

;