面试之MYSQL主从复制(详细)

一、什么是主从复制:

主从复制:是用来建立一个和主数据库完全一样的数据库环境,称为从数据库;主数据库一般是准实时的业务数据库。

二、主从复制的作用(好处或者说为什么要做主从)

1、做数据的热备,作为后备数据库,主数据库服务器故障后,可切换到从数据库继续工作,避免数据丢失。

2、架构的扩展。业务量越来越大,I/O访问频率过高,单机无法满足,此时做多库的存储,降低磁盘I/O访问的频率,提高单个机器的I/O性能

3、读写分离,使数据库能支撑更大的并发。在报表中尤其重要。由于部分报表sql语句非常的慢,导致锁表,影响前台服务。如果前台使用master,报表使用slave,那么报表sql将不会造成前台锁,保证了前台速度。

三、主从复制的原理(重中之重,面试必问):

1.数据库有个bin-log二进制文件,记录了所有sql语句。
2.我们的目标就是把主数据库的bin-log文件的sql语句复制过来。
3.让其在从数据的relay-log重做日志文件中再执行一次这些sql语句即可。

4.下面的主从配置就是围绕这个原理配置

5.具体需要三个线程来操作:

binlog输出线程。每当有从库连接到主库的时候,主库都会创建一个线程然后发送binlog内容到从库。

在从库里,当复制开始的时候,从库就会创建两个线程进行处理:

从库I/O线程。当START SLAVE语句在从库开始执行之后,从库创建一个I/O线程,该线程连接到主库并请求主库发送binlog里面的更新记录到从库上。从库I/O线程读取主库的binlog输出线程发送的更新并拷贝这些更新到本地文件,其中包括relay log文件。

从库的SQL线程。从库创建一个SQL线程,这个线程读取从库I/O线程写到relay log的更新事件并执行。

可以知道,对于每一个主从复制的连接,都有三个线程。拥有多个从库的主库为每一个连接到主库的从库创建一个binlog输出线程,每一个从库都有它自己的I/O线程和SQL线程。

或者

分为四步走:

  1. 主库对所有DDL和DML产生的日志写进binlog;

  2. 主库生成一个 log dump 线程,用来给从库I/O线程读取binlog;

  3. 从库的I/O Thread去请求主库的binlog,并将得到的binlog日志写到relay log文件中;

  4. 从库的SQL Thread会读取relay log文件中的日志解析成具体操作,将主库的DDL和DML操作事件重放。

关于DDL和DML

SQL语言共分为以下几大类:查询语言DQL,控制语言DCL,操纵语言DML,定义语言DDL。事务控制TCL.

DQL(Data QUERY
Languages)语句:即数据库定义语句,用来查询SELECT子句,FROM子句,WHERE子句组成的查询块,比如:select–from–where–grouop
by–having–order by–limit

DDL(Data Definition
Languages)语句:即数据库定义语句,用来创建数据库中的表、索引、视图、存储过程、触发器等,常用的语句关键字有:CREATE,ALTER,DROP,TRUNCATE,COMMENT,RENAME。增删改表的结构

DML(Data Manipulation
Language)语句:即数据操纵语句,用来查询、添加、更新、删除等,常用的语句关键字有:SELECT,INSERT,UPDATE,DELETE,MERGE,CALL,EXPLAIN
PLAN,LOCK TABLE,包括通用性的增删改查。增删改表的数据

DCL(Data Control Language)语句:即数据控制语句,用于授权/撤销数据库及其字段的权限(DCL is short
name of Data Control Language which includes commands such as GRANT
and mostly concerned with rights, permissions and other controls of
the database system.)。常用的语句关键字有:GRANT,REVOKE。

TCL(Transaction Control
Language)语句:事务控制语句,用于控制事务,常用的语句关键字有:COMMIT,ROLLBACK,SAVEPOINT,SET
TRANSACTION。

主从复制如图:
在这里插入图片描述
原理图
在这里插入图片描述

四、其实主从复制也存在一些问题:

  1. 负载均衡,由于复制的时间差,不能保证同步读,而且写仍然单点,没法多点写,我对这个理解就是半吊子的读写均衡。

  2. 容灾,基本都是有损容灾,因为数据不同步,谁用谁知道,半吊子的容灾。

可能只是提供一种成本较低的数据备份方案加不完美的容灾和负载均衡吧,这种方案注定是一种过渡方案,个人认为必须更新了。当然,在不是体量巨大的情况下,还是不失为一个优化的解决办法。

