MySQL面试 主从复制篇

问:Mysql主从原理

MySQL的主从复制是一个异步的复制过程,将一个MySQL数据库的数据复制到另一个MySQL库,在master与Slave之间实现整个主从复制的过程是有三个线程参与完成的。
(1)master服务器将数据的改变记录二进制binlog日志,当master上的数据发生改变时,则将其改变写入二进制日志中;
(2)slave服务器会在一定时间间隔内对master二进制日志进行探测其是否发生改变,如果发生改变,则开始一个I/OThread请求master二进制事件。
(3)同时主节点为每个I/O线程启动一个dump线程,用于向其发送二进制事件,并保存至从节点本地的中继日志中,从节点将启动SQL线程从中继日志中读取二进制日志,在本地重放,使得其数据和主节点的保持一致,最后I/OThread和SQLThread将进入睡眠状态,等待下一次被唤醒。

也就是说:
从库会生成两个线程,一个I/O线程,一个SQL线程;
I/O线程会去请求主库的binlog,并将得到的binlog写到本地的relay-log(中继日志)文件中;
主库会生成一个log dump线程,用来给从库I/O线程传binlog;
SQL线程,会读取relay log文件中的日志,并解析成sql语句逐一执行;
在这里插入图片描述

1、从库通过手工执行change master to 语句连接主库 start slave
2、从库的IO线程和主库的dump线程建立连接。
3、从库根据change master to 语句提供的file名和position号,IO线程向主库发起binlog的请求。
4、主库dump线程根据从库的请求,将本地binlog以events的方式发给从库IO线程。
5、从库IO线程接收binlog events,并存放到本地relay-log中,传送过来的信息,会记录到master.info中
6、从库SQL线程应用relay-log,并且把应用过的记录到relay-log.info中,默认情况下,已经应用过的relay 会自动被清理purge

问:MySQL主从复制有哪些策略

MySQL复制支持多种不同的复制策略,包括同步、半同步、异步和延迟策略等。
同步策略:Master要等待所有Slave应答之后才会提交(MySql对DB操作的提交通常是先对操作事件进行二进制日志文件写入然后再进行提交)。
半同步策略:Master等待至少一个Slave应答就可以提交。
异步策略:Master不需要等待Slave应答就可以提交。
延迟策略:Slave要至少落后Master指定的时间。

问:Mysql支持哪些复制类型

(1)基于语句的复制:在主服务器上执行的SQL语句,在从服务器上执行同样的语句。MySQL默认采用基于语句的复制,效率比较高。
 一旦发现没法精确复制时,会自动选择基于行的复制。
(2)基于行的复制:把改变的内容复制过去,而不是把命令在从服务器上执行一遍。从MySQL5.0开始支持。
(3)混合类型复制:默认采用基于语句的复制,一旦发现基于语句无法精确复制时,就会采用基于行的复制。

问:mysql异步主从复制存在的问题

主库宕机后,数据可能丢失
从库只有一个sql Thread,主库写压力大,复制很可能延时

解决方法:
半同步复制—解决数据丢失的问题
并行复制----解决从库复制延迟的问题
问:主从复制解决了哪些问题
数据分布(data distribution)
负载均衡(load balancing)
备份(backups)
高可用和容错行(high availability and failover)

问:什么是GTID主从复制

基于GTID的复制是从Mysql5.6开始支持的一种新的复制方式。此方式与传统基于日志的方式存在很大的差异,在原来的基于日志的复制中,从服务器连接到主服务器并告诉主服务器要从哪个二进制日志的偏移量开始执行增量同步,这时我们如果指定的日志偏移量不对,这与可能造成主从数据的不一致,而基于GTID的复制会避免。

在基于GTID的复制中,首先从服务器会告诉主服务器已经在从服务器执行完了哪些事务的GTID值,然后主库会有把所有没有在从库上执行的事务,发送到从库上进行执行,并且使用GTID的复制可以保证同一个事务只在指定的从库上执行一次,这样可以避免由于偏移量的问题造成数据不一致。

问:什么是GTID

也就是全局事务ID,保证为每一个在主库上提交的事务在复制集群中可以生成一个唯一的ID。

问:GTID有哪些组成部分

