MySQL的复制是基于binlog来实现的。

流程如下

涉及到三个线程,主库的DUMP线程,从库的IO线程和SQL线程。

1. 主库将所有操作都记录到binlog中。当复制开启时,主库的DUMP线程根据从库IO线程的请求将binlog中的内容发送到从库。

2. 从库的IO线程接受到主库DUMP线程发送的binlog事件后,将其写到本地的relay-log。

3. 从库的SQL线程重放relay-log中的事件。

实际上,在MySQL 4.0之前,复制只有两个线程,master和slave端各一个。在Slave端,该线程同时负责接收主库发来的binlog事件,也负责事件的重放,所以没有使用relay-log,这样容易导致,当binlog事件的重放速度较慢时,会影响binlog事件的接受。

复制的搭建

基本步骤如下:

1. 配置主库和从库

2. 创建复制的账号

3. 创建主库一致性快照

4. 根据主库的快照,建立从库

5. 开启复制

详细步骤如下

1. 配置主库和从库

主库

开启binlog并设置server-id

[mysqld]
log-bin=mysql-bin
server-id=

在一组复制结构中,每个服务器必须配置一个唯一的server-id。该值的有效范围为1~232-1。

如果server-id设置为0的话,则MySQL会自动将它更改为1。此时,对复制没有影响。

如果server-id没有显式设置的话,则MySQL同样会将它设置为1,但是从连接的时候,IO线程会报错

Last_IO_Error: Got fatal error  from master when reading data from binary log: 'Misconfigured master - server_id was not set'

从库

设置server-id

[mysqld]
server-id=2

在从服务器上,可以选择不开启binlog。当开启了binlog后,如果想把重放的时间同样也记录到binlog中,可将log_slave_updates参数设置为1。

设置完毕后,重启数据库

2. 创建复制账号

主库上执行

mysql> CREATE USER 'repl'@'%.mydomain.com' IDENTIFIED BY 'slavepass';
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%.mydomain.com';

3. 创建主库一致性快照

在这里,我用mysqldump来创建数据库快照

# mysqldump --master-data=2  -R --single-transaction -A > 3306_20160815.sql

在生成的备份文件中,我们可以得到在对数据库执行一致性快照时主的状态,包括二进制文件的名称及位置

# head -30 3306_20160815.sql

...
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000016', MASTER_LOG_POS=120;
...

4. 根据主库的快照,建立从库

# mysql < 3306_20160815.sql

5. 开启复制

根据第3步获取到的主库状态执行CHANGE MASTER TO命令

mysql> CHANGE MASTER TO
MASTER_HOST='master_host_name',
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.info和relay-log.info中。如果没有显式指定MASTER_LOG_FILE,则默认为空,因为此时还没有和主库建立连接,并不知道主库binlog的文件名称,只有等到和主库建立连接时才能知道。如果MASTER_LOG_POS没有显式指定,则默认为4,即忽略binlog的头4个字节,从第一个事件开始读取。

开启复制功能

mysql> start slave;

查看复制的状态

mysql> show slave status\G

重点关注以下两个变量,如果为YES,则代表复制搭建成功。

...
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
...

注:以上搭建场景是基于主库上已经有一定的数据。如果在全新的环境中搭建,实际上会更简单。

只需获取主库的状态信息即可

mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000016 | 120 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec

MySQL复制的格式

MySQL的复制有三种格式:

Statement-based replication(SBR)

基于语句的复制,即master上执行的SQL语句原封不动的在slave上重放。该复制格式在MySQL 3.23即出现了。

优点:

1. 节省binlog的空间。

2. 可用于审核,毕竟所有的DML语句都是直接记录在binlog中。

缺点:

1. 很多函数在主从上执行的结果并不一致

LOAD_FILE(),UUID(), UUID_SHORT(),USER(),FOUND_ROWS(),SYSDATE(),GET_LOCK(),IS_FREE_LOCK(),IS_USED_LOCK(),MASTER_POS_WAIT(),RAND(),RELEASE_LOCK(),SLEEP(),VERSION()

2. DELETE和UPDATE操作,带了LIMIT子句,却没有带ORDER BY,可能导致主从执行的结果并不一致。

3. 相对于基于行的复制,master上执行INSERT ... SELECT操作需要更多的行锁。

4. 自定义函数(UDF)必须确保执行的结果是确定的。

Row-based replication(RBR)

基于行的复制,MySQL 5.1引入的,相对于SBR,它记录的是DML操作涉及到的行。

优点:

1. 安全。master上所有的变更都能复制到slave上。

2. 在执行以下操作时,只需更少的行锁。

INSERT ... SELECT

带有AUTO_INCREMENT列的INSERT操作

UPDATE和DELETE中,WHERE条件没有用上索引。

缺点:

1. 会产生大量的日志。

譬如一张表有1w条记录,如果我不带任何条件执行delete操作,则在基于statement的复制中,在binlog中只会记录delete from table这一条记录,但是在基于row的复制中,则会记录1w笔记录,每笔记录类似于delete from table where ..。

这会带来以下问题

1> 如果利用binlog进行恢复,会需要更长的时间.

2> 在写数据到binlog中时,因为数据量大,会导致binlog的锁定时间较长,影响数据库的并发。

3> 较大的日志会对磁盘IO和网络IO产生较大的压力。

4> 增大slave的延迟。

2. 不会对二进制日志进行校验。

3. 不推荐基于库级别的复制

包括--replicate-do-db, --replicate-ignore-db, --replicate-rewrite-db

MIXED

MIXED是上述两者的的结合,会根据执行的语句和涉及的存储引擎自动在这两种模式间切换。默认情况下,采用的是基于语句的复制模式,在遇到unsafe statements时,会切换为基于行的复制模式。

关于切换的条件,可参考官方文档:http://dev.mysql.com/doc/refman/5.7/en/binary-log-mixed.html

在MySQL 5.7.7之前,默认的是基于语句的复制模式,从MySQL 5.7.7开始,默认基于行的复制模式。

复制中涉及的文件

relay-log

relay-log保存着从库IO线程从主库读取到的binlog事件。和binlog格式一样,可通过mysqlbinlog解析其中的内容。

可通过配置relay_log和relay_log_index参数设置relay-log和relay-log.index文件的名称。

relay-log在如下情况下会发生切换:

1. slave IO线程启动的时候。

2. 执行FLUSH LOGS操作的时候。

3. 达到参数max_relay_log_size设置的大小,默认为0,即以max_binlog_size的值作为max_relay_log_size的大小。

slave SQL线程在重放完一个relay-log文件中的所有事件后,会自动删除relay-log文件(由relay_log_purge参数控制),所以没有显式删除relay-log的命令。

master.info

该文件保存了主库的主机名,端口,复制账号的用户名和密码,以及从库接受主库binlog事件的位置信息,通过这些位置信息,从库的IO线程知道下次从哪里获取主库的binlog事件。

该位置信息对应于show slave status\G中的Master_Log_File和Read_Master_Log_Pos。

如下所示:

# cat master.info

mysql-bin.

192.168.244.10
repl
repl 1800.000 cad449f2-5d4f-11e6-b353-000c29c64704

relay-log.info

该文件记录从库的重放信息,这样即便数据库发生重启,SQL线程也知道该从哪里开始重放。

该位置信息对应于show slave status\G中的Relay_Master_Log_File和Exec_Master_Log_Pos。

# cat relay-log.info

./mysqld-relay-bin.

mysql-bin.

Crash-Safe Replication

slave每次接受binlog或者应用relay-log时,都要修改master.info或relay-log.info的信息并同步到磁盘中,这会导致大量的磁盘操作,所以,一般都是采用异步方式来对这两个文件进行更改。虽然每次都会修改这些文件,但是持久化到磁盘却留给操作系统处理。在内存与磁盘中的信息不一致时,如果此时操作系统宕机,内存中的信息将无法及时同步到磁盘中。操作系统恢复后,master.info和relay-log.info的数据依然是旧的,所以会从已经执行的部分重新执行。

MySQL 5.6为了改善这个问题,提供了两个参数,可将master.info和relay-log.info中的内容保存在表中而不是磁盘文件中。

master-info-repository

可设置为TABLE或FILE,如果使用FILE,则复制的位置信息依旧保存在master.info中,如果设置为TABLE,则信息报保存在mysql.slave_master_info中,默认为FILE。

relay-log-info-repository

可设置为TABLE或FILE,如果使用FILE,则应用relay-log的信息会保存在relay-log.info中,如果设置为TABLE,则保存在mysql.slave_relay_log_info中,默认为FILE。

通过将上述两个变量设置为TABLE,可实现“Crash-Safe Replication”,上述的相关操作都会放到一个事务中进行。

总结

1. 启用复制功能并不会增加服务器太多的开销,主要是开启binlog带来的开销,包括binlog文件的追加写操作开销,以及系统调用fsync带来的开销。

2. MySQL的复制功能具有向后兼容性,因为较新版本的MySQL的binlog中会进入新的事件类型。所以,可以将较新版本的MySQL作为从库。

3. MySQL复制是异步的。

4. MySQL 5.6开始新增延迟复制功能,由master_delay参数来控制。

参考

1. http://dev.mysql.com/doc/refman/5.7/en/replication-configuration.html

2. MariaDB原理与实现