五、面试题分析(如果问到数据库主从问题,必问以下问题)

1、主从的好处是?

2、主从的原理是?

3、从数据库的读的延迟问题了解吗?如何解决?

原因:当主库的TPS并发较高时,产生的DDL数量超过slave一个sql线程所能承受的范围,那么延时就产生了,当然还有就是可能与slave的大型query语句产生了锁等待,还有网络延迟。

(谈到MySQL数据库主从同步延迟原理,得从mysql的数据库主从复制原理说起,mysql的主从复制都是单线程的操作,主库对所有DDL和DML产生binlog,binlog是顺序写,所以效率很高;slave的Slave_IO_Running线程会到主库取日志,效率会比较高,slave的Slave_SQL_Running线程将主库的DDL和DML操作都在slave实施。**DML和DDL的IO操作是随机的,不是顺序的,**因此成本会很高,还可能是slave上的其他查询产生lock争用,由于Slave_SQL_Running也是单线程的,所以一个DDL卡主了,需要执行10分钟,那么所有之后的DDL会等待这个DDL执行完才会继续执行,这就导致了延时。有朋友会问:“主库上那个相同的DDL也需要执行10分,为什么slave会延时?”,答案是master可以并发,Slave_SQL_Running线程却不可以。

常见原因:Master负载过高、Slave负载过高、网络延迟、机器性能太低、MySQL配置不合理。

解决方法一 :最简单的减少slave同步延时的方案就是在架构上做优化,尽量让主库的DDL快速执行。还有就是主库是写,对数据安全性较高,比如sync_binlog=1,innodb_flush_log_at_trx_commit = 1 之类的设置,而slave则不需要这么高的数据安全,完全可以讲sync_binlog设置为0或者关闭binlog,innodb_flushlog也可以设置为0来提高sql的执行效率。另外就是使用比主库更好的硬件设备作为slave。

对于上面MYSQL参数 sync_binlog=1 说明:
MySQL提供一个sync_binlog参数来控制数据库的binlog刷到磁盘上去。
----默认,sync_binlog=0,表示MySQL不控制binlog的刷新,由文件系统自己控制它的缓存的刷新。这时候的性能是最好的,但是风险也是最大的。因为一旦系统Crash,在binlog_cache中的所有binlog信息都会被丢失。
----如果sync_binlog>0,表示每sync_binlog次事务提交,MySQL调用文件系统的刷新操作将缓存刷下去。最安全的就是sync_binlog=1了,表示每次事务提交,MySQL都会把binlog刷下去,是最安全但是性能损耗最大的设置。这样的话,在数据库所在的主机操作系统损坏或者突然掉电的情况下,系统才有可能丢失1个事务的数据。但是binlog虽然是顺序IO,
----但是设置sync_binlog=1,多个事务同时提交,同样很大的影响MySQL和IO性能。虽然可以通过group commit的补丁缓解,但是刷新的频率过高对IO的影响也非常大。对于高并发事务的系统来说,“sync_binlog”设置为0和设置为1的系统写入性能差距可能高达5倍甚至更多。
----所以很多MySQL DBA设置的sync_binlog并不是最安全的1,而是100(注:每写N次操作系统缓冲就执行一次刷新操作)或者是0。这样牺牲一定的一致性,可以获得更高的并发和性能。

对于上面MYSQL参数 innodb_flush_log_at_trx_commit = 1说明:
-----提交事务的时候将 redo 日志写入磁盘中,所谓的 redo 日志,就是记录下来你对数据做了什么修改,比如对 “id=10 这行记录修改了 name 字段的值为 xxx”,这就是一个日志。如果我们想要提交一个事务了,此时就会根据一定的策略把 redo 日志从 redo log buffer 里刷入到磁盘文件里去。此时这个策略是通过 innodb_flush_log_at_trx_commit 来配置的,他有几个选项。
-----值为0 : 提交事务的时候,不立即把 redo log buffer 里的数据刷入磁盘文件的,而是依靠 InnoDB 的主线程每秒执行一次刷新到磁盘。此时可能你提交事务了,结果 mysql 宕机了,然后此时内存里的数据全部丢失。
-----值为1 : 提交事务的时候,就必须把 redo log 从内存刷入到磁盘文件里去,只要事务提交成功,那么 redo log 就必然在磁盘里了。注意,因为操作系统的“延迟写”特性,此时的刷入只是写到了操作系统的缓冲区中,因此执行同步操作才能保证一定持久化到了硬盘中。
-----值为2 : 提交事务的时候,把 redo 日志写入磁盘文件对应的 os cache 缓存里去,而不是直接进入磁盘文件,可能 1 秒后才会把 os cache 里的数据写入到磁盘文件里去。
-----可以看到,只有1才能真正地保证事务的持久性,但是由于刷新操作 fsync() 是阻塞的,直到完成后才返回,我们知道写磁盘的速度是很慢的,因此 MySQL 的性能会明显地下降。如果不在乎事务丢失,0和2能获得更高的性能。

解决方法二 :数据放入缓存中,更新数据库后,在预期可能马上用到的情况下,主动刷新缓存->(Redis的角度)

解决办法三:对于比较重要且必须实时的数据,比如用户刚换密码(密码写入 Master),然后用新密码登录(从 Slaves 读取密码),会造成密码不一致,导致用户短时间内登录出错。所以在这种需要读取实时数据的时候最好从 Master 直接读取,避免 Slaves 数据滞后现象发生。

4、做主从后主服务器挂了怎么办?

在这里插入图片描述

一、Mysql主库宕机情况分类:

1)硬件问题,(服务器、ecs、虚拟主机等等)宕机

