MySQL主从复制and读写分离

目录

前言

一、主从复制

1、什么是读写分离

2、为什么要读写分离呢

3、什么时候要读写分离

4、主从复制与读写分离

5、mysq支持的复制类型

6、主从复制的工作过程

7、主从复制的优点

二、MySQL有四种同步方式:

1、异步复制(Async Replication)

2、同步复制(Sync Replication)

3、半同步复制(Semi-Sync Replication)

4、增强半同步复制(lossless Semi-Sync Replication、无损复制)

三、主从复制高延迟

1、原因

2、解决方案

四、读写分离

1、基于程序代码内部实现

2、基于中间代理层实现

五、MySQL主从搭建

1、配置说明

 2、关闭防火墙和增强机制

3、主从服务器时间同步

3.2 Slave1服务器

3.3Slave2服务器

4、主服务器配置

5、从服务器配置

5.1Slave1

5.2Slave2

6、验证主从复制效果

六、读写分离

1、amoeba 服务器软件安装

1.1安装Java环境

1.2安装Amoeba软件

2、配置 amoeba 读写分离,两个 slave 读负载均衡

3、客户端测试

 3.1客户端建表

3.2关闭Slave功能后在主从服务器插入数据

3.3关闭Slave功能后,客户端服务器写入数据

3.4从服务器开启Slave服务

3.5客户端再次插入数据

 七、问题整理

1、主从同步原理

2、如何查看主从同步状态是否成功

3、如果I/O和SQL不是yes呢,你是如何排查的

4、show slave status能看到哪些信息(比较重要的)

5、主从复制慢(延迟)有哪些可能

总结


前言

MySQL主从复制(MySQL Replication)是指从一个MySQL主服务器(master)将数据拷贝到另一台或多台MySQL从服务器(slaves)的过程。将主数据库的DDL和DML操作通过二进制日志(binlog)传到从服务器(slave)上,然后在从服务器上对这些日志重新执行,从而使得主从服务器的数据保持同步。 MySQL从3.23版本开始提供复制的功能。

在企业应用中,成熟的业务通常数据量都比较大,单台MySQL在安全性、高可用性和高并发方面都无法满足实际的需求,配置多台主从数据库服务器以实现读写分离。

一、主从复制

1、什么是读写分离

读写分离,基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。

2、为什么要读写分离呢

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

3、什么时候要读写分离

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

4、主从复制与读写分离

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

5、mysq支持的复制类型

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

6、主从复制的工作过程

  1. Master节点将数据的改变记录成二进制日志(Binary log),当Master上的数据发生改变时,则将其改变写入二进制日志中。
  2. Slave节点会在一定时间间隔内对Master的二进制日志进行探测其是否发生改变,如果发生改变,则开始一个I/O线程请求 Master的二进制事件。
  3. 同时Master节点为每个I/O线程启动一个dump线程,用于向其发送二进制事件,并保存至Slave节点本地的中继日志(Relay log)中,Slave节点将启动SQL线程从中继日志中读取二进制日志,在本地重放,即解析成 sql 语句逐一执行,使得其数据和 Master节点的保持一致,最后I/O线程和SQL线程将进入睡眠状态,等待下一次被唤醒。

具体流程如下图:

内容简化:Master将数据保存在二进制日志文件中,I/O thread 向dump thread发出同步请求,dump thread收到请求后将数据发送给I/O thread ,I/O会将数据写入到本地的Relay log中,SQL thread通过读取本地数据的Relay log中的数据,同步到自己的数据库中,至此完成数据同步

注:

  • 中继日志通常会位于 OS 缓存中,所以中继日志的开销很小。
  • 复制过程有一个很重要的限制,即复制在 Slave上是串行化的,也就是说 Master上的并行更新操作不能在 Slave上并行操作。