浅析MySQL复制的更多相关文章

  1. 浅析MySQL数据碎片的产生(data free)

    浅析MySQL数据碎片的产生 2011-03-30 09:28 核子可乐译 51CTO 字号:T | T MySQL列表,包括MyISAM和InnoDB这两种最常见的类型,而根据经验来说,其碎片的产生 ...

  2. mysql复制那点事(2)-binlog组提交源码分析和实现

    mysql复制那点事(2)-binlog组提交源码分析和实现 [TOC] 0. 参考文献 序号 文献 1 MySQL 5.7 MTS源码分析 2 MySQL 组提交 3 MySQL Redo/Binl ...

  3. MySQL复制环境(主从/主主)部署总结性梳理

    Mysql复制概念说明Mysql内建的复制功能是构建大型,高性能应用程序的基础.将Mysql的数据分布到多个系统上去,这种分布的机制,是通过将Mysql的某一台主机的数据复制到其它主机(slaves) ...

  4. MYSQL复制

    今天我们聊聊复制,复制对于mysql的重要性不言而喻,mysql集群的负载均衡,读写分离和高可用都是基于复制实现.下文主要从4个方面展开,mysql的异步复制,半同步复制和并行复制,最后会简单聊下第三 ...

  5. mysql复制一列到另一列

    mysql复制一列到另一列   UPDATE 表名 SET B列名=A列名 需求:把一个表某个字段内容复制到另一张表的某个字段. 实现sql语句1: 复制代码代码如下: UPDATE file_man ...

  6. MySQL 复制介绍及搭建

    MySQL复制介绍 MySQL复制就是一台MySQL服务器(slave)从另一台MySQL服务器(master)进行日志的复制然后再解析日志并应用到自身,类似Oracle中的Data Guard. M ...

  7. 转mysql复制主从集群搭建

    最近搭了个主从复制,中间出了点小问题,排查搞定,记录下来 1环境:虚拟机:OS:centos6.5Linux host2 2.6.32-431.el6.x86_64 #1 SMP Fri Nov 22 ...

  8. MySQL复制表结构表数据

    MySQL复制表结构 表数据 1.复制表结构及数据到新表CREATE TABLE 新表 SELECT * FROM 旧表这种方法会将oldtable中所有的内容都拷贝过来,当然我们可以用delete ...

  9. MySQL复制的基本概念和实现

    MySQL的复制的概念是完成水平扩展的架构 MySQL性能方面的扩展方式有scale on(向上扩展,垂直扩展)                          scale out(向外扩展,水平扩 ...

随机推荐

  1. ASP.NET MVC5+EF6+EasyUI 后台管理系统(71)-微信公众平台开发-公众号管理

    系列目录 思维导图 下面我们来看一个思维导图,这样就可以更快了解所需要的功能: 上一节我们利用了一个简单的代码例子,完成了与微信公众号的对话(给公众号发一条信息,并得到回复) 这一节将讲解公众号如何设 ...

  2. Linux学习之探索文件系统

    Linux,一起学习进步-    ls With it, we can see directory contents and determine a variety of important file ...

  3. 分布式学习系列【dubbo入门实践】

    分布式学习系列[dubbo入门实践] dubbo架构 组成部分:provider,consumer,registry,monitor: provider,consumer注册,订阅类似于消息队列的注册 ...

  4. Android中Fragment和ViewPager那点事儿(仿微信APP)

    在之前的博文<Android中使用ViewPager实现屏幕页面切换和引导页效果实现>和<Android中Fragment的两种创建方式>以及<Android中Fragm ...

  5. git

    CMD命令:git initgit add . [添加文件至暂存区]git commit -m '描述性语句 随意写即可'git branch gh-pages [创建仓库分支]git checkou ...

  6. linux之查看系统命令

    cpu信息 1.查看逻辑cpu核数 # cat /proc/cpuinfo| grep "processor"| wc -l 2.查看物理cpu个数 # cat /proc/cpu ...

  7. 超千个节点OpenStack私有云案例(1):CERN 5000+ 计算节点私有云

    CERN:欧洲核子研究组织 本文根据以下几篇文章整理而来: https://www.openstack.org/summit/tokyo-2015/videos/presentation/unveil ...

  8. RabbitMQ基础知识

    RabbitMQ基础知识 一.背景 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现.AMQP 的出现其实也是应了广大人民群众的需求,虽然 ...

  9. CSharpGL(14)用geometry shader渲染模型的法线(normal)

    +BIT祝威+悄悄在此留下版了个权的信息说: CSharpGL(14)用geometry shader渲染模型的法线(normal) +BIT祝威+悄悄在此留下版了个权的信息说: 2016-08-13 ...

  10. Java继承

    Java只支持单继承,不支持多继承. 一个类只能有一个父类,不可以有多个父类. class SubDemo extends Demo{} //ok class SubDemo extends Demo ...