浅析MySQL复制
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复制的更多相关文章
- 浅析MySQL数据碎片的产生(data free)
浅析MySQL数据碎片的产生 2011-03-30 09:28 核子可乐译 51CTO 字号:T | T MySQL列表,包括MyISAM和InnoDB这两种最常见的类型,而根据经验来说,其碎片的产生 ...
- mysql复制那点事(2)-binlog组提交源码分析和实现
mysql复制那点事(2)-binlog组提交源码分析和实现 [TOC] 0. 参考文献 序号 文献 1 MySQL 5.7 MTS源码分析 2 MySQL 组提交 3 MySQL Redo/Binl ...
- MySQL复制环境(主从/主主)部署总结性梳理
Mysql复制概念说明Mysql内建的复制功能是构建大型,高性能应用程序的基础.将Mysql的数据分布到多个系统上去,这种分布的机制,是通过将Mysql的某一台主机的数据复制到其它主机(slaves) ...
- MYSQL复制
今天我们聊聊复制,复制对于mysql的重要性不言而喻,mysql集群的负载均衡,读写分离和高可用都是基于复制实现.下文主要从4个方面展开,mysql的异步复制,半同步复制和并行复制,最后会简单聊下第三 ...
- mysql复制一列到另一列
mysql复制一列到另一列 UPDATE 表名 SET B列名=A列名 需求:把一个表某个字段内容复制到另一张表的某个字段. 实现sql语句1: 复制代码代码如下: UPDATE file_man ...
- MySQL 复制介绍及搭建
MySQL复制介绍 MySQL复制就是一台MySQL服务器(slave)从另一台MySQL服务器(master)进行日志的复制然后再解析日志并应用到自身,类似Oracle中的Data Guard. M ...
- 转mysql复制主从集群搭建
最近搭了个主从复制,中间出了点小问题,排查搞定,记录下来 1环境:虚拟机:OS:centos6.5Linux host2 2.6.32-431.el6.x86_64 #1 SMP Fri Nov 22 ...
- MySQL复制表结构表数据
MySQL复制表结构 表数据 1.复制表结构及数据到新表CREATE TABLE 新表 SELECT * FROM 旧表这种方法会将oldtable中所有的内容都拷贝过来,当然我们可以用delete ...
- MySQL复制的基本概念和实现
MySQL的复制的概念是完成水平扩展的架构 MySQL性能方面的扩展方式有scale on(向上扩展,垂直扩展) scale out(向外扩展,水平扩 ...
随机推荐
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(71)-微信公众平台开发-公众号管理
系列目录 思维导图 下面我们来看一个思维导图,这样就可以更快了解所需要的功能: 上一节我们利用了一个简单的代码例子,完成了与微信公众号的对话(给公众号发一条信息,并得到回复) 这一节将讲解公众号如何设 ...
- Linux学习之探索文件系统
Linux,一起学习进步- ls With it, we can see directory contents and determine a variety of important file ...
- 分布式学习系列【dubbo入门实践】
分布式学习系列[dubbo入门实践] dubbo架构 组成部分:provider,consumer,registry,monitor: provider,consumer注册,订阅类似于消息队列的注册 ...
- Android中Fragment和ViewPager那点事儿(仿微信APP)
在之前的博文<Android中使用ViewPager实现屏幕页面切换和引导页效果实现>和<Android中Fragment的两种创建方式>以及<Android中Fragm ...
- git
CMD命令:git initgit add . [添加文件至暂存区]git commit -m '描述性语句 随意写即可'git branch gh-pages [创建仓库分支]git checkou ...
- linux之查看系统命令
cpu信息 1.查看逻辑cpu核数 # cat /proc/cpuinfo| grep "processor"| wc -l 2.查看物理cpu个数 # cat /proc/cpu ...
- 超千个节点OpenStack私有云案例(1):CERN 5000+ 计算节点私有云
CERN:欧洲核子研究组织 本文根据以下几篇文章整理而来: https://www.openstack.org/summit/tokyo-2015/videos/presentation/unveil ...
- RabbitMQ基础知识
RabbitMQ基础知识 一.背景 RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue )的开源实现.AMQP 的出现其实也是应了广大人民群众的需求,虽然 ...
- CSharpGL(14)用geometry shader渲染模型的法线(normal)
+BIT祝威+悄悄在此留下版了个权的信息说: CSharpGL(14)用geometry shader渲染模型的法线(normal) +BIT祝威+悄悄在此留下版了个权的信息说: 2016-08-13 ...
- Java继承
Java只支持单继承,不支持多继承. 一个类只能有一个父类,不可以有多个父类. class SubDemo extends Demo{} //ok class SubDemo extends Demo ...