7、主从复制的优点

  1. 数据备份(Data Backup):只是简单的对数据库进行备份,降低数据丢失的风险,
  2. 线下统计:用于报表等对数据时效性要求不高的场合;
  3. 负载均衡(Load Balance)、读写分离:主要用在MySQL集群,解决单点故障或做故障切换;以降低单台服务器的负载和风险,如实现读写分离,可以使得服务器访问负荷比较均衡。
  4. 数据分发(Data DistributIOn)、灾备:主要用于多数据中心或异地备份,实现数据分发与同步。
  5. 高可用和数据容错(High Availability and Failover):MySQL自带的健康监控和检测,根据配置的时间间隔,可以检测主库是否正常工作,一旦发现主库宕机或无法正常工作,就会选择到最好的一个备库上。

二、MySQL有四种同步方式:

1、异步复制(Async Replication)

默认同步方式是异步复制。主库将更新写入Binlog日志文件后,不需要等待数据更新是否已经复制到从库中,就可以继续处理更多的请求。Master将事件写入binlog,但并不知道Slave是否或何时已经接收且已处理。在异步复制的机制的情况下,如果Master宕机,事务在Master上已提交,但很可能这些事务没有传到任何的Slave上。假设有Master->Salve故障转移的机制,此时Slave也可能会丢失事务。MySQL复制默认是异步复制,异步复制提供了最佳性能。

2、同步复制(Sync Replication)

主库将更新写入Binlog日志文件后,需要等待数据更新已经复制到从库中,并且已经在从库执行成功,然后才能返回继续处理其它的请求。同步复制提供了最佳安全性,保证数据安全,数据不会丢失,但对性能有一定的影响。

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)即是确认字符。

4、增强半同步复制(lossless Semi-Sync Replication、无损复制)

增强半同步是在MySQL 5.7引入,其实半同步可以看成是一个过渡功能,因为默认的配置就是增强半同步,所以,大家一般说的半同步复制其实就是增强的半同步复制,也就是无损复制。

增强半同步和半同步不同的是,等待ACK时间不同

rpl_semi_sync_master_wait_point = AFTER_SYNC(默认)

半同步的问题是因为等待ACK的点是Commit之后,此时Master已经完成数据变更,用户已经可以看到最新数据,当Binlog还未同步到Slave时,发生主从切换,那么此时从库是没有这个最新数据的,用户看到的是老数据。

增强半同步将等待ACK的点放在提交Commit之前,此时数据还未被提交,外界看不到数据变更,此时如果发送主从切换,新库依然还是老数据,不存在数据不一致的问题。

三、主从复制高延迟

1、原因

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

2、解决方案

  • 从库优化 Mysql 参数。比如增大 innodb_buffer_pool_size,让更多操作在 mysql 内存中完成,减少磁盘操作
  • 从库使用高性能主机(高性能 cpu、大内存),避免使用虚拟云主机,使用物理主机,提升 I/O 吞吐量
  • 从库使用 SSD 磁盘
  • 网络优化,避免跨机房实现同步
     

四、读写分离

读写分离就是只在主服务器上写,只在从服务器上读。基本的原理是让主数据库处理事务性操作,而从数据库处理 select 查询。数据库复制被用来把主数据库上事务性操作导致的变更同步到集群中的从数据库。目前较为常见的 MySQL 读写分离分为以下两种:


1、基于程序代码内部实现

在代码中根据 select、insert 进行路由分类,这类方法也是目前生产环境应用最广泛的。
优点是性能较好,因为在程序代码中实现,不需要增加额外的设备为硬件开支;缺点是需要开发人员来实现,运维人员无从下手。
但是并不是所有的应用都适合在程序代码中实现读写分离,像一些大型复杂的Java应用,如果在程序代码中实现读写分离对代码改动就较大。

2、基于中间代理层实现

代理一般位于客户端和服务器之间,代理服务器接到客户端请求后通过判断后转发到后端数据库,有以下代表性程序。

  1. MySQL-Proxy:MySQL-Proxy 为 MySQL 开源项目,通过其自带的 lua 脚本进行SQL 判断。
  2. Atlas:是由奇虎360的Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目。它是在mysql-proxy 0.8.2版本的基础上,对其进行了优化,增加了一些新的功能特性。360内部使用Atlas运行的mysql业务,每天承载的读写请求数达几十亿条。支持事物以及存储过程。
  3. Amoeba:由陈思儒开发,作者曾就职于阿里巴巴。该程序由Java语言进行开发,阿里巴巴将其用于生产环境。但是它不支持事务和存储过程。