一个GITD由两部分组成的,分别是source_id 和transaction_id,GTID=source_id:transaction_id,其中source_id就是执行事务的主库的server-uuid值,server-uuid值是在mysql服务首次启动生成的,保存在数据库的数据目录中,在数据目录中有一个auto.conf文件,这个文件保存了server-uuid值(唯一的)。而事务ID则是从1开始自增的序列,表示这个事务是在主库上执行的第几个事务,Mysql会保证这个事务和GTID是一比一的关系。

问:GTID原理

1.当一个事务在主库端执行并提交时,产生GTID,一同记录到binlog日志中。
2.binlog传输到slave,并存储到slave的relaylog后,读取这个GTID的这个值设置gtid_next变量,即告诉Slave,下一个要执行的GTID值。
3.sql线程从relay log中获取GTID,然后对比slave端的binlog是否有该GTID。
4.如果有记录,说明该GTID的事务已经执行,slave会忽略。
5.如果没有记录,slave就会执行该GTID事务,并记录该GTID到自身的binlog, 在读取执行事务前会先检查其他session持有该GTID,确保不被重复执行。
6.在解析过程中会判断是否有主键,如果有就用二级索引,如果没有就用全部扫描。

问:具体是怎么配置GTID的

Master配置

[mysqld]
binlog-format=ROW
log-bin=master-bin

#从服务器更新同步二进制日志信息,适用于高可用中,从服务器升级主服务器用
log-slave-updates=true
# 开启GTID
gtid-mode=on

# 强制gtid一直性,用于保证启动gitd后事务的安全
enforce-gtid-consistency=true 

#指定中继日志的存储方式,默认是文件,这样配置是使用了 两个表,是INNODB存储引擎,好处是当出现数据库崩溃时,利用INNODE事务引擎的特点,对这两个表进行恢复,以保证从服务器可以从正确位置恢复数据。
master-info-repository=TABLE
relay-log-info-repository=TABLE

#同步master_info,任何事物提交以后都必须要把事务提交以后的二进制日志事件的位置对应的文件名称,记录到master_info中,下次启动自动读取,保证数据无丢失
sync-master-info=1

#设定从服务器的启动线程数,0表示不启动
slave-parallel-workers=2
#主服务端在启动的时候要不要校验bin-log本身的校验码
binlog-checksum=CRC32

#都是在服务器出现故障情况下,读取对服务器有用的数据
master-verify-checksum=1
slave-sql-verify-checksum=1
#启用后,可用于在二进制日志记录事件相关信息,可降低故障排除复杂度(并非强制启动)
binlog-rows-query-log_events=1

server-id=1

配置完成重启master;
Show master status;会多一项executed_gtid_set列
show global variables like '%uuid%'
show global variables like '%gtid%'

Slave配置

[mysqld]
#二进制日志的格式,有row、statement和mixed几种类型;需要注意的是:当设置隔离级别为READ-COMMITED必 须设置二进制日志格式为ROW,现在MySQL官方认为STATEMENT这个已经不再适合继续使用,但mixed类型在默认的事务隔离级别下,可能会导致主从数据不一致;
binlog-format=ROW 

#启动GTID及满足附属的其它需求
log-slave-updates=true
gtid-mode=on
enforce-gtid-consistency=true

#在崩溃时保证二进制及从服务器安全的功能;
master-info-repository=TABLE
relay-log-info-repository=TABLE 

#可确保无信息丢失
sync-master-info=1 

#设定从服务器的SQL线程数;0表示关闭多线程复制功能;
slave-parallel-workers=2  
binlog-checksum=CRC32
master-verify-checksum=1
slave-sql-verify-checksum=1
binlog-rows-query-log_events=1
server-id=11
read_only = on //这个参数主要保证从服务器的数据安全性

备份要同步的数据库

mysqldump --single-transaction --master-data=2 --triggers --routines --database testdb -uroot -p > testdb.sql

–master-data=2表示在dump过程中记录主库的binlog和pos点,并在dump文件中注释掉这一行;=1的时候不会注释。

–single-transaction参数的作用,设置事务的隔离级别为可重复读,即REPEATABLE READ,这样能保证在一个事务中所有相同的查询读取到同样的数据,也就大概保证了在dump期间,如果其他innodb引擎的线程修改了表的数据并提交,对该dump线程的数据并无影响,在这期间不会锁表。

导入备份库到从库

在主库创建用户

grant replication slave on *.* to 'slave'@'%' identified by '123456';

