mysql主从复制

一:mysql复制默认以什么方式进行、复制粒度html

二:mysql复制的优点mysql

三:mysql复制的方法sql

四:mysql复制的多种类型数据库

五:记录binlog的三种格式安全

六:mysql基于binlog复制的原理以及搭建过程服务器

七:mysql复制相关的参数多线程

八:延迟复制的原理以及搭建过程并发

九:半同步复制的原理以及搭建过程app

十:基于GTID复制的原理、搭建过程以及限制条件异步

 

•MySQL复制容许将主实例(master)上的数据同步到一个或多个从实例(slave)上,默认状况下复制是异步进行的,从库也不须要一直链接到主库来同步数据

• MySQL复制的数据粒度能够是主实例上全部的数据库,也能够是指定的一个或多个数据库,也能够是一个数据库里的指定的表

• MySQL复制所带来的优点在于:
• 扩展能力:经过复制功能能够将MySQL的性能压力分担到一个或多个slave上。这要求全部的写操做和修改操做都必须在Master上完成,而读操做能够被分配到一个或多个slave上。
将读写分离到不一样服务器执行以后,MySQL的读写性能获得提高
• 数据库备份:因为从实例是同步主实例的数据,因此能够将备份做业部署到从库
• 数据分析和报表:一样,一些数据分析和报表的实现能够在从实例执行,以减小对主库的性能影响
• 容灾能力:能够在物理距离较远的另外一个数据中心创建一个slave,保证在主实例所在地区遭遇灾难时,在另外一个数据中心能快速恢复

MySQL复制有两种方法
• 传统方式:基于主库的bin-log将日志事件和事件位置复制到从库,从库再加以应用来达到主从同步的目的
• Gtid方式:global transaction identifiers是基于事务来复制数据,所以也就不依赖日志文件,同时又能更好的保证主从库数据一致性

MySQL复制有多种类型:
• 异步复制:一个主库,一个或多个从库,数据异步同步到从库
• 同步复制:在MySQL Cluster中特有的复制方式
• 半同步复制:在异步复制的基础上,确保任何一个主库上的事务在提交以前至少有一个从库已经收到该事务并日志记录下来
• 延迟复制:在异步复制的基础上,人为设定主库和从库的数据同步延迟时间,即保证数据延迟至少是这个参数

• 并行复制:SQL线程实现了多线程,来提高slave的并发度

 

MySQL复制有三种核心格式
• 基于语句的复制(statement based replication):基于主库将SQL语句写入到bin log中完成复制
• 基于行数据的复制(row based replication):基于主库将每个行数据变化的信息做为事件写入到bin log中完成日志
• 混合复制(mixed based replication):上述二者的结合。默认状况下优先使用基于语句的复制,只有当部分语句若是基于语句复制不安全的状况下才会自动切换为基于行数据的复制

mysql复制的工做原理:

MySQL复制涉及三个线程,其中一个在主库,另两个在从库
• binlog dump thread:在主库建立,用来在从库连接过来时发送bin log的内容
• slave io thread:在备库建立,用来链接主库并请求发送新的bin log内容。该线程读取主库的bin log dump线程发送的更新内容并将此内容复制到本地的relay log中
• Slave sql thread:在备库建立,读取slave io线程在本地relay log中的内容并在本地执行内容中的事件

MySQL基于binlog的复制

基于binary log的复制是指主库将修改操做写入到bin log中,从库负责读取主库的bin log,并在本地复制一份,而后将里面的操做在从库执行一遍,每一个从库会保存目前读取主库日志的文件名和日志位置主库和每一个从库都必须有一个惟一ID,叫server-id配置在配置文件中

传统主从环境的搭建步骤
主库:
1.安装完成mysql
2.修改主机的配置文件打开binlog
server-id=1 ##取值范围 1~2^32-1
log-bin=/dbdata/data/bin-log
log-bin-index=/dbdata/data/bin-log.index
3.建立同步帐号
CREATE USER 'repl'@'192.168.237.%' IDENTIFIED BY 'mysql';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.237.%';
4.在从库用用同步帐号登陆主库测试帐号
5.备份全库并把备份文件copy到从库恢复(备份以前全库加锁;flush tables with read lock;) 生产环境中不适用lock   --single-transaction --master-data=2;
6.记录show master status \G 位置