2)service问题,Mysql宕机,服务异常,端口异常等

二、硬件问题处理思路

硬件问题我们可以查看IDC巡检记录,或通过远程控制卡查看硬件运行状态,根据事实情况就行硬件故障报修进行处理,恢复业务步骤:

查看报警信息,确认业务是否收到影响,必要时切从库进行数据交互

IDC询问排查

确认硬件故障,短时间无法修复开Case处理

通知部门领导,处理进度,并实时记录

事件处理完成后,拟写故障报告,会议通报。

三、MySQL service问题处理思路

1)首先要做的就是判断是否影响业务,是否需要切库,保证业务运行时首要任务

2)如果此时需要切从库,按照如下步骤进行:

1> 先查看MySQL 从库状态

show processlistG

##如果看到两个状态,说明此时的从库和主库是同步的 =====[如果不同步,建议考出binlog进行同步]

#state: waiting for master to send event I/O线程

#state:has read all relay log;waiting for the slave I/O thread to update it sql线程

2> 登录从库分别查看:【多个从库 哪个替代主库呢??】

cat /data/3306/data/master.info

cat /data/3307/data/master.info

##看哪个从库的哪个master.info哪个更新,就说明哪个从库一致性更高,所以此时就确定最新的库为主库。

选个pos最大的作为主库

或利用半同步的功能,直接选择做实时同步的这个从库。

3> 确保所有relay log全部更新完毕。

stop slave io_thread;show processlist; [在每个从库上执行]

##直到看到has read all relay log;表示从库更新都执行完毕

4> 登录从库

mysql -uroot -p您的密码 -S /data/3306/mysql.sock #sock路径根据自己的进行修改

stop slave;

reset master;

quit;

5> 进入数据库数据目录,删除master.info relay-log.info

cd /data/3306/data/master

rm -f master.info relay-log.info

检查授权表,类似read-only参数

6> 3306 提升从库为主库

vim /data/3306/my.cnf

开启:

log-bin =/data/3306/mysql-bin

//如果存在log-slave-updates read-only等参数一定要注释掉。

/data/3306/mysql stop

/data/3306/mysql start

到此,提升主库完毕

四、所有slave指向新的master

7> 如果主库服务器没down,需要去主库拉取bin-log补全提升主库的从库

8> 其它从库操作 【指向新的master】

已检查(同步user rep均存在)

登录从库

stop slave;

change master to master_host=‘192.168.1.32’; //如果不同步,就指定位置点

start slave;

show slave statusG;

解决的思路:在我看来都应该围绕bin log日志和从服务器上的relay log 等文件还有就是数据的备份。所以说做好数据备份才是王道,这样能最大程度上保证数据不会丢失。

读写分离实现方法

为了减轻数据库的压力,一般会进行数据库的读写分离,

实现方法一是通过分析sql语句是insert/select/update/delete中的哪一种,从而对应选择主从。
二是通过拦截方法名称的方式来决定主从的,如:save*()、insert*() 形式的方法使用master库,select()开头的使用slave库。

虽然大多数都是从程序里直接实现读写分离的,但对于分布式的部署和水平和垂直分割,一些代理的类似中间件的软件还是挺实用的,如 MySQL
Proxy比较。mysql proxy根本没有配置文件, lua脚本就是它的全部,当然lua是相当方便的。

猜你喜欢

转载自blog.csdn.net/weixin_42754971/article/details/113616962