从库链接主库

CHANGE MASTER TO
MASTER_HOST='150.138.81.95',
MASTER_USER='slave',
MASTER_PASSWORD='123456',
MASTER_PORT=13307,
MASTER_AUTO_POSITION=1;

启动从库

start slave;
Show slave status;

看 slave_io_running 、slave_sql_running 、master_uuid 、Retrieved_Gtid_Set 、Executed_Gtid_Set
主库可以查看链接过来的slave show slave hosts;

问:什么是半同步复制,原理是什么

从MySQL5.5开始,MySQL以插件的形式支持半同步复制。想理解半同步呢,首先我们得先了解异步,全同步的概念。

异步复制(Asynchronous replication)
MySQL默认的复制即是异步的,主库在执行完客户端提交的事务后会立即将结果返给给客户端,并不关心从库是否已经接收并处理,这样就会有一个问题,主如果crash掉了,此时主上已经提交的事务可能并没有传到从上,如果此时,强行将从提升为主,可能导致新主上的数据不完整。

全同步复制(Fully synchronous replication)
指当主库执行完一个事务,所有的从库都执行了该事务才返回给客户端。因为需要等待所有从库执行完该事务才能返回,所以全同步复制的性能必然会收到严重的影响。

半同步复制(Semisynchronous replication)
介于异步复制和全同步复制之间,主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到并写到relay log中才返回给客户端。相对于异步复制,半同步复制提高了数据的安全性,同时它也造成了一定程度的延迟,这个延迟最少是一个TCP/IP往返的时间。所以,半同步复制最好在低延时的网络中使用。

半同步复制的潜在问题

主机dumper线程承担的工作变多了,这样显然会降低整个数据库的性能。
客户端事务在存储引擎层提交后,在得到从库确认的过程中,主库宕机了,此时,可能的情况有两种

1.事务还没发送到从库上
此时,客户端会收到事务提交失败的信息,客户端会重新提交该事务到新的主上,当宕机的主库重新启动后,以从库的身份重新加入到该主从结构中,会发现,该事务在从库中被提交了两次,一次是之前作为主的时候,一次是被新主同步过来的。

2.事务已经发送到从库上
此时,从库已经收到并应用了该事务,但是客户端仍然会收到事务提交失败的信息,重新提交该事务到新的主上。

无数据丢失的半同步复制Loss-Less
针对上述潜在问题,MySQL 5.7引入了一种新的半同步方案:Loss-Less半同步复制。

问:Loss-Less半同步复制有哪些优点解决了哪些问题?

1 主从一致性加强
支持在事务commit前等待ACK
新版本的semi sync 增加了rpl_semi_sync_master_wait_point参数 来控制半同步模式下 主库在返回给会话事务成功之前提交事务的方式。

该参数有两个值:

AFTER_COMMIT(5.6默认值)
master将每个事务写入binlog ,传递到slave 刷新到磁盘(relay log),同时主库提交事务。master等待slave 反馈收到relay log,只有收到ACK后master才将commit OK结果反馈给客户端。

AFTER_SYNC(5.7默认值,但5.6中无此模式)
master 将每个事务写入binlog , 传递到slave 刷新到磁盘(relay log)。master等待slave 反馈接收到relay log的ack之后,再提交事务并且返回commit OK结果给客户端。 即使主库crash,所有在主库上已经提交的事务都能保证已经同步到slave的relay log中。因此5.7引入了after_sync模式,带来的主要收益是解决after_commit导致的master crash主从间数据不一致问题,因此在引入after_sync模式后,所有提交的数据已经都被复制,故障切换时数据一致性将得到提升。

2 性能提升 支持发送binlog和接受ack的异步化
旧版本的semi sync 受限于dump thread ,原因是dump thread 承担了两份不同且又十分频繁的任务:传送binlog 给slave ,还需要等待slave反馈信息,而且这两个任务是串行的,dump thread 必须等待 slave 返回之后才会传送下一个 events 事务。dump thread 已然成为整个半同步提高性能的瓶颈。在高并发业务场景下,这样的机制会影响数据库整体的TPS .

为了解决上述问题,在5.7版本的semi sync 框架中,独立出一个 ack collector thread ,专门用于接收slave 的反馈信息。这样master 上有两个线程独立工作,可以同时发送binlog 到slave ,和接收slave的反馈。