从库:
1.修改从库的配置文件
server-id=2
relay-log=/dbdata/data/relay-log
relay-log-index=/dbdata/data/relay-log.index
2. CHANGE MASTER TO
MASTER_HOST=‘master_host_name’, ##主库的主机名
MASTER_PORT=port_number ##主库的端口号
MASTER_USER=‘replication_user_name’, ##复制的数据库用户名
MASTER_PASSWORD=‘replication_password’, ##复制的用户密码
MASTER_LOG_FILE=‘recorded_log_file_name’, ##主库的日志文件名
MASTER_LOG_POS=recorded_log_position; ##主库的日志文件位置
例:
CHANGE MASTER TO
MASTER_HOST='192.168.10.241',
MASTER_PORT=3306,
MASTER_USER='repl',
MASTER_PASSWORD='mysql',
MASTER_LOG_FILE='mysql-bin.000013',
MASTER_LOG_POS=154;
3.start slave;

• 查看主备库复制是否正常:

• 在slave上执行show slave status\G命令

seconds_behind_master 指的是什么意思?从库延迟时间?

官网解释:

 

seconds_Behind_Master: The number of seconds that the slave SQL thread is behind processing the master binary log
也就是说,是SQL thread在执行IO thread dump下来的relay log的时间差。你们都知道relay log中event记录的时间戳是主库上的时间戳,而SQL thread的时间戳是从库上的,也就是说,若是主库和从库的时间是一致的,那么这个SBM表明的确实是从库延后主库的一个时间差

 

 

 

 

复制相关的参数

• log_slave_updates:该参数用来控制是否将收到的主库的更新数据的语句也记录在slave本身的bin log中。正常状况下是不须要记录的,但若是是想建立级联复制关系,好比A -> B -> C,这其中B既要做为A的从库,也要做为C的主库,则须要既开启log-bin参数,也要开启log_slave_updates参数

• replicate-do-db:该参数用来指定须要复制的数据库

• replicate-ignore-db:该参数决定了忽略指定数据库的复制,其行为和replicate-do-db正好相反

• replicate-do-table=db_name.tbl_name:经过该参数告知slave的SQL thread仅复制指定表上的数据。若是有多个表,则该参数要使用屡次

• replicate-ignore-table=db_name.tbl_name:经过该参数告知slave的SQL thread将指定表上的数据过滤掉

• replicate-wild-do-table=db_name.tbl_name:经过该参数告知SQL的SQL thread仅复制符合匹配的表,可使用_和%做为通配符。好比replicate-wild-dotable=foo%.bar%表示复制以foo打头的数据库下全部bar打头的表数据。若是是replicate-wild-do-table=foo%.%,则表示即复制foo打头的全部表的数据,也复制create/drop/alter database foo打头的命令

• replicate-wild-ignore-table=db_name.tbl_name:经过该参数告知SQL的SQL thread过滤掉符合匹配的表

• slave-parallel-workers: 该参数决定了slave上启动多个SQL thread线程来并行应用数据的默认值是0表明不容许并行,取值范围能够是0~1024

• skip-slave-start :该参数决定了在MySQL启动时是否先不启动slave线程,即暂停复制

• slave-parallel-type=type :该参数决定了当启动了并行以后,采用什么粒度的并行方式。默认值database表示按照不一样的数据库执行并行LOGICAL_CLOCK则表示按照在binlog中的一组提交的事务做为并行粒度

• slave-skip-errors=[err_code1,err_code2,...|all|ddl_exist_errors]:该参数决定了当slave的SQL thread执行过程当中碰到何种错误时能够忽略并继续接下来的数据复制。正常状况下当有错误发生时,复制会中止而须要人工干预修复才能继续进行。除非很是自信能够忽略某些错误,不然不要使用这个参数,否则会致使虽然复制执行正常,但其实内部的数据已经彻底不一致

• sql_slave_skip_counter表明在非GTID复制环境下,经过设置此参数来跳过多少个复制事件。设置完该参数并不是当即生效,而是要等待下次start slave命令的执行生效,并将该参数再次设置为0

• binlog-do-db=db_name: 该参数决定了哪些库下的修改会被记录到bin log中。其行为与replicate-do-db类型,在基于SQL语句复制的环境下,只记录在当前数据库下的修改

• binlog-ignore-db=db_name:该参数决定了在bin log中忽略的数据库,其行为与replicate-ignore-db类型

• binlog_format:该参数决定了bin log中记录的格式

MySQL延迟复制

延迟复制是指定从库对主库的延迟至少是指定的这个间隔时间,默认是0秒。能够经过change master to命令来指定CHANGE MASTER TO MASTER_DELAY = N;
其原理是从库收到主库的bin log以后,不是当即执行,而是等待指定的秒数以后再执行