由于使用MySQL Proxy 需要写大量的Lua脚本,这些Lua并不是现成的,而是需要自己去写。这对于并不熟悉MySQL Proxy 内置变量和MySQL Protocol 的人来说是非常困难的。
Amoeba是一个非常容易使用、可移植性非常强的软件。因此它在生产环境中被广泛应用于数据库的代理层。
 

五、MySQL主从搭建

1、配置说明

服务器主机名IP应用
Master 服务器master192.168.223.13mysql5.7
Slave1 服务器slave1192.168.223.33mysql5.7
Slave2 服务器slave2192.168.223.50mysql5.7

 2、关闭防火墙和增强机制

systemctl stop firewalld 
systemctl disable firewalld
setenforce 0

3、主从服务器时间同步

3.1Master服务器

yum -y install ntp

vim /etc/ntp.conf
#--末尾添加--
server 127.127.223.0							#设置本地是时钟源,注意修改自己的网段
fudge 127.127.223.0 stratum 8			    	#设置时间层级为 8(限制在 15 内)

service ntpd start

 

修改配置文件 vim /etc/ntp.conf

 

3.2 Slave1服务器

yum -y install ntp ntpdate

service ntpd start
/usr/sbin/ntpdate 192.168.10.20				#进行时间同步

crontab -e
*/30 * * * * /usr/sbin/ntpdate 192.168.10.20

 

 

3.3Slave2服务器

yum -y install ntp ntpdate

service ntpd start
/usr/sbin/ntpdate 192.168.223.13		#进行时间同步

crontab -e
*/30 * * * * /usr/sbin/ntpdate 192.168.223.13

4、主服务器配置

vim /etc/my.cnf
server-id = 1
log-bin=master-bin              #添加,主服务器开启二进制日志
log-slave-updates=true            #添加,允许从服务器更新二进制日志
binlog_format = MIXED
 
systemctl restart mysqld
 
mysql -u root -p
GRANT REPLICATION SLAVE ON *.* TO 'myslave'@'192.168.223.%' IDENTIFIED BY '123456';     
#给从服务器授权
FLUSH PRIVILEGES;
 
show master status;
 
#File 列显示日志名,Fosition 列显示偏移量

 

5、从服务器配置

5.1Slave1

vim /etc/my.cnf
server-id = 2                               #修改,注意id与Master的不同,两个Slave的id也要不同
relay-log=relay-log-bin                     #添加,开启中继日志,从主服务器上同步日志文件记录到本地
relay-log-index=slave-relay-bin.index       #添加,定义中继日志文件的位置和名称
relay_log_recovery = 1                       #选配项
#当 slave 从库宕机后,假如 relay-log 损坏了,导致一部分中继日志没有处理,则自动放弃所有未执行的 relay-log,并且重新从 master 上获取日志,这样就保证了relay-log 的完整性。默认情况下该功能是关闭的,将 relay_log_recovery 的值设置为 1 时, 可在 slave 从库上开启该功能,建议开启。
 
systemctl restart mysqld
 
mysql -u root -p
change master to master_host='192.168.223.10' , master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=604;
#配置同步,注意 master_log_file 和 master_log_pos 的值要与Master查询的一致,这里的是例子,每个人的都不一样
 
start slave;                        #启动同步,如有报错执行 reset slave;
show slave status\G                 #查看 Slave 状态
//确保 IO 和 SQL 线程都是 Yes,代表同步正常。
Slave_IO_Running: Yes               #负责与主机的io通信
Slave_SQL_Running: Yes              #负责自己的slave mysql进程

 

5.2Slave2

vim /etc/my.cnf
server-id = 3                               #修改,注意id与Master的不同,两个Slave的id也要不同
relay-log=relay-log-bin                     #添加,开启中继日志,从主服务器上同步日志文件记录到本地
relay-log-index=slave-relay-bin.index       #添加,定义中继日志文件的位置和名称
relay_log_recovery = 1                       #选配项
#当 slave 从库宕机后,假如 relay-log 损坏了,导致一部分中继日志没有处理,则自动放弃所有未执行的 relay-log,并且重新从 master 上获取日志,这样就保证了relay-log 的完整性。默认情况下该功能是关闭的,将 relay_log_recovery 的值设置为 1 时, 可在 slave 从库上开启该功能,建议开启。
 