3 性能提升 控制主库接收slave 写事务成功反馈数量
MySQL 5.7新增了rpl_semi_sync_master_wait_slave_count参数,可以用来控制主库接受多少个slave写事务成功反馈,给高可用架构切换提供了灵活性。

4 性能提升 Binlog 互斥锁改进
旧版本半同步复制在主提交binlog的写会话和dump thread读binlog的操作都会对binlog添加互斥锁,导致binlog文件的读写是串行化的,存在并发度的问题。
MySQL 5.7对binlog lock进行了以下两方面优化
1.移除了dump thread对binlog的互斥锁
2.加入了安全边际保证binlog的读安全

5 性能提升 组提交
5.7引入了新的变量slave-parallel-type,其可以配置的值有:
DATABASE (5.7之前默认值),基于库的并行复制方式;
LOGICAL_CLOCK (5.7新增值),基于组提交的并行复制方式;
MySQL 5.6版本也支持所谓的并行复制,但是其并行只是基于DATABASE的,也就是基于库的。如果用户的MySQL数据库实例中存在多个DATABASE ,对于从机复制的速度的确可以有比较大的帮助,如果用户实例仅有一个库,那么就无法实现并行回放,甚至性能会比原来的单线程更差。

MySQL5.7中增加了一种新的并行模式:为同时进入COMMIT阶段的事务分配相同的序列号,这些拥有相同序列号的事务在备库是可以并发执行的。

MySQL 5.7真正实现的并行复制,这其中最为主要的原因就是slave服务器的回放与主机是一致的即master服务器上是怎么并行执行的slave上就怎样进行并行回放。不再有库的并行复制限制,对于二进制日志格式也无特殊的要求(基于库的并行复制也没有要求)。

问:半同步复制延迟了会怎么样

事实上,半同步复制并不是严格意义上的半同步复制
当半同步复制发生超时时(由rpl_semi_sync_master_timeout参数控制,单位是毫秒,默认为10000,即10s),会暂时关闭半同步复制,转而使用异步复制。当master dump线程发送完一个事务的所有事件之后,如果在rpl_semi_sync_master_timeout内,收到了从库的响应,则主从又重新恢复为半同步复制。

问:5.6 和 5.7 的半同步复制有什么不同

MySQL 5.7极大的提升了半同步复制的性能。
5.6版本的半同步复制,dump thread 承担了两份不同且又十分频繁的任务:传送binlog 给slave ,还需要等待slave反馈信息,而且这两个任务是串行的,dump thread 必须等待 slave 返回之后才会传送下一个 events 事务。dump thread 已然成为整个半同步提高性能的瓶颈。在高并发业务场景下,这样的机制会影响数据库整体的TPS 。

5.7版本的半同步复制中,独立出一个 ack collector thread ,专门用于接收slave 的反馈信息。这样master 上有两个线程独立工作,可以同时发送binlog 到slave ,和接收slave的反馈。

MySQL 5.7版对Loss-Less半同步复制技术的优化,使得其成熟度和执行效率都得到了质的提高。我们建议在使用MySQL 5.7作为生产环境的部署时,可以使用半同步技术作为高可用与读写分离方案的数据复制方案。

问:半同步复制怎么配置

查看插件目录

show variables like 'plugin_dir';

查看以安装插件

select plugin_name,plugin_status,plugin_type,load_option,plugin_library from information_schema.plugins;
show plugins;

分别在主从节点上安装相关的插件
Master:

INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';

Slave:

INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';

卸载插件(非必须)

UNINSTALL PLUGIN rpl_semi_sync_slave;

查看插件配置变量

show global variables like '%rpl_semi_sync_slave%';

在master上的配置文件中,添加

rpl_semi_sync_master_enabled=ON 
或执行
set global rpl_semi_sync_master_enabled = 1;

在至少一个slave节点的配置文件中添加

rpl_semi_sync_slave_enabled=ON 
或执行
set global rpl_semi_sync_slave_enabled = 1;
STOP SLAVE IO_THREAD; START SLAVE IO_THREAD;

重新启动mysql服务即可生效。

确认半同步功能已经启用 修改一点表中数据

master> SHOW STATUS LIKE 'rpl_semi_sync_master_yes_tx';

问:说说对多线程复制理解