延迟复制的使用场景好比:
确保在主库上被错误修改的数据能及时找回
测试在从库IO集中在恢复bin log过程当中对应用程序的访问影响,保留一份若干天前的数据库状态,和当前状态能够作对比
show slave status中SQL_Delay值代表了设置的延迟时长

MySQL半同步复制

默认建立的MySQL复制是异步的,意味着主库将数据库修改事件写入到本身的bin log,而并不知道从库是否获取了这些事件并应用在本身身上。因此当主库崩溃致使要主从切换时,有可能从库上的数据不是最新的

从5.7版本开始MySQL经过扩展的方式支持了半同步复制当主库执行一个更新操做事务时,提交操做会被阻止直到至少有一个半同步的复制slave确认已经接收到本次更新操做,主库的提交操做才会继续,半同步复制的slave发送确认消息只会在本次更新操做记录已经记录到本地的relay log以后,若是没有任何slave发送确认消息而致使超时时,半同步复制会转换成异步复制

半同步复制会对MySQL性能产生影响,由于主库的提交动做只有在收到至少一个从库的确认消息以后才能执行。但这个功能是性能和数据可靠性方面的权衡

rpl_semi_sync_master_wait_point参数用来控制半同步复制的行为:

AFTER_SYNC
AFTER_COMMIT 

须要配置的系统参数包括:
rpl_semi_sync_master_enabled:在主库配置,确保主库的半同步复制功能开启
rpl_semi_sync_master_timeout:配置主库等待多少毫秒时间来保证接收备库的确认消息,当超过这个时间时,半同步变成异步方式
rpl_semi_sync_slave_enabled:在从库配置,确保从库的半同步复制功能开启

主库【】
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled = 1;
SET GLOBAL rpl_semi_sync_master_timeout = N; ##N是毫秒,默认是10000,表明10秒
从库【】
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
SET GLOBAL rpl_semi_sync_slave_enabled =1;
需在从库重启slave线程

半同步复制监控参数:

Rpl_semi_sync_master_clients:检查半同步的slave个数
Rpl_semi_sync_master_status:1表示主库的半同步功能开启而且运行正常,0表示主库的半同步功能关闭或者半同步复制已经变成了异步复制
Rpl_semi_sync_master_no_tx:表示有多少提交没有收到slave的确认消息
Rpl_semi_sync_master_yes_tx:表示有多少个提交收到了slave的确认消息
Rpl_semi_sync_slave_status:1表示备库上slave功能开启而且运行正常,0表示功能为开启或者运行异常

经过mysql> SHOW STATUS LIKE 'Rpl_semi_sync%';查看各个参数的状态

 

mysql并行复制

 

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

 

  • 若判断能够并行执行,那么选择worker线程执行事务的二进制日志
  • 若判断不能够并行执行,如该操做是DDL,亦或者是事务跨schema操做,则等待全部的worker线程执行完成以后,再执行当前的日志

 

这意味着 coordinator线程并非仅将日志发送给worker线程,本身也能够回放日志,可是全部能够并行的操做交付由worker线程完成

(疑问:这里是在判断不能够并行执行时,在等待全部的worker线程执行完成后,是由coordinator执行仍是由worker进程非并行进行。从上面两句话中看不出coordinator进程回放日志。)

上述机制实现了基于schema的并行复制存在两个问题,首先是crash safe功能很差作,由于可能以后执行的事务因为并行复制的关系先完成执行,那么当发生crash的时候,这部分的处理逻辑是比较复杂的。从代码上看,5.6这里引入了Low-Water-Mark标记来解决该问题,其是但愿借助于日志的幂等性来解决该问题,不过5.6的二进制日志回放还不能实现幂等性。另外一个最为关键的问题是这样设计的并行复制效果并不高,若是用户实例仅有一个库,那么就没法实现并行回放,甚至性能会比原来的单线程更差。而 单库多表是比多库多表更为常见的一种情形 。

MySQL 5.7基于组提交的并行复制

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

从MySQL官方来看,其并行复制的本来计划是支持表级的并行复制和行级的并行复制,行级的并行复制经过解析ROW格式的二进制日志的方式来完成, WL#4648 。可是最终出现给小伙伴的确是在开发计划中称为:MTS: Prepared transactions slave parallel applier,可见: WL#6314 

MySQL 5.7并行复制的思想简单易懂,一言以蔽之: 一个组提交的事务都是能够并行回放 ,由于这些事务都已进入到事务的prepare阶段,则说明事务之间没有任何冲突(不然就不可能提交)。

