1.官网
https://dev.mysql.com/doc/refman/5.7/en/replication.html
2.主从复制产生背景
1.如果单台数据库服务满足不了访问需求,那我们可以做数据库的集群方案。集群的话必然会面临一个问题,就是不同的节点之间数据一致性的问题。
2.如果同时读写多台数据库节点,怎么让所有的节点数据保持一致?
这个时候我们需要用到复制技术(replication),被复制的节点称为master,复制的节点称为 slave。
slave本身也可以作为其他节点的数据来源,这个叫做级联复制。
3.主从复制模式
一主一从
主主复制
一主多从---扩展系统读取的性能,因为读是在从库读取的;
多主一从---5.7开始支持
联级复制--
图示
3.1.一主一从
3.2.一主多从
3.3.主主复制
3.4.多主一从
3.5级联复制
4.主从复制的优势
实时灾备,用于故障切换
读写分离,提供查询服务
备份,避免影响业务
5.主从复制的必要条件
主库开启binlog日志(设置log-bin参数)
主从server-id不同
从库服务器能连通主库
6.主从复制原理
6.1.图示
1.从数据库(从节点)上会有一个IO线程去连接Master节点,
2.然后Master节点会通过(log dump thread)线程将binlog日志发送给IO线程
3.IO线程将数据写入Relay Log
4.从节点会有一个SQL线程读取Relay Log的日志
5.然后SQL线程通过读取的Relay Log日志写入到从节点数据库
6.2.详细原理流程
1.主从复制的基础是主库记录数据库的所有变更记录到binlog。
2.binlog: binary log,主库中保存更新事件日志的二进制文件。
3.binlog 是数据库中保存配置中过期时间内所有修改数据库结构或内容的一个文件。
如果过期时间是10d的话,那么就是最近10d的数据库修改记录。
4.mysql主从复制是一个异步的复制过程,主库发送更新事件到从库,从库读取更新记录,
并执行更新记录,使得从库的内容与主库保持一致。
5.在主库里,只要有更新事件出现,就会被依次地写入到binlog里面,是之后从库连接到
主库时,从主库拉取过来进行复制操作的数据源。
6.主库binlog输出线程。每当有从库连接到主库的时候,主库都会创建一个线程然后发送
binlog内容到从库。
7.对于主库每一个即将发送给从库的sql事件,binlog输出线程会将其锁住。
一旦主库的该事件被线程读取完之后,该锁会被释放,即使在主库的该事件完全发送到
从库的时候,该锁也会被释放。
8.在从库里,当复制开始的时候,从库就会创建两个线程进行处理:
8.1.从库I/O线程。
当START SLAVE语句在从库开始执行之后,从库创建一个I/O线程,
该线程连接到主库并请求主库发送binlog里面的更新记录到从库上。
从库I/O线程读取主库的binlog输出线程发送的更新并拷贝这些更新到本地文件,
其中包括relay log文件。
8.2.从库的SQL线程。
从库创建一个SQL线程,这个线程读取从库I/O线程写到relay log的更新事件并执行。
9.概述
9.1.可以知道,对于每一个主从复制的连接,都有三个线程。
9.2.拥有多个从库的主库为每一个连接到主库的从库创建一个binlog输出线程,
9.3.每一个从库都有它自己的I/O线程和SQL线程。从库通过创建两个独立的线程,
使得在进行复制时,从库的读(I/O线程)和写(SQL线程)进行了分离。
9.3.1.因此,即使负责执行的线程(SQL线程)运行较慢,负责读取更新语句的线程并不会因此变得缓慢。
9.3.2.比如说,如果从库有一段时间没运行了,当它在此启动的时候,
尽管它的SQL线程执行比较慢,它的I/O线程可以快速地从主库里读取所有的binlog内容。
这样一来,即使从库在SQL线程执行完所有读取到的语句前停止运行了,
I/O线程也至少完全读取了所有的内容,
并将其安全地备份在从库本地的relay log,
随时准备在从库下一次启动的时候执行语句。
7.主从复制的模式
7.1.异步复制[单线程模式]------早起的mysql复制模式
7.1.1.概述
1.所谓单线程:我们这里主要是指从节点单线程的顺序的执行binlog日志文件中的SQL语句;
7.1.2.缺陷
1.因为我们的数据库连接一般都是并发执行的,可以同时支持多个SQL的请求,但是我们的从节点在进行复制的过程中
如果是这种单线程顺序执行,可能在数据库同步效率上是有延迟了;
思考:我们如果利用多线程去处理binlog文件中的SQL是否可以?
关于纯粹的多线程的去处理,还是有问题的,我们看一下下面的SQL就知道了了。
如下的三条SQL我们如何并发执行,有可能我们先执行了SQL3 会出新表都不存在的现象;
SQL1:insert into emp values(1,'gaoxinfu');
SQL2:update emp set name='gaoxinfu-up' where id=1;
SQL3:delete from emp where id=1;
7.2.全同步复制
7.2.1.概述
1.默认来讲,我们的主从复制的这个策略,master主节点的binlog日志写入与从节点的同步是分开去做的;
也就是应用客户端只要写入master节点的binlog日志就会结束,返回客户端;
2.全同步复制:主要是指从应用客户端写入数据库,不仅仅要等binlog日志写完,还要等从节点数据同步完,才能返回;
7.2.2.缺陷
1.这种方式很明显,效率是非常低的,SQL执行耗时很明显会增加;
7.3.半同步复制 (介于全同步与异步复制之间)
7.3.1.概念
1.主库在执行完客户端提交的事务后不是立刻返回给客户端,而是等待至少一个从库接收到 binlog并写到relay log中才返回给客户端。
master不会等待很长的时间,但是返回给客户端的时候,数据就即将写入成功了,因为它只剩最后一步了:就是读取 relay log,写入从库。
7.3.2.主库/从库安装 (同步插件:semisync_master.so)
mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
Query OK, 0 rows affected (1.29 sec)
mysql> show variables like '%semi_sync%';
+-------------------------------------------+------------+
| Variable_name | Value |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled | OFF |
| rpl_semi_sync_master_timeout | 10000 |
| rpl_semi_sync_master_trace_level | 32 |
| rpl_semi_sync_master_wait_for_slave_count | 1 |
| rpl_semi_sync_master_wait_no_slave | ON |
| rpl_semi_sync_master_wait_point | AFTER_SYNC |
+-------------------------------------------+------------+
6 rows in set (0.01 sec)
mysql>
1.默认是关闭的状态;
7.3.2.主库开启半同步复制
mysql> set global rpl_semi_sync_master_enabled=1;
Query OK, 0 rows affected (0.01 sec)
mysql> show variables like '%semi_sync%';
+-------------------------------------------+------------+
| Variable_name | Value |
+-------------------------------------------+------------+
| rpl_semi_sync_master_enabled | ON |
| rpl_semi_sync_master_timeout | 10000 |
| rpl_semi_sync_master_trace_level | 32 |
| rpl_semi_sync_master_wait_for_slave_count | 1 |
| rpl_semi_sync_master_wait_no_slave | ON |
| rpl_semi_sync_master_wait_point | AFTER_SYNC |
+-------------------------------------------+------------+
6 rows in set (0.01 sec)
mysql>
7.3.4.从库开启半同步复制
-- 从库执行
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
set global rpl_semi_sync_slave_enabled=1;
show global variables like '%semi%';
7.3.5.半同步复制的优势
1.相对于异步复制,半同步复制提高了数据的安全性,同时它也造成了一定程度的延迟,它需要等待一个slave写入中继日志,这里多了一个网络交互的过程,
所以,半同步复制最好在低延时的网络中使用。这个是从主库和从库连接的角度,来保证slave数据的写入。
7.4.多库并行复制
7.4.1.概念
怎么实现并行复制呢?设想一下,如果3条语句是在三个数据库执行,操作各自的数据库,是不是肯定不会产生并发的问题呢?
执行的顺序也没有要求。当然是,所以如果是操作三个数据库,这三个数据库的从库的SQL线程可以并发执行。
但是在大部分的情况下,我们都是单库多表的情况,在一个数据库里面怎么实现并行复制呢?
或者说,我们知道,数据库本身就是支持多个事务同时操作的;为什么这些事务在主库上面可以并行执行,却不会出现问题呢?
因为他们本身就是互相不干扰的,比如这些事务是操作不同的表,或者操作不同的 行,不存在资源的竞争和数据的干扰。
那在主库上并行执行的事务,在从库上肯定也是 可以并行执行,是不是?比如在 master 上有三个事务同时分别操作三张表,
这三个事务 是不是在slave上面也可以并行执行呢?
7.5.异步复制之 GTID 复制
7.5.1.概念
我们可以把那些在主库上并行执行的事务,分为一个组,并且给他们编号, 这一个组的事务在从库上面也可以并行执行。
这个编号,我们把它叫做 GTID(Global Transaction Identifiers),这种主从复制的方式,我们把它叫做基于 GTID 的复制。
7.5.2.开关
show global variables like 'gtid_mode'; # 默认关闭的状态
无论是优化 master 和 slave 的连接方式,还是让从库可以并行执行 SQL,都是从数据库的层面去解决主从复制延迟的问题。