MySQL主从复制与读写分离( 主从复制原理 、读写分离原理 、配置 MySQL 主从复制 、配置 MySQL 读写分离)

一、 MySQL主从复制与读写分离简介

在实际的生产环境中,如果对数据库的读和写都在同一个数据库服务器中操作,无论是在安全性、高可用性还是高并发等各个方面都是完全不能满足实际需求的。因此,一般来说 都是通过主从复制(Master-Slave)来同步数据,再通过读写分离来提升数据库并发负载能力的方案来进行部署与实施。

MySQL数据库自身提供的主从复制功能可以方便的实现数据的多处自动备份,实现数据库的拓展。多个数据备份不仅可以加强数据的安全性,通过实现读写分离还能进一步提升数据库的负载性能。

如图所示,一台主 MySQL 服务器带两台从 MySQL 服务器做数据复制,前端应用在进行数据库写操作时,对主服务器进行操作,在进行数据库读操作时,对两台从服务器进行操作,这样大量减轻了对主服务器的压力。

二、 MySQL主从复制原理

MySQL 的主从复制和 MySQL 的读写分离两者有着紧密联系,首先要部署主从复制,只有主从复制完成了,才能在此基础上进行数据的读写分离。

2.1 MySQL 支持的复制类型
基于语句的复制。在主服务器上执行的 SQL 语句,在从服务器上执行同样的语句。MySQL 默认采用基于语句的复制,效率比较高。
基于行的复制。把改变的内容复制过去,而不是把命令在从服务器上执行一遍。
混合类型的复制。默认采用基于语句的复制,一旦发现基于语句无法精确复制时,就会采用基于行的复制。
全局事务标识符 GTID(Global Transaction Identifier,GTID)
基于SQL语句的方式是最直接的方式,也是目前默认的复制方式,后来的三种是MySQL 5以后才出现的复制方式。

2.2 MySQL复制的工作过程

在这里插入图片描述

 1、在每个事务更新数据完成之前,Master 将这些改变记录进二进制日志。写入二进制日志完成后,Master 通知存储引擎提交事务。

2、Slave 将 Master 的 Binary log 复制到其中继日志(Relay log)。首先,Slave 开始一个工作线程——I/O 线程,I/O 线程在 Master 上打开一个普通的连接,然后开始 Binlog dump process。Binlog dump process 从 Master 的二进制日志中读取事件,如果已经跟上 Master,它会睡眠并等待 Master 产生新的事件。I/O 线程将这些事件写入中继日志。

3、SQLslave thread(SQL 从线程)处理该过程的最后一步。SQL 线程从中继日志读取事件,并重放其中的事件而更新 Slave 数据,使其与 Master 中的数据保持一致。只要该线程与 I/O 线程保持一致,中继日志通常会位于 OS 的缓存中,所以中继日志的开销很小。 复制过程有一个很重要的限制,即复制在 Slave 上是串行化的,也就是说 Master 上的并行更新操作不能在 Slave 上并行操作。

三、 配置MySQL主从复制

 MySQL主服务器设置

[root@master ~]# vim /etc/my.cnf
server-id=1               ##主从ID号不能相同
log-bin=master-bin        ##主服务器日志文件
log-slave-updates=true    ##从服务器更新二进制文件


[root@master ~]# systemctl restart mysqld

为从服务器创建一个账户,便于从服务器从主服务器进行日志同步

[root@master ~]# mysql -uroot -p
mysql> grant all on *.* to 'slave'@'%' identified by '123456';
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements
##这个报错是说您的密码不符合当前策略要求我们修改密码策略和长度就可以,下面是修改方法

mysql> set global validate_password_policy=0;

mysql> set global validate_password_length=1;

mysql> grant all on *.* to 'slave'@'%' identified by '123456';

mysql> show master status;
+-------------------+----------+--------------+------------------+-------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------+-------------------+
| master-bin.000001 |      435 |              |                  |                   |
+-------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

从服务器设置