为了兼容MySQL 5.6基于库的并行复制,5.7引入了新的变量slave-parallel-type,其能够配置的值有:

  • DATABASE:默认值,基于库的并行复制方式
  • LOGICAL_CLOCK:基于组提交的并行复制方式

支持并行复制的GTID

如何知道事务是否在一组中,又是一个问题,由于原版的MySQL并无提供这样的信息。在MySQL 5.7版本中,其设计方式是将组提交的信息存放在GTID中。那么若是用户没有开启GTID功能,即将参数gtid_mode设置为OFF呢?故MySQL 5.7又引入了称之为Anonymous_Gtid的二进制日志event类型,如:

mysql> SHOW BINLOG EVENTS in 'mysql-bin.000006';
+------------------+-----+----------------+-----------+-------------+-----------------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+------------------+-----+----------------+-----------+-------------+-----------------------------------------------+
| mysql-bin.000006 | 4 | Format_desc | 88 | 123 | Server ver: 5.7.7-rc-debug-log, Binlog ver: 4 |
| mysql-bin.000006 | 123 | Previous_gtids | 88 | 194 | f11232f7-ff07-11e4-8fbb-00ff55e152c6:1-2 |
| mysql-bin.000006 | 194 | Anonymous_Gtid | 88 | 259 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| mysql-bin.000006 | 259 | Query | 88 | 330 | BEGIN |
| mysql-bin.000006 | 330 | Table_map | 88 | 373 | table_id: 108 (aaa.t) |
| mysql-bin.000006 | 373 | Write_rows | 88 | 413 | table_id: 108 flags: STMT_END_F |
......

  

这意味着在 MySQL 5.7版本中即便不开启GTID,每一个事务开始前也是会存在一个Anonymous_Gtid ,而这GTID中就存在着组提交的信息。

LOGICAL_CLOCK

然而,经过上述的SHOW BINLOG EVENTS,咱们并无发现有关组提交的任何信息。可是经过mysqlbinlog工具,用户就能发现组提交的内部信息

root@localhost:~# mysqlbinlog mysql-bin.0000006 | grep last_committed
#150520 14:23:11 server id 88 end_log_pos 259 CRC32 0x4ead9ad6 GTID last_committed=0 sequence_number=1
#150520 14:23:11 server id 88 end_log_pos 1483 CRC32 0xdf94bc85 GTID last_committed=0 sequence_number=2
#150520 14:23:11 server id 88 end_log_pos 2708 CRC32 0x0914697b GTID last_committed=0 sequence_number=3
#150520 14:23:11 server id 88 end_log_pos 3934 CRC32 0xd9cb4a43 GTID last_committed=0 sequence_number=4
#150520 14:23:11 server id 88 end_log_pos 5159 CRC32 0x06a6f531 GTID last_committed=0 sequence_number=5
#150520 14:23:11 server id 88 end_log_pos 6386 CRC32 0xd6cae930 GTID last_committed=0 sequence_number=6
#150520 14:23:11 server id 88 end_log_pos 7610 CRC32 0xa1ea531c GTID last_committed=6 sequence_number=7
#150520 14:23:11 server id 88 end_log_pos 8834 CRC32 0x96864e6b GTID last_committed=6 sequence_number=8
#150520 14:23:11 server id 88 end_log_pos 10057 CRC32 0x2de1ae55 GTID last_committed=6 sequence_number=9
#150520 14:23:11 server id 88 end_log_pos 11280 CRC32 0x5eb13091 GTID last_committed=6 sequence_number=10
#150520 14:23:11 server id 88 end_log_pos 12504 CRC32 0x16721011 GTID last_committed=6 sequence_number=11
#150520 14:23:11 server id 88 end_log_pos 13727 CRC32 0xe2210ab6 GTID last_committed=6 sequence_number=12
#150520 14:23:11 server id 88 end_log_pos 14952 CRC32 0xf41181d3 GTID last_committed=12 sequence_number=13
...

  

能够发现较之原来的二进制日志内容多了last_committed和sequence_number,last_committed表示事务提交的时候,上次事务提交的编号,若是事务具备相同的last_committed,表示这些事务都在一组内,能够进行并行的回放。例如上述last_committed为0的事务有6个,表示组提交时提交了6个事务,而这6个事务在从机是能够进行并行回放的。

上述的last_committed和sequence_number表明的就是所谓的LOGICAL_CLOCK