systemctl restart mysqld
 
mysql -u root -p
change master to master_host='192.168.223.10' , master_user='myslave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=604;
#配置同步,注意 master_log_file 和 master_log_pos 的值要与Master查询的一致,这里的是例子,每个人的都不一样
 
start slave;                        #启动同步,如有报错执行 reset slave;
show slave status\G                 #查看 Slave 状态
//确保 IO 和 SQL 线程都是 Yes,代表同步正常。
Slave_IO_Running: Yes               #负责与主机的io通信
Slave_SQL_Running: Yes              #负责自己的slave mysql进程

 

6、验证主从复制效果

在Master上创建一个新的数据库,然后去Slave上查看是否进行同步复制

六、读写分离

1、amoeba 服务器软件安装

1.1安装Java环境

因为 amoeba 是基于 jdk1.5 开发的,所以官方推荐使用 jdk1.5 或 1.6 版本,高版本不建议使用

wget http://101.34.22.188/jdk1.6/jdk-6u14-linux-x64.bin -P /opt
cp -a /opt/jdk-6u14-linux-x64.bin /usr/local
chmod +x /usr/local/jdk-6u14-linux-x64.bin
cd /usr/local				#生成的 jdk 目录会在当前目录
./jdk-6u14-linux-x64.bin	#回车或按空格至用户选项,输入 yes 最后再回车
mv /usr/local/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 版本是不是 1.6,不是找找原因

1.2安装Amoeba软件

wget http://101.34.22.188/amoeba/amoeba-mysql-binary-2.2.0.tar.gz -P /opt/
mkdir /usr/local/amoeba
tar zxvf /opt/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 说明安装成功

2、配置 amoeba 读写分离,两个 slave 读负载均衡

在 master、slave1、slave2 的 mysql 上开放权限给 amoeba 访问

mysql> grant all on *.* to test@'192.168.223.%' identified by '123456';
mysql> select user,host,authentication_string from mysql.user;

 

amoeba 服务器配置 amoeba 服务

#修改配置文件前先做备份
cd /usr/local/amoeba/conf/
cp amoeba.xml amoeba.xml.bak
cp dbServers.xml dbServers.xml.bak


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


vim /usr/local/amoeba/conf/dbServers.xml	#修改数据库配置文件
#--23行--注释掉  作用:默认进入 test 库,以防 mysql 中没有 test 库时会报错
<!-- <property name="schema">test</property> -->
#--26--修改,使用之前创建的授权用户
<property name="user">test</property>
#--29--去掉注释,密码为之前创建的授权用户密码
<property name="password">123456</property>
#--45--修改,设置主服务器的名 master
<dbServer name="master"  parent="abstractServer">
#--48--修改,设置主服务器的地址
<property name="ipAddress">192.168.223.13</property>
#--52--修改,设置从服务器的名 slave1
<dbServer name="slave1"  parent="abstractServer">
#--55--修改,设置从服务器1的地址
<property name="ipAddress">192.168.223.33</property>
#--58--复制上面 6 行粘贴,设置从服务器 2 的名 slave2 和地址
<dbServer name="slave2"  parent="abstractServer">
<property name="ipAddress">192.168.223.50</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

 

 

 

3、客户端测试

客户端快速安装 mysql

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

 

 3.1客户端建表

客户端

#通过 amoeba 服务器代理访问 mysql,在通过客户端连接 mysql 后写入的数据只有主服务会记录,然后同步给从服务器
#这里通过 192.168.223.30 主机的 8066 端口使用用户 amoeba 登录 mysql
mysql -uamoeba -h 192.168.223.30 -P8066 -p
MySQL [(none)]> show databases;
MySQL [(none)]> use Fesitival
MySQL [Fesitival]> create table test(id int,name char(20));
MySQL [Fesitival]> show tables;

 

Master服务器

mysql> use Fesitival;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| test           |
+----------------+
1 row in set (0.00 sec)

Slave1服务器

