一、概念
1、什么是读写分离
读写分离,基本的原理是让主数据库处理事务性增、改、删操作( INSERT、UPDATE、DELETE) ,而从数据库处理
SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。
2、读写分离的原因
因为数据库的“写”(写10000条数据可能要3分钟)操作是比较耗时的。
但是数据库的“读”(读10000条数据可能只要5秒钟)。
所以读写分离,解决的是,数据库的写入,影响了查询的效率。
3、在什么时候需要读写分离
数据库不一定要读写分离,如果程序使用数据库较多时,而更新少,查询多的情况下会考虑使用。利用数据库主从
同步,再通过读写分离可以分担数据库压力,提高性能。
4、主从复制与读写分离
在实际的生产环境中,对数据库的读和写都在同一个数据库服务器中,是不能满足实际需求的。无论是在安全性、
高可用性还是高并发等各个方面都是完全不能满足实际需求的。
因此,通过主从复制的方式来同步数据,再通过读写分离来提升数据库的并发负载能力。有点类似于rsync(文件
同步工具),但是不同的是rsync是对磁盘文件做备份,而mysql主从复制是对数据库中的数据、语句做备份。
5、主从复制的过程
- 主节点负责用户的写操作,用户发起写操作后,会修改数据库
- 数据库修改后,会更新主节点上的二进制日志
- 主服务器会产生一个dump线程,一边读取二进制日志一边将二进制日志通过网络传给从服务器
- 从服务器会开启io线程,接受主服务器的二进制日志
- 如果数据量较大,不会存在内存中,会写入中继日志,这时只是生成文件,并没有同步
- 从服务器再开启sql 线程将 中继日志中操作写入数据库完成更新
6、mysql从服务器挂了,恢复后如何保证数据同步
- 物理方法: rsync 磁盘文件同步。 使用文件恢复,主节点需要停服务。
- 主从复制: 将从节点原有库删除,通过偏移量,重新做一次主从复制
7、半同步复制什么情况下会降为异步复制,什么时候又会恢复同步复制?
-
当半同步复制发生超时(由rpl_semi_sync_master_timeout 参数控制,默认为10000ms, 即10s),会暂时
-
关闭半同步复制,转而使用异步复制,也就是会自动降为异步工作。
-
当malster dump 线程发送完一个事务的所有事件之后,如果在rpl_ semi_sync_master_ timeout 内,收到了
从库的响应,则主从又重新恢复为半同步复制。
二、MySQL主从复制延迟原因和优化方法
1、主从复制延迟
- master服务器高并发,形成大量事务。
- 网络延迟。
- 主从硬件设备导致(cpu主频、内存IO、硬盘IO)。
- 是同步复制,而不是异步复制。
2、优化方法
- 从库优化Mysql参数。比如增大innodb_buffer_pool_size,让更多操作在Mysql内存中完成,减少磁盘操作。
- 从库使用高性能主机。包括cpu强悍、内存加大。避免使用虚拟云主机,使用物理主机,这样提升了I/O方面性。
- 从库使用SSD磁盘。
- 网络优化,避免跨机房实现同步。
三、MySQL主从复制同步模式
1、异步复制(Asynchronous replication)
MySQL默认的复制即是异步的,主库在执行完客户端提交的事务后会立即将结果返给客户端,并不关心从库是否
已经接收并处理,这样就会有一个问题,主如果crash掉了,此时主上已经提交的事务可能并没有传到从上,如果
此时,强行将从提升为主,可能导致新主上的数据不完整。
2、全同步复制(Fully synchronous replication)
指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。因为需要等待所有从库执行完该事务才能
返回,所以全同步复制的性能必然会收到严重的影响。
3、半同步复制(Semisynchronous replication)
介于异步复制和全同步复制之间,主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从
库接收到并写到relay log中才返回给客户端。相对于异步复制,半同步复制提高了数据的安全性,同时它也造成了
一定程度的延迟,这个延迟最少是一个TCP/IP往返的时间。所以,半同步复制最好在低延时的网络中使用。
四、主从复制实战(异步复制)
实验环境:
Master:192.168.10.130
Slave1:192.168.10.132
Slave2:192.168.10.133
实验思路:
-
配置主服务器,修改其配置文件,在主数据库中创建一个同步账号授权给从数据库使用。
-
配置从数据库,修改其配置文件,在从数据库中配置同步。
-
验证能否同步成功
实验图示:
实验步骤:
1、主服务器的mysql配置
Master:192.168.10.130
[root@Master ~]#vim /etc/my.cnf
[mysqld]
server_id=130 #指定服务ID号,master和两台slave都要不同
log-bin=/data/mysql/mysql-bin #添加,主服务器开启二进制日志
[root@Master ~]#mkdir /data/mysql -p #建立文件夹
[root@Master ~]#chown -R mysql.mysql /data/ #注意修改权限
[root@Master ~]#systemctl restart mysqld #重启服务
[root@Master ~]#mysql -uroot -pAdmin@123 #进入数据库
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 | 154 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
mysql> grant replication slave on *.* to test@'192.168.10.%' identified by 'Admin@123'; #建立复制用户,给从服务器授权
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> flush privileges; #刷新权限
Query OK, 0 rows affected (0.00 sec)
2、从服务器的mysql配置
Slave1:192.168.10.132
Slave2:192.168.10.133
[root@Slave1 ~]#vim /etc/my.cnf
[mysqld]
server_id=132 #修改,注意id与Master的不同,两个Slave的id也要不同
log-bin=/data/mysql/mysql-bin #从服务器开启二进制日志
relay-log=relay-log-bin #开启中继日志,从主服务器上同步日志文件记录到本地
relay-log-index=slave-relay-bin.index #定义中继日志索引文件的位置和名称,一般和relay-log在同一目录
[root@Slave1 ~]#mkdir /data/mysql -p #建立文件夹
[root@Slave1 ~]#chown mysql.mysql /data/ -R #修改权限
[root@Slave1 ~]#systemctl restart mysqld #重启服务
[root@Slave1 ~]#mysql -uroot -pAdmin@123 #进入数据库
CHANGE MASTER TO
MASTER_HOST='192.168.10.130',
MASTER_USER='test',
MASTER_PASSWORD='Admin@123',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000003',
MASTER_LOG_POS=154;
mysql> start slave; #启动同步
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G #查看slave状态
Slave2 服务器也是同样配置,注意配置文件中 server-id 要和前面两台不同,我这里设置为 server-id =133。
3、验证主从复制
五、主从复制实例(半同步复制)
实验环境:
Master:192.168.10.130
Slave1:192.168.10.132
Slave2:192.168.10.133
实验操作:
-------1、所有服务器关闭防火墙------
systemctl disable --now firewalld
setenforce 0
-------2、主数据库配置---------
vim /etc/my.cnf #在 [mysqld] 区域添加下面内容
......
plugin-load=rpl_semi_sync_master=semisync_master.so #加载mysql半同步复制的插件
rpl_semi_sync_master_enabled=ON #或者设置为"1",即开启半同步复制功能
rpl-semi-sync-master-timeout=1000 #超时时间为1000ms,即1s
systemctl restart mysqld
-------3、从数据库配置-----------
vim /etc/my.cnf
......
plugin-load=rpl_semi_sync_slave=semisync_slave.so
rpl_semi_sync_slave_enabled=ON
systemctl restart mysqld
-------4、查看半同步是否在运行---------------
#主数据库执行
show status like 'Rpl_semi_sync_master_status';
show variables like 'rpl_semi_sync_master_timeout';
#从数据库执行(此时可能还是OFF状态,需要在下一步重启IO线程后,从库半同步状态才会为ON)
show status like 'Rpl_semi_sync_slave_status';
#重启从数据库上的IO线程
STOP SLAVE IO_THREAD;
START SLAVE IO_THREAD;
#在主库查询半同步状态
show status like '%Rpl_semi%';
参数说明:
Rpl_semi_sync_master_clients #半同步复制客户端的个数
Rpl_semi_sync_master_net_avg_wait_time #平均等待时间(默认毫秒)
Rpl_semi_sync_master_net_wait_time #总共等待时间
Rpl_semi_sync_master_net_waits #等待次数
Rpl_semi_sync_master_no_times #关闭半同步复制的次数
Rpl_semi_sync_master_no_tx #表示没有成功接收slave提交的次数
Rpl_semi_sync_master_status #表示当前是异步模式还是半同步模式,on为半同步
Rpl_semi_sync_master_timefunc_failures #调用时间函数失败的次数
Rpl_semi_sync_master_tx_avg_wait_time #事物的平均传输时间
Rpl_semi_sync_master_tx_wait_time #事物的总共传输时间
Rpl_semi_sync_master_tx_waits #事物等待次数
Rpl_semi_sync_master_wait_pos_backtraverse #可以理解为"后来的先到了,而先来的还没有到的次数"
Rpl_semi_sync_master_wait_sessions #当前有多少个session因为slave的回复而造成等待
Rpl_semi_sync_master_yes_tx #成功接受到slave事物回复的次数
当半同步复制发生超时(由rpl_semi_sync_master_timeout参数控制,默认为10000ms,即10s),会暂时关闭半同步复制,转而使用异步复制,也就是会自动降为异步工作。
当 master dump 线程发送完一个事务的所有事件之后,如果在 rpl_semi_sync_master_timeout 内,收到了从库的响应, 则主从又重新恢复为半同步复制。
六、MySQL读写分离
1、MySQL读写分离原理
- 读写分离就是只在主服务器上写,只在从服务器上读。
- 基本的原理是让主数据库处理事务性操作,而从数据库处理select查询。
- 数据库复制被用来把主数据库上事务性操作导致的变更,同步到集群中的从数据库。
2、读写分离类型
基于程序代码内部实现
在代码中根据 select、insert 进行路由分类,这类方法也是目前生产环境应用最广泛的。
优点是性能较好,因为在程序代码中实现,不需要增加额外的设备为硬件开支。
缺点是需要开发人员来实现,运维人员无从下手。
但是并不是所有的应用都适合在程序代码中实现读写分离,像一些大型复杂的Java应用,如果在程序代码中实现读写分离对代码改动就较大。
基于中间代理层实现
MySQL-Proxy。MySQL-Proxy 为 MySQL 开源项目,通过其自带的 lua 脚本进行SQL 判断。
Atlas。是由奇虎360的Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目。它是在
mysql-proxy 0.8.2版本的基础上,对其进行了优化,增加了一些新的功能特性。360内部使用Atlas运行的mysql业
务,每天承载的读写请求数达几十亿条。支持事物以及存储过程。
Amoeba。由陈思儒开发,作者曾就职于阿里巴巴。该程序由Java语言进行开发,阿里巴巴将其用于生产环境。但
是它不支持事务和存储过程。