多线程复制是社区版5.6中新增的,并行是指从库多线程apply binlog。库级别并行应用binlog,同一个库数据更改还是串行的(5.7版并行复制基于事务组)

一般主从复制有三个线程且都是单线程:
Binlog Dump(主) ‐‐> IO Thread(从) ‐‐> SQL Thread(从)。
而master 这边是通过并发线程提交,事务通过LSN 写入binlog;但是Slave 只有一个IO 线程和SQL 线程,是单线程,所以在业务大的情况下就很容易造成主从延时.

如果开启并行复制功能(slave_parallel_workers > 0),那么SQL 线程就变为了coordinator 线程。

coordinator 线程主要负责两部分内容:
Coordinator+worker(多个)
若判断可以并行执行,那么选择worker 线程执行事务的二进制日志。
若判断不可以并行执行,如该操作是DDL,或者是事务跨schema 操作,则等待所有的worker 线程执行完成之后,再执行当前的日志。

这意味着coordinator 线程并不是仅将日志发送给worker 线程,自己也可以回放日志,但是所有可以并行的操作交付由worker 线程完成。

这样设计的并行复制效果并不高,如果用户实例仅有一个库,那么就无法实现并行回放,甚至性能会比原来的单线程更差,而单库多表是比多库多表更为常见的一种情形。

MySQL5.7 的MTS(Enhanced Muti‐threadedslaves)
MySQL 5.7 引入了新的机制来实现并行复制,不再有基于库的并行复制限制,主要思想就是slave 服务器的回放与主机是一致的,master 服务器上是怎么并行执行,slave 上就怎样进行并行回放。

mysql v5.7.2 进行了优化,增加了参数slave_parallel_type,参数有两个选项:
LOGICAL_CLOCK:基于逻辑时钟 ,可以在一个DATABASE 中并发执行relay log 事务
DATABASE: 基于数据库,v5.6 默认是这个参数,改参数每个库只能一个线程;(默认)

master_info_repository=TABLE (开启MTS 功能后,会频繁更新master.info,设置为TABLE 减小开销)
relay_log_info_repository=TABLE
slave_master_info 记录了首次同步master 的位置

relay_log_recovery=ON (slave IO 线程crash,如果relay‐log损坏,则自动放弃所有未执行的relay‐log,重新从master 上获取日志,保证relay‐log 的完整性)

slave_preserve_commit_order=ON (保证提交的顺序性)在slave 上应用事务的顺序是无序的,和relay log 中记录的事务顺序不一样,这样数据一致性是无法保证的,为了保证事务是按照relay log 中记录的顺序来回放,就需要开启参数slave_preserve_commit_order。

虽然mysql5.7 添加MTS 后,虽然slave 可以并行应用relay log,但commit 部分仍然是顺序提交,其中可能会有等待的情况。
relay-log = relay-log
relay-log-index = relay-log.index
slave_parallel_type=LOGICAL_CLOCK
slave_parallel_workers=2
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON
slave_preserve_commit_order=ON
log_bin=mysql‐bin
log_slave_updates=ON

问:5.7的并行复制是如何实现的呢?

5.7的并行复制基于一个前提,所有已经处于prepare阶段的事务,都是可以进行并行提交的。

这些当然也可以在从库中并行提交,因为处于这个阶段的事务,都是没有冲突的,该获取的资源都已经获取了,反过来说,如果有冲突,则后来的会等已经获取资源的事务完成之后才能继续,故而不会进入prepare阶段,这时一种新的并行复制思路,完全摆脱了原来一直致力于未来防止冲突而做的分发算法,等待策略等复杂而又效率低的下的工作。

一句话说:一个组提交的事务都是可以并行回放的
问:如何来定义哪些事务事务处于prepare阶段的,以及在生成的binlog内容中该如何告诉SLAVE哪些事务是可以并行复制的
5.7为了兼容5.6版本的库级复制,增加了一个参数slave_parallel_type,用来与之前5.6版本的库级别复制区分,5.6版的库级复制参数值为DATABASE,而5.7版的并行复制参数值为logical_clock。

5.7版本中生成的binlog内容,只是将GTID事件过滤出来了,其他的和以前的版本时一样的,GTID这个事件相比5.6版本,多了两个内容:
last_committed
sequence_number