[root@slave ~]# vim /etc/my.cnf
server-id=2
relay-log=relay-log-bin                  ##从主服务器上同步日志文件记录到本地
relay-log-index=slave-relay-bin-index    ##定义relay-log的位置和名称
read-only=1                              ##是否只读,1 代表只读, 0 代表读写
#super-read-only=1                       ##将超管也设置为只读,看自身情况设置


[root@slave ~]# systemctl restart mysqld

[root@slave ~]# mysql -uroot -p
mysql> change master to master_host='192.168.100.2',master_user='slave',master_password='123456',master_log_file='master-bin.000001',master_log_pos=435;

mysql> start slave;

mysql> show slave status\G;

参数说明

master_host:主数据库的IP地址;
master_port:主数据库的运行端口;
master_user:在主数据库创建的用于同步数据的用户账号;
master_password:在主数据库创建的用于同步数据的用户密码;
master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取File参数;
master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取Position参数;
master_connect_retry:连接失败重试的时间间隔,单位为秒。

 

测试主从同步

在主服务器创建一个数据库看看是否可以同步到从服务器上

主
mysql> create database aaa;
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| aaa                |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+


从
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| aaa                |
| abc                |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+

MySQL读写分离原理

读写分离就是只在主服务器上写,只在从服务器上读。基本的原理是让主数据库处理事务性查询,而从数据库处理 select 查询。数据库复制被用来把主数据库上事务性查询导致的变更同步到集群中的从数据库。

在这里插入图片描述

目前较为常见的 MySQL 读写分离分为两种。

1、基于程序代码内部实现
在代码中根据 select、 insert 进行路由分类,这类方法也是目前生产环境应用最广泛的。
优点是性能较好,因为在程序代码中实现,不需要增加额外的设备作为硬件开支;
缺点是需要开发人员来实现,运维人员无从下手。

2、基于中间代理层实现
代理一般位于客户端和服务器之间,代理服务器接到客户端请求后通过判断后转发到后端数据库,有两个代表性程序。

  MySQL-Proxy。MySQL-Proxy 为 MySQL 开源项目,通过其自带的 lua 脚本进行 SQL 判断,虽  然是 MySQL 官方产品,但是 MySQL 官方并不建议将 MySQL-Proxy 用到生产环境。

  Amoeba。 Java 语言开发,阿里巴巴将其用于生产环境。它不支持事务和存储过程。

通过程序代码实现 MySQL 读写分离自然是一个不错的选择,但是并不是所有的应用都适合在程序代码中实现读写分离,像一些大型复杂的 Java 应用,如果在程序代码中实现读写分离对代码改动就较大。

五、 搭建MySQL读写分离

Amoeba(变形虫)项目开源框架于 2008 年发布一款 AmoebaforMySQL 软件。这个软件致力于 MySQL 的分布式数据库前端代理层,它主要为应用层访问 MySQL 的时候充当 SQL 路由功能,并具有负载均衡、高可用性、SQL 过滤、读写分离、可路由到相关的目标 数据库、可并发请求多台数据库。通过 Amoeba 能够完成多数据源的高可用、负载均衡、 数据切片的功能。

在主机 Amoeba 上安装 Java 环境

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

[root@amoeba ~]# yum -y remove java
[root@amoeba ~]# tar zxvf jdk-8u351-linux-x64.tar.gz 
[root@amoeba ~]# mv jdk1.8.0_351/ /usr/local/java 
[root@amoeba ~]# vim  /etc/profile
export JAVA_HOME=/usr/local/java
export JRE_HOME=/usr/local/java/jre
export AMOEBA_HOME=/usr/local/amoeba
export PATH=$PATH:$JAVA_HOME/bin:$AMOEBA_HOME/bin
export CLASSPATH=./:/local/java/lib:/usr/local/java/jre/lib

[root@amoeba ~]# source /etc/profile

[root@amoeba ~]# java -version

安装amoeba

下载amoeba
[root@amoeba ~]# wget https://jaist.dl.sourceforge.net/project/amoeba/Amoeba%20for%20mysql/3.x/amoeba-mysql-3.0.5-RC-distribution.zip
[root@amoeba ~]# unzip amoeba-mysql-3.0.5-RC-distribution.zip
[root@amoeba ~]# mv amoeba-mysql-3.0.5-RC /usr/local/amoeba
[root@amoeba ~]# chmod 755 /usr/local/amoeba/ -R