并行复制配置与调优

master_info_repository

务必将参数master_info_repostitory设置为TABLE,这样性能能够有50%~80%的提高。这是由于并行复制开启后对于元master.info这个文件的更新将会大幅提高,资源的竞争也会变大。在以前 InnoSQL 的版本中,添加了参数来控制刷新master.info这个文件的频率,甚至能够不刷新这个文件。由于刷新这个文件是没有必要的,即根据master-info.log这个文件恢复自己就是不可靠的。在MySQL 5.7中,Inside君推荐将master_info_repository设置为TABLE,来减少这部分的开销。

slave_parallel_workers

若将slave_parallel_workers设置为0,则MySQL 5.7退化为原单线程复制,但将slave_parallel_workers设置为1,则SQL线程功能转化为coordinator线程,可是只有1个worker线程进行回放,也是单线程复制。然而,这两种性能却又有一些的区别,由于多了一次coordinator线程的转发,所以slave_parallel_workers=1的性能反而比0还要差

配置:

【从库】

master_info_repository = TABLE
relay_log_info_repository = TABLE
relay_log_recovery = 1
slave-parallel-type = LOGICAL_CLOCK
slave-parallel-workers = 16
slave_preserve_commit_order=1
slave_transaction_retries=128

 

MySQL基于GTID的复制

GTID(global transaction identifiers)复制是彻底基于事务的复制,即每一个在主库上执行的事务都会被分配一个惟一的全局ID并记录和应用在从库上这种复制方式简化了创建slave和master/slave之间切换的工做,由于其彻底不须要找当前执行的bin log和log中的位置完成切换,一个GTID是master上执行的任何commit事务所分配的全局惟一ID标示,其由两部分组成:GTID = source_id:transaction_id
Source_id表明主库的server_uuid,transaction_id表明事务按顺序提交的ID,好比第一个提交则是1,第十个提交的事务就是10,GTID集合表明一组GTID

GTID复制原理

① 当一个事务在主库提交时,该事务就被赋予了一个GTID,并记录在主库的binary log
② 主库的binary log会被传输到从库的relay log中,从库读取此GTID并生成gtid_next系统参数
③ 从库验证此GTID并无在本身的binary log中使用,则应用此事务在从库上

mysql5.7.4开始;gtid_executed系统表记录同步复制的信息(UUID:事务号),这样就能够不用开启log_slave_updates参数,减小了从库的压力

GTID复制【】
主从同样都须要添加;同步记录会存放在mysql系统库的gtid_executed表中
gtid-mode=on
enforce-gtid-consistency=on
从库【】
stop slave ;
reset slave all;
CHANGE MASTER TO
MASTER_HOST=‘master_host_name’, ##主库的主机名
MASTER_PORT=port_number ##主库的端口号
MASTER_USER=‘replication_user_name’, ##复制的数据库用户名
MASTER_PASSWORD=‘replication_password’, ##复制的用户密码
MASTER_AUTO_POSITION = 1;
主从复制过程当中参数详解:
replicate-do-db :在从库定义的
binlog-do-db:在主库定义的,那些库中的修改能够记录到二进制日志中

使用GTID复制的限制条件:
因为GTID复制是依赖于事务的,因此MySQL的一些属性不支持,当一个事务中既包含对InnoDB表的操做,也包含对非事务型存储引擎表(MyISAM)的操做时,就会致使一个事务中可能会产生多个GTID的状况;或者是当master和slave的表使用的存储引擎不同时,都会致使GTID复制功能不正常
create table…select语句在基于语句复制的环境中是不安全的,在基于行复制的环境中,此语句会被拆分红两个事件,一是建立表,二是insert数据,在某些状况下这两个事件会被分配相同的GTID,而致使insert数据的操做被忽略,因此GTID复制不支持create table … select语句create/drop temporary table语句在GTID复制环境中不能放在事务中执行,只能单独执行,而且autocommit要开启sql_slave_skip_counter语句是不支持的,若是想要跳过事务,可使用gtid_executed变量

基于GTID复制跳过错误实际应用:

1.stop slave;
2.set GTID_NEXT='f0e1cd81-46cc-11e8-87fb-00163e321fb5:5600010'; 注:GTID_NEXT=Executed_Gtid_Set 当前执行的事物+1
3.begin; commit; 执行一个空事物
4.SET @@SESSION.GTID_NEXT= 'AUTOMATIC';
5.start slave

 

参考:

https://www.cnblogs.com/xiaotengyi/p/5532191.html