mysql> use Fesitival;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| test           |
+----------------+
1 row in set (0.00 sec)

Slave2服务器

mysql> use Fesitival;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| test           |
+----------------+
1 row in set (0.00 sec)

测试结果:在客户端中做出修改,所有的服务器中都能看到操作

3.2关闭Slave功能后在主从服务器插入数据

Master服务器

mysql> insert into test1 values(1,'master');
Query OK, 1 row affected (0.01 sec)

mysql> select * from test1;
+------+--------+
| id   | name   |
+------+--------+
|    3 | master |
+------+--------+
1 row in set (0.00 sec)

Slave1服务器

mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test values(1,'slave1');
Query OK, 1 row affected (0.00 sec)

mysql> select * from test;
+------+--------+
| id   | name   |
+------+--------+
|    1 | slave1 |
+------+--------+
1 row in set (0.00 sec)

Slave2服务器

mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test values(2,'slave2');
Query OK, 1 row affected (0.01 sec)

mysql> select * from test;
+------+--------+
| id   | name   |
+------+--------+
|    2 | slave2 |
+------+--------+
1 row in set (0.00 sec)

客户机

MySQL [Fesitival]> select * from test1;
+------+--------+
| id   | name   |
+------+--------+
|    2 | slave2 |
+------+--------+
1 row in set (0.00 sec)

MySQL [Fesitival]> select * from test1;
+------+--------+
| id   | name   |
+------+--------+
|    1 | slave1 |
+------+--------+
1 row in set (0.00 sec)

测试结果:客户端在 slave1、slave2 中轮询查看数据。由于从服务器都关闭了 slave 功能,因此无法查看 master 服务器中的修改

3.3关闭Slave功能后,客户端服务器写入数据

客户端

MySQL [Fesitival]> insert into test values(4,'client1');
Query OK, 1 row affected (0.01 sec)

MySQL [Fesitival]> select * from test1;
+------+--------+
| id   | name   |
+------+--------+
|    2 | slave2 |
+------+--------+
1 row in set (0.01 sec)

MySQL [Fesitival]> select * from test1;
+------+--------+
| id   | name   |
+------+--------+
|    1 | slave1 |
+------+--------+
1 row in set (0.01 sec)

Master服务器

mysql> mysql> select * from test;
+------+---------+
| id   | name    |
+------+---------+
|    3 | master  |
|    4 | client1 |
+------+---------+
2 rows in set (0.00 sec)

 Slave1服务器

mysql> mysql> select * from test;
+------+---------+
| id   | name    |
+------+---------+
|    3 | master  |
|    4 | client1 |
+------+---------+
2 rows in set (0.00 sec)

Slave2

mysql> mysql> select * from test;
+------+--------+
| id   | name   |
+------+--------+
|    2 | slave2 |
+------+--------+
1 row in set (0.00 sec)

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

3.4从服务器开启Slave服务

Slave1 服务器

mysql> start slave;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from test;
+------+---------+
| id   | name    |
+------+---------+
|    1 | slave1  |
|    3 | master  |
|    4 | client1 |
+------+---------+
3 rows in set (0.00 sec)

Slave2 服务器

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test;
+------+---------+
| id   | name    |
+------+---------+
|    2 | slave2  |
|    3 | master  |
|    4 | client1 |
+------+---------+
3 rows in set (0.00 sec)

Master服务器

mysql> select * from test;
+------+---------+
| id   | name    |
+------+---------+
|    3 | master  |
|    4 | client1 |
+------+---------+
2 rows in set (0.00 sec)

客户端

MySQL [Fesitival]> select * from test1;
+------+---------+
| id   | name    |
+------+---------+
|    1 | slave1  |
|    3 | master  |
|    4 | client1 |
+------+---------+
3 rows in set (0.00 sec)

MySQL [Fesitival]> select * from test1;
+------+---------+
| id   | name    |
+------+---------+
|    2 | slave2  |
|    3 | master  |
|    4 | client1 |
+------+---------+
3 rows in set (0.00 sec)

测试结果:从服务器开启 slave 服务后可以从 master 服务器上获取更新,但是从服务器上的更新不会被 master 服务器看到 

3.5客户端再次插入数据