[root@amoeba ~]# vim /usr/local/amoeba/jvm.properties 
JVM_OPTIONS="-server -Xms1024m -Xmx1024m -Xss256k"

[root@amoeba ~]# /usr/local/amoeba/bin/launcher
[root@amoeba ~]# netstat -anptu | grep 8066

配置授权用户

主服务器:配置写权限

mysql> grant all on *.* to 'amoeba'@'192.168.100.%' identified by '123456'; 
mysql> flush privileges;

查看
mysql> show grants for amoeba@'192.168.100.%';

配置amoeba配置文件

[root@amoeba ~]# vim /usr/local/amoeba/conf/amoeba.xml

 

 

 配置数据库服务配置文件

[root@amoeba ~]# vim /usr/local/amoeba/conf/dbServers.xml

 

配置文件修改完成后,重新启动Amoeba,并查看状态

[root@amoeba ~]# kill -9 9280
[root@amoeba ~]# /usr/local/amoeba/bin/launcher  &
[root@amoeba ~]# netstat -anptu | grep 8066

客户机上的测试

[root@server2 ~]# yum -y install mariadb*
[root@server2 ~]# systemctl start mariadb
[root@server2 ~]# mysql -uamoeba -p123456 -h 192.168.100.6 -P8066

#通过amoeba登录数据库 -u用户名 -p密码 -h 访问地址为amoeba服务器 -P amoeba端口号

主从同步验证

在主服务器上新建test数据库和表tt

mysql> create database test;
Query OK, 1 row affected (0.01 sec)
mysql> use test
Database changed
mysql> create table tt(name char(10), id int(3) primary key auto_increment);
Query OK, 0 rows affected (0.02 sec)
mysql> desc tt;
+-------+----------+------+-----+---------+----------------+
| Field | Type     | Null | Key | Default | Extra          |
+-------+----------+------+-----+---------+----------------+
| name  | char(10) | YES  |     | NULL    |                |
| id    | int(3)   | NO   | PRI | NULL    | auto_increment |
+-------+----------+------+-----+---------+----------------+

在从服务器上都可查看到test和表tt(主从复制的效果)

mysql> use test;
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 |
+----------------+
| tt             |
+----------------+
1 row in set (0.00 sec)

关闭从服务器的从状态

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

在客户端进行写入操作:
客户端:也无法查看,只能写入主服务器

MySQL [(none)]> insert into test.tt values('a',1);
Query OK, 1 row affected (0.02 sec)

MySQL [(none)]> select * from test.tt;
ERROR 1146 (42S02): Table 'test.tt' doesn't exist

只能在主服务器查看,从服务器无法查看
主服务器:

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

从服务器:

mysql> select * from test.tt;
ERROR 1146 (42S02): Table 'test.tt' doesn't exist

在从服务器上写入数据
slave1:

mysql> insert into tt values('bb',2);
Query OK, 1 row affected (0.01 sec)
#从服务器上可以查看
mysql> select * from tt;
+------+----+
| name | id |
+------+----+
| bb   |  2 |
+------+----+

slave2:

mysql> select * from test.tt;
+------+----+
| name | id |
+------+----+
| aa   |  1 |
| cc   |  3 |
+------+----+

客户端可以轮流读取到从服务器的数据

在这里插入图片描述

 而主服务器上不会存储从服务器的数据,依旧是从客户端写入的数据。

mysql> select * from tt;
+------+----+
| name | id |
+------+----+
| a    |  1 |
+------+----+

实现了读写分离。

开启主从同步之后,主服务器上写入的数据同步到从服务器,客户端也能读取主服务器数据了,但从服务器上的数据不会到主服务器上。

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

mysql> select * from test.tt;
+------+----+
| name | id |
+------+----+
| a    |  1 |
+------+----+
1 row in set (0.01 sec)

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笨鸟先飞geigeigei

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值