last_committed值有11个值,分别是0,1,2,3,4,5,6,7,8,9,10。
这就表示当前binlog包括11个组,也就是说,last_committted中的每个值对应于一个组的编号,last_committed为10的有4个事务,这4个事务在5.7版本中,被定义为可以并行复制(提交)的,而sequence_number是顺序增长的,每一个事物对应一个序列号(sequence_number)。

另外,还有一个细节可能不太容易被发现,其实每一个组的last_commit值,都是上一个组中事务的sequence_number最大值,也是本组中事物sequence_number的最小值减1,同时这两个值的有效作用域都在文件内,同时这两个值的有效作用域都在文件内,只要换一个文件(flush binary logs),这两个值都会从0或1开始计数。

在MySQL 5.6版本之前,Slave服务器上有两个线程I/O线程和SQL线程。I/O线程负责接收二进制日志(更准确的说是二进制日志的event),SQL线程进行回放二进制日志。如果在MySQL 5.6版本开启并行复制功能,那么SQL线程就变为了coordinator线程。

coordinator线程主要负责以前两部分的内容:

1.若判断可以并行执行,那么选择worker线程执行事务的二进制日志.
2.若判断不可以并行执行,如该操作是DDL,亦或者是事务跨schema操作,则等待所有的worker线程执行完成之后,再执行当前的日志.

这意味着coordinator线程并不是仅将日志发送给worker线程,自己也可以回放日志,但是所有可以并行的操作交付由worker线程完成。coordinator线程与worker是典型的生产者与消费者模型。

并行复制两个主要参数slave_parallel_type,slave_parallel_workers

问:说说多线程复制分发原理,从库是如何分发的

从库是以事务为单位,做APPLY的,每一个事物会有一个GTID事件,从而都有一个last_committed及sequence_number值,分发原理如下。

1,从库SQL线程拿到一个新事务,取出last_committed及sequence_number值。
2,判断当前last_committed是不是大于当前已将执行的sequence_number的最小值(low_water_mark,简称lwm)。
3,如果大于,则说明上一个组的事务还没有完成。此时等待lwm变大,知道last_committed与lwm相等,才可以继续。
4,如果小于或等于,则说明上一个组的事务与正在执行的组是同一个组,不需要等待。
5,SQL线程通过统计,找到一个空闲的worker线程,如果没有空闲的,则SQL线程转入等待状态,直到找到一个为止。
6将当前事物打包,交给选定的worker,之后worker线程会去APPLY这个事务,此时的SQL显现出就会处理下一个事务。

上面的步骤是以事务为单位介绍的,其实实际处理中还是一个事件一个事件地分发。如果一个事务已经选定了worker,而新的event还在那个事务中,则直接交给那个worker处理即可。
从分发原理来看,同时执行的都是具有相同last_commit值的事务,不同只是后面的需要等前面做完了才能执行,事物都是随机分配到了worker线程中,但是执行的话,必须是一行一行地执行。一行事务数越多,并行读越高,也说明主库瞬时压力很大。

问:主从复制什么情况下会产生延迟

mysql的主从复制都是单线程的操作,主库对所有DDL和DML产生的日志写进binlog,由于binlog是顺序写,所以效率很高,slave的sql thread将主库的DDL和DML操作事件在slave中重放。

DML和DDL的IO操作是随机的,不是顺序,所以成本要高很多,另一方面,由于sql thread也是单线程的,当主库的并发较高时,产生的DML数量超过slave的SQL thread所能处理的速度,或者当slave中有大型query语句产生了锁等待,那么延时就产生了。

首要原因:数据库在业务上读写压力太大,CPU计算负荷大,网卡负荷大,硬盘随机IO太高
次要原因:读写binlog带来的性能影响,网络传输延迟。

问:主从延迟有哪些解决方案

架构方面
1.业务的持久化层的实现采用分库架构,mysql服务可平行扩展,分散压力。
2.单个库读写分离,一主多从,主写从读,分散压力。这样从库压力比主库高,保护主库。
3.服务的基础架构在业务和mysql之间加入memcache或者redis的cache层。降低mysql的读压力。
4.不同业务的mysql物理上放在不同机器,分散压力。

