【Mysql】主从复制和读写分离
一、定义
1、什么是读写分离?
在主库master上负责处理事务性写入操作,在从库slave上负责处理查询操作,并通过主从复制将主库上的数据同步给从库。
2、为什么要读写分离?
从集中到分布,最基本的一个需求不是数据存储的瓶颈,而是在于计算的瓶颈,即SQL查询的瓶颈。我们知道,一般情况下,数据库的一次写操作几十个毫秒的时间内就能完成,而有的读操作则可能要几秒到几分钟才能有结果,很多复杂的 SQL,其消耗服器 CPU 的能力超强,不亚于死循环的威力。
所以读写分离,解决的是,数据库的写入和查询之间的性能影响 。
3、什么时候需要读写分离?
数据库不一定要读写分离,如果程序使用数据库较多时,且更新少,查询多的情况下会考虑使用。利用数据库主从同步,再通过读写分离可以分担数据库压力,提高性能。
4、主从复制和读写分离
主从复制用于将主数据库事务性操作的变更同步到集群中的从数据库。在实际的生产环境中,对数据库的读和写都在同一个数据库服务器中,是不能满足实际需求的。无论是在安全性、高可用性还是高并发等各个方面都是完全不能满足实际需求的。因此,通过主从复制的方式来同步数据,再通过读写分离来提升数据库的并发负载能力。有点类似于rsync,但是不同的是rsync是对磁盘文件做备份,而mysql主从复制是对数据库中的数据、语句做备份。
5、读写分离的作用
通过读写分离可以分担数据库单节点的负载压力,还可避免读写操作相互阻塞,从而提高数据库的读写性能。
6、主从复制的作用
实现读写分离、跨主机热备份数据、作为数据库高可用的基础。
二、mysql主从复制的类型
1、基于SQL语句的复制(statement)
优点:执行效率高,磁盘占用空间小,IO性能消耗低。
缺点:无法保证在高并发高负载时候的主从复制精确度
2、基于行的复制(row)
优点:记录最详细,精确度最高。
缺点:磁盘占用空间大,IO性能消耗高
3、混合类型的复制(mixed)
默认采用基于SQL语句的复制,一旦发现基于语句无法保证复制的精确度时,就会采用基于行的复制
三、主从复制的原理
(关键词:两个日志 二进制日志(bin log)、中继日志(relay log),三个线程 IO线程 SQL线程 DUMP线程)
1、主库master如果发生数据更新,会将写入操作记录到自己的二进制日志中
2、从库slave探测到主库的二进制日志发生了更新,就会开启IO线程向主库请求二进制日志事件
3、主库会为每个从库的IO线程请求开启DUMP线程,并发送二进制日志事件给从库
4、从库接收到二进制日志事件后会保存到自己的中继日志中
5、从库开启SQL线程读取中继日志中的事件,并在本地进行重放(将事件解析成SQL语句逐一执行),从而实现从库和从库的数据一致
四、mysql主从复制的同步模式
1、异步复制
主库在执行完客户端提交的事务后就会立即响应给客户端,不关心从库是否完成复制。
2、半同步复制
主库在执行完客户端提交的事务后,需要等待至少一个从库返回响应给主库,才会响应给客户端。
3、全同步复制
主库在执行完客户端提交的事务后,需要等待所有从库返回响应给主库,才会响应给客户端。
五、主从复制中会遇到的问题
1、在什么情况下半同步复制会降为异步复制?
当主库在半同步复制超时时间内没有收到从库的响应,就会降为异步复制,半同步复制超时参数为 rpl_semi_sync_master_timeout(默认值为10s)
当主库发送完一个事务事件后,主库在半同步复制超时时间范围内收到了从库的响应,就会恢复为半同步复制
在半同步复制模式下,主库会开启 ACK Collector 线程(简称ACK线程)专门用来接收从库返回的响应消息。
2、mysql主从复制延迟问题
原因:主库可以并发多线执行写入操作,而从库的SQL线程默认是单线程串行化复制,从库的复制效率可能会跟不上主库的写入速度
3、如何判断是否发生主从复制延迟?
可通过在从库执行show slave status命令,查看输出参数Seconds_Behind_Master的值是否为0,来判断是否方法是了主从复制延迟。
(1)如果为NULL,表示IO或SQL线程有问题。
(2)如果为0,表示没有出现复制延迟。
(3)如果为正值,表示已经出现主从复制延迟,数值越大代表从库落后主库越多。
4、导致主从复制延迟有哪些因素?
(1)主库写入操作并发量太大,事务数太多
(2)网络延迟
(3)从库硬件比主库相差太大
(4)使用了全同步复制
(5)事务太大,慢SQL语句太多
5、延迟问题的解决
(1)网络优化:将从库分布在与主库相同的局域网或网络延迟较小的环境中,尽量避免跨机房
(2)硬件优化:升级从库的硬件配置。使用更高的CPU、更大的内存,使用固态硬盘或采用RAID10提升硬盘的读写性能
(3)操作优化:将大事务拆分成多个较小的事务执行;优化一些SQL语句操作,比如可以将多个DDL或DML操作合并到一个SQL语句中批量执行;创建索引,避免全表扫描,出现锁表阻塞
(4)架构优化:主从复制的同步模式采用 半同步复制 或 异步复制。使用读写分离来避免读写操作相互阻塞
(5)配置优化:
innodb_buffer_pool_size #加大InnoDB存储引擎的缓存池大小,减少对磁盘的访问,设置为系统总内存的70%-80%
innodb_log_file_size #加大InnoDB的重做日志文件大小,减少日志刷新次数
innodb_log_buffer_size #加大InnoDB的重做日志的缓存大小,减少对磁盘的访问
innodb_flush_log_at_trx_commit = 1 #双1设置,设置InnoDB的重做日志和二进制日志的刷盘策略,每提交一次事务就刷入硬盘,可提高数据写入的安全性,但可能影响性能
sync_binlog = 1 #可在主库配置双1设置,保证数据安全;在从库设置为2或0,提升性能
slave_parallel_workers #在从库使用多线程并行复制
log-slave-updates = 0 #在从库让主从复制的数据不记录到二进制日志,减少对磁盘的访问
max_connections = 1000 #增加最大连接数,避免在用户访问高峰期出现数据库连接错误
6、mysql主从复制不一致问题如何解决?
(1)从库停止同步
(2)在主库使用 mysqldump 命令对数据库进行完全备份,并使用 show master status 查看当前的二进制日志文件和位置
(3)在从库使用完全备份的文件进行数据恢复
(4)在从库使用 change master 命令重新进行主从复制对接,并开启同步
stop slave;
mysqldump -u 用户 -p密码 --all-databases --single-transaction --master-data=2 > XXX.sql
show master status;
mysql -u 用户 -p密码 < XXX.sql
reset slave;
#开启GTID模式的配置
change master to master_host='主库IP', master_port=端口, master_user='用户',master_password='密码', master_log_file='二进制日志文件名', master_log_pos=文件位置;
change master to master_host='主库IP', master_port=端口, master_user='用户',master_password='密码',master_auto_position = 1;
start slave;