客户端

MySQL [Fesitival]> insert into test values(5,'client2');
Query OK, 1 row affected (0.01 sec)

MySQL [Fesitival]> select * from test;
+------+---------+
| id   | name    |
+------+---------+
|    1 | slave1  |
|    3 | master  |
|    4 | client1 |
|    5 | client2 |
+------+---------+
4 rows in set (0.00 sec)

MySQL [Fesitival]> select * from test;
+------+---------+
| id   | name    |
+------+---------+
|    2 | slave2  |
|    3 | master  |
|    4 | client1 |
|    5 | client2 |
+------+---------+
4 rows in set (0.01 sec)

Slave1 服务器

mysql> select * from test;
+------+---------+
| id   | name    |
+------+---------+
|    1 | slave1  |
|    3 | master  |
|    4 | client1 |
|    5 | client2 |
+------+---------+
4 rows in set (0.01 sec)

Slave2 服务器

mysql> select * from test;
+------+---------+
| id   | name    |
+------+---------+
|    2 | slave2  |
|    3 | master  |
|    4 | client1 |
|    5 | client2 |
+------+---------+
4 rows in set (0.00 sec)

Master服务器

mysql> select * from test;
+------+---------+
| id   | name    |
+------+---------+
|    3 | master  |
|    4 | client1 |
|    5 | client2 |
+------+---------+
3 rows in set (0.00 sec)

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

 七、问题整理

1、主从同步原理

  • 通过amoeba代理服务器,实现只在主服务器上写,只在从服务上读;
  • 主数据库处理事务性查询,从数据库处理 select 查询;
  • 数据库复制被用来把事务性查询导致的变更同步到集群中的从数据库

2、如何查看主从同步状态是否成功

  • 在从服务器内输入命令 show slave status\G,查看主从信息进行查看,里面有IO线程的状态信息,还有master服务器的IP地址、端口、事务开始号,
  • 当 slave_io_running 和 slave_sql_running 都显示为yes时,表示主从同步状态成功

3、如果I/O和SQL不是yes呢,你是如何排查的

  • 首先排除网络问题,使用ping命令查看从服务是否能与主服务器通信
  • 再者查看防火墙和核心防护是否关闭
  • 接着查看从服务器内的slave是否开启
  • 两个从服务器的 server-id 是否相同导致只能连上一台
  • master_log_file 和 master_log_pos 的值要是否与Master查询的一致

4、show slave status能看到哪些信息(比较重要的)

  • IO线程的状态信息
  • master服务器的IP地址、端口、事务开始位置
  • 最近一次的报错信息和报错位置等

5、主从复制慢(延迟)有哪些可能

  • 主服务器的负载过大,被多个睡眠或者僵尸线程占用,导致系统负载过大
  • 从库硬件比主库差,导致复制延迟
  • 主从复制单线程,如果主库写并发太大,来不及传送到从库,就会导致延迟。
  • 慢SQL语句过多
  • 网络延迟

总结

MySQL读写分离能提高系统性能的原因在于:

  1. ​物理服务器增加,机器处理能力提升。拿硬件换性能。
  2. ​主从只负责各自的读和写,极大程度缓解X锁和S锁争用。
  3. slave可以配置myiasm引擎,提升查询性能以及节约系统开销。
  4. master直接写是并发的,slave通过主库发送来的binlog恢复数据是异步。
  5. ​ slave可以单独设置一些参数来提升其读的性能。
  6. ​ 增加冗余,提高可用性。
     

常见的实现方式:

  1. Mysql-proxy:其为mysql的开源项目,通过其自带的lua脚本进行sql判断,虽然是mysql官方产品,但是mysql官方并不建议其使用到生产环境中。
  2. Amoeba:该程序由Java语言进行开发。这个软件致力于mysql的分布式数据库前端代理层,它主要为应用层访问mysql的时候充当sql路由功能。Amoeba能够完成多数据源的高可用、负载均衡、数据切片等功能。
  3. MyCat:MyCat是目前最流行的基于Java语言编写的数据库中间件,是一个实现了MySql协议的服务器,其核心功能是分库分表。配合数据库的主从模式还可以实现读写分离。
     
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值