参数方面
1.增大从库参数innodb_buffer_pool_size的值,可以缓存更多数据,减少由于转换导致的IO压力。
2.增大参数innodb_log_file_size,innodb_log_file_in_group的值,减少buffer pool的磁盘IO,提升写入性能。
3.修改参数innodb_flush_method为 O_DIRECT,提升写入性能(在ssd下,或者磁盘IO能力强的时候推荐使用).
4.如果可以的话,把从库binlog关掉,或者关掉参数log_slave_updates.
5.修改参数innodb_flush_log_at_trx_commit为0 或者2.
6.如果binlog没有关掉,修改sync_binlog参数为0或一个很大的数,减少磁盘压力。
7.如果binlog_format为ROW模式,并且被修改表没有主键,则需要加上主键。
8.如果binlog_format为ROW模式,则可以在从库中删掉一些不必要的索引,同步之后在加上。
9.了解清楚写库上的操作内容,适当地在从库中预热以下数据,可以减少在复制时等待的时间。
10.如果binlog_format为STATEMENT模式,或者存在DDL复制,则可以将tmpdir参数改到内存中,比如/dev/shm
11.修改参数master_info_info_repository,relay_log_info_repository为table,减少直接IO导致的磁盘压力。

版本方面
将mysql升级到5.7版本,使用多线程并行复制。

硬件方面
1.采用好服务器,比如4u比2u性能明显好,2u比1u性能明显好。
2.存储用ssd或者盘阵或者san,提升随机写的性能。
3.主从间保证处在同一个交换机下面,并且是万兆环境。

硬件强劲,延迟自然会变小。

问:什么情况下会导致主从复制失败?

1、主机没启动,或者宕机,检查主库状态。
2、网络通信问题,使用ping命令检查;或使用shell命令进行shell端登录测试。
3、防火墙,selinux
4、复制用户名、密码、端口号、地址有问题,使用MySQL命令进行shell端登录测试。
5、MySQL自动解析,会将连接的IP解析成主机名(skip-name-resolve=0)写入my.cnf文件即可。
6、从库IO异常关闭,通过show slave status\G进行查看

复制出错处理
常见:1062(主键冲突),1032(记录不存在)

解决:
3.手动处理
4.跳过复制错误:set global sql_slave_skip_counter=1

问:如何复制部分数据

主库添加参数:

binlog_do_db=db1
binlog_ignore_db=db1
binlog_ignore_db=db2

或从库添加参数

replicate_do_db=db1
replicate_ignore_db=db1
replicate_do_table=db1.t1
replicate_wild_do_table=db%.%
replicate_wild_ignore_table=db1.%

问:因为复制是有延迟的,肯定会发生主库写了,但是从库还没有读到的情况,遇到这种问题怎么办?

MySQL支持不同的复制策略,基于不同的复制策略达到的效果也是不一样的,如果是异步复制,MySQL不能保证从库立马能够读到主库实时写入的数据,这个时候我们要权衡选择不同复制策略的利弊来进行取舍。

所谓利弊,就是我们是否对从库的读有那么高的实时性要求,如果真的有,我们可以考虑使用同步复制策略,但是这种策略相比于异步复制策略会大大降低主库的响应时间和性能。我们可以考虑是否可以在应用的设计层面去避开这个问题?

问:通过复制模型虽然读能力可以通过扩展slave机器来达到提高,而写能力却不能,如果写达到瓶颈我们应该怎么做呢?

这种复制模型对于写少读多型应用是非常有优势的,其次,当遇到这种问题的时候我们可以对数据库进行分库操作。

所谓分库,就是将业务相关性比较大的表放在同一个数据库中,例如之前数据库有A,B,C,D四张表,A表和B表关系比较大,而C表和D表关系比较大,这样我们把C表和D表分离出去成为一个单独的数据库,通过这种方式,我们可以将原有的单点写变成双点写或多点些,从而降低原有主库的写负载。

问:语句和行复制有什么优缺点?我们如何选择?

基于语句的复制
实际上是把主库上执行的SQL在从库上重新执行一遍,这么做的好处是实现起来简单,但也有缺点,比如我们SQL里面使用了NOW(),当同一条SQL在从库中执行的时候显然和在主库中执行的结果是不一样的。

基于行的复制
为了保证串行执行,就需要更多的锁。
基于行复制的时候二进制日志中记录的实际上是数据本身,这样从库可以得到正确的数据。
这种方式缺点很明显,数据必须要存储在二进制日志文件中,这无疑增加的二进制日志文件的大小,同时增加的IO线程的负载和网络带宽消耗。

相比于基于语句的复制还有一个优点就是基于行的复制无需重放查询,省去了很多性能消耗。
无论哪种复制模式都不是完美的,日志如何选择,这个问题可以在理解他们的优缺点之后进行权衡。

问:断电的时候,二进制日志文件没有刷新到磁盘,主库重新启动之后,从库尝试读该偏移量的二进制日志,会出现读不到的情况,这个问题应该怎么解决?

首先如果开启了sync_binlog选项,对于innodb同时设置innodb_flush_log_at_trx_commot=1,则可以保证二进制日志文件会被写入磁盘,但MyISAM引擎可能会导致数据损坏。如

果没有开启这个选项,则可以通过制定从库的二进制偏移量为下一个二进制日志文件的开头,但是不能解决事件丢失问题。

问:从库在非计划的关闭或重启时,回去读master.info文件去找上次停止复制的位置,这同样会有一个问题,如果master.info不正确,就会导致复制数据不一致的情况,遇到这个问题怎么办?

这个问题可以通过两种方式解决,一是控制master.info在从库非计划关闭或重启的时候让master.info能够同步到磁盘,这样下次启动的时候就不会读取错误的信息,这有助于减少错误的发生概率。另外想要找到正确的复制位置是困难的,我们也可以选择忽略错误。

问:什么情况下binlog会损坏?

Mysql binlog用来记录在服务器端上执行的SQL语句(假设binlog_format=statement).

根据sync_binlog的设置(默认为0,可以设置为1)

设置为0时,每次线程在生成binlog时不调用操作系统同步文件的函数,这样binlog可能存在于文件系统缓存中.设置为1时,每次在写binlog时,同时设用操作系统同步文件系统的函数,保证binlog会写到文件系统中.

设置为1时,每次都需要同步文件系统,再加上使用innodb存储引擎,本身又有自己的事务日志,从而给IO带来很大的压力.
设置为0时,带来的好处是事务处理性能基本上不受到binlog的影响,但是安全性受到影响,比如在掉电时,binlog没有及时写回,导致了binlog损坏,从而使mysql无法正常启动。

问:主库二进制日志文件损坏怎么办?

临时的解决办法就是修改log_bin设置,从新指定一个名字,启动mysql服务器.
原来的从库可能需要重初始化.有时候sync_binlog带来的io压力又很大,设置为0或是1确实是一个问题.
在mysql 5.6以后引入了rpl-semisync后,设置sync_binlog.使用这种方式带来可选的方案。前提是从库的网络,性能要够快,而不致于对主库的事务响应。

问:MySQL 8.0 中的并行复制优化了哪些

在5.7中基于逻辑时钟 Logical_Clock ,必须是在主上并行提交的事务才能在从上并行回放。
如果主上并发压力不大,那么就无法享受到并行复制带来的好处。
5.7 中引入了 binlog_group_commit_sync_delay 和 binlog_group_commit_sync_no_delay_count 两个参数。

通过让Binlog在执行 fsync 前等待一小会来提高Master上组提交的比率。但是无论如何,并行回放的速度还是取决于主上并行提交的情况。

MySQL 8.0中引入了一种新的机制来判断事务能否并行回放
基于 WriteSet 的冲突检测,通过检测事务在运行过程中是否存在写冲突来决定从机上的回放顺序,在主机上产生 Binlog 的时候,不再基于组提交,而是基于事务本身的更新冲突来确定并行关系。从机上的并发程度不再依赖于主机了。

问:做主从后主服务器挂了怎么办?

主库宕机:
(1)确保所有的relay log全部更新完毕,在每个从库上执行show processlist
(2)更新完毕后,登录所有从库查看master.info文件,对比选择pos最大的作为新的主库,
(3)然后登录这个新的主库,执行stop slave;进入主目录,删除master.Info和relay-log.info配置my.cnf文件开启log-bin文件
(4)创建用于同步的用户并授权slave
(5)登录另外一台从库,执行stop slave停止同步
(6)执行start slave
(7)修改新的master数据,测试slave是否同步更新

从库宕机:
(1)查看从库上mysql的错误日志,里面有记录主从挂掉时的binlog信息。
(2)有了binlog和postion信息后,只需要重新在从库上进行change master to配置即可。配置后开启slave状态,没有报错
(3)查看slave状态,发现slave已经正常了,开始进行延时数据恢复。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值