浅析 MySQL Replication(转)
目前很多公司中的生产环境中都使用了MySQL Replication ,也叫 MySQL 复制,搭建配置方便等很多特性让 MySQL Replication 的应用很广泛,我们曾经使用过一主拖20多个从库来分担业务压力。关于 MySQL Replication 的文章网络上也有很多,但大多数都是讲如何搭建MySQL Replication,并没有说清楚如何才能搭建出高可靠的MySQL Replication。这篇文章也对半同步复制,无损复制,多源复制做了讲解。
复制有哪些用途
• 读写分离
• 灾备
• 高可用
• 线下统计
• 备份
复制是如何工作的
从上图中可以看到,复制的主要步骤:
1 master 将改变记录到二进制日志 binary log 中
2 slave 上的IO线程将主库上的日志复制到自己的 relay log 中
3 slave 上SQL线程回放中继日志的内容,使 slave 上的数据与 master 达到一致
binlog 二进制日志文件,用于记录 MySQL 的数据变更。
relay-log 中继日志文件,slave 的I/O线程读取 master 的 Binlog,记录到 relay-log 中,然后 SQL 线程会读取 relay-log 日志的内容并应用到 slave 服务器。
Binlog 记录的格式
STATEMENT(记录操作的SQL语句)
• 优点 减少了 Binlog 日志量,节约IO,提高性能,易于理解
• 缺点 不是所有的DML语句都能被复制,有些函数UUID()、FOUND_ROWS()、USER() 也无法被复制
ROW(记录操作的每一行数据的变化信息,RC 隔离级别,必须是 row 格式)
• 优点 任何情况都可以被复制,ROW 模式是最安全可靠的
• 缺点 产生大量的日志,特别是 copy data 的 DDL 会让日志暴涨
• 建议表一定要有主键
MIXED (混合模式)
• 先使用 STATEMENT 模式记录 Binlog ,对于 STATEMENT 模式无法复制的操作使用 ROW 模式保存 Binlog,MySQL 会根据执行的 SQL 语句选择日志记录方式。Bug 较多,不建议使用。
Binlog Events
我们都知道 Binlog 日志用于记录所有对 MySQL 的操作的变更,而这每一个变更都会对应的事件,也就是 Event,index文件记录了所有的 Binlog 位置,每个 Binlog 会有 header event,rotate 三个 event,Binlog 的结构如下。
常见的Event如下:
• Format_desc:全新的binlog日志文件
• Rotate :日志分割
• Table_map:表,列等元数据
• Query:查询
• Write_rows: 插入
• Update_rows:更新
• Delete_rows:删除
在了解了以上基础的内容后,我们可以带着以下的三个问题去学习复制到底是怎样工作的。
• 事务是如何提交的?事务提交先写 binlog 还是 redo log?
• 为什么 MySQL 有 binlog,还有redo log?
• 如何保证这两部分的日志做到一致性?
务是如何提交的?事务提交先写 binlog 还是 redo log?
以上的图片中可以看到,事务的提交主要分三个主要步骤:
1 InnoDB 层写 prepare log,此时SQL已经成功执行,并生成 xid 信息及 redo 和 undo 的内存日志,写入 redo log file
2 MySQL Server 层写 binlog (write --》 fsync)
3 InnoDB 层写 commit log, InnoDB存储引擎内提交,使 undo 和 redo 永久写入磁盘
为什么 MySQL 有 binlog,还有 redo log?
这个是因为 MySQL 体系结构的原因,MySQL 是多存储引擎的,不管使用那种存储引擎,都会有 binlog,而不一定有 redo log,简单的说,binlog 是 MySQL Server 层的,redo log 是 InnoDB 层的。
如何保证这两部分的日志做到一致性?
事务提交的过程上面已经说到,需要写 redo log 还要写 binlog,那么如何保证数据的一致性呢,如果不能保证写这两个文件在同一事务中,那么就会造成数据不一致,这个不一致包括MySQL crash时和主从复制的数据不一致。
面试时经常会问的一个问题,影响MySQL写入性能、数据一致性的参数有哪些?无疑是 双一参数 innodb_flush_log_at_trx_commit 和sync_binlog, 这两个参数是控制 MySQL 磁盘写入策略以及数据安全性的关键参数,MySQL 为了保证 master 和 slave 的数据一致性,就必须保证 binlog 和 InnoDB redo 日志的一致性。
参数说明如下:
innodb_flush_log_at_trx_commit(redo)
• 0 log buffer 每秒一次地写入 log file 中,且进行 flush 操作
• 1 每次事务提交时都会把 log buffer 的数据写入 log file,并进行 flush 操作
• 2 每次事务提交时 MySQL 都会把 log buffer 的数据写入 log file,不进行 flush 操作
sync_binlog (binlog)
• 0 刷新binlog_cache中的信息到磁盘由os决定
• N 每N次事务提交刷新binlog_cache中的信息到磁盘
那么如何保证 binlog 和 InnoDB redo 日志的一致性,MySQL 使用内部分布式事物来保证一致性,MySQL
在 prepare 阶段会生成 xid,xid 会写入prepare
log中,也会写入到binlog中,当恢复时会对比此事务的xid在两个文件中是否都有,如果都存在该xid对应的事物会提交,反之会rollback此事务,下面是几种情况分析:
1 当事务在 prepare 阶段 crash,将该事务 rollback。
2 当事务在 binlog 阶段 crash,此时日志还没有成功写入到磁盘中,启动时会 rollback 此事务
3 当事务在 binlog 日志已经 fsync() 到磁盘后 crash,但是InnoDB没有来得及 commit,此时 MySQL 启动时会重新将该事务重做并 commit,使 InnoDB 存储引擎的 redo log 和 binlog 始终保持一致。
总结起来说就是如果一个事物在 prepare log 阶段中落盘成功,并在 MySQL Server 层中的 binlog 也写入成功,那这个事务必定commit成功。
组提交
现在回头看事务是如何提交的那张图,会发现innodb层每个事务是并行的,但是在写binlog时,MySQL
Server层就变成了串行,这是因为每次提交都会去申请prepare_commit_mutex这把锁造成的,在MySQL
5.6版本中,提供了Binary Log Group Commit 也就是组提交,Group Commit分为了三个阶段。
• Flush stage:Leader线程遍历FLUSH_STAGE链表,写入binary log缓存
• Sync stage :将binlog缓存sync到磁盘,当sync_binlog=1时所有该队列事务的二进制日志缓存永久写入磁盘
• Commit stage: leader根据顺序让InnoDB存储引擎完成Commit
下面是我们测试组提交的一张图,可以看到组提交的TPS高不少。
1062、1053复制错误
可能DBA在使用MySQL Replication的过程中,在slave 宕机或异常时,会遇到1062等错误,大家都是使用以下方式解决。
• SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1
• GTID 通过空事务方式
但为什么数据会冲突呢?我们分解下复制的步骤,这里有张图很好,图片来自于网络。
我们可以看到这里有保存Replication matadata的两个文件,
• relay-info.log保存了SQL线程回放到的Relay_log_name和Relay_log_pos,以及对应的Master的Master_log_name和Master_log_pos。
• master-info.log保存了连接master的用户,密码,端口,Master_log_name 和 Master_log_pos等信息。
如下图,如果SQL线程正在回放,回放完后,还没来的及写到Replication matadata的文件中,就宕机了,此时重启slave后,就会出现1062错误。
在MySQL
5.6中,提供了SQL/IO thread
crash-safe特性。通过将relay_log_info_repository=TABLE,relay-info将信息写入到mysql.slave_relay_log_info这张表中,不但可以保证一致性(写文件变成同一事物的原子操作),还提高了写入性能。
如上图。IO thread同理,稍有不同的是 relay-log-recover 设置为1后,slave 的 IO thread 读取 events 时,会根据从 SQL thread 回放到的位置重新读取。
复制最优的参数配置
上面讲了这么多,其实就是得出 MySQL Replication 的最可靠的参数配置。
master:
binlog_format = ROW
transaction-isolation = READ-COMMITTE
Dexpire_logs_days = 30
server-id = 327
sync_binlog = 1
innodb_flush_log_at_trx_commit = 1
innodb_support_xa = 1
slave:
log_slave_updates=1
server-id = 328
relay_log_recover = 1
relay_log_info_repository = TABLE
master_info_repository = TABLE
read_only = 1
如何提高复制效率?
MySQL
5.6提供了并行复制,但是这种并行只是基于database的。如果是基于单database的依然无法做到真正的并行回放,这个阶段很多DBA将数据库进行垂直拆分,将一个database拆分成几个database,通过设置slave_parallel_workers=n,可以进行database级别的并行复制,但对于热点业务复制延迟依然无法解决。
MySQL
5.6版本中还引入了GTID,不但降低了主从failover时,寻找filename,position的难度,更是加入到了组提交中,这也造就了MySQL
5.7版本中的Multi-Threaded Slave的出现。如下图,一组中的事务,可以并行回放。
在下图的测试中,MySQL 5.7的多线程复制极大的提升了延迟效率,在30个线程并发操作的时候还能保证平均延迟5.9秒左右,而单线程复制的延迟率基本一直在上升。
Multi-Threaded Slave 相关参数
slave-parallel-type= DATABASE /LOGICAL_CLOCK
-- DATABASE -- 基于库级别的并行复制 与5.6相同
-- LOGICAL_CLOCK -- 逻辑时钟,主上怎么并行执行,从上怎么回放。
slave-parallel-workers=16
-- 并行复制的线程数
slave_preserve_commit_order=1
--commit的顺序保持一致
半同步
我们都知道,默认的
MySQL Replication 复制为异步模式,异步也就说明会有丢失数据的可能性,MySQL在5.5版本中提供了 semi-sync
replication,也就是半同步,但半同步只能说减少数据丢失的风险,所以在 MySQL 5.7版本中,MySQL 提供了 lossless
semi-sync replication,也就是无损复制,可最低限度的减少数据丢失(无损复制会和半同步一样在出问题时会切换为异步复制)。
在半同步中,至少有一个Slave节点收到binlog后再返回,不能完全避免数据丢失,超时后,切回异步复制。在事物提交的过程中,在InnoDB层的
commit log 阶段后,Master 节点需要收到至少一个Slave节点回复的ACK后,才能继续下一个事物。
无损复制
在无损复制中,master把binlog发送给slave,只有在slave把binlog写到本地的relay-log里,master才会将事务提交到存储引擎层,然后把请求返回给客户端,客户端才可以看见刚才提交的事务。在一个事物提交的过程中,在MySQL
Server 层的 binlog阶段后,Master节点需要收到至少一个Slave节点回复的ACK后,才能继续下一个事物。
半同步复制与无损复制的对比
ACK的时间点不同
• 半同步复制在InnoDB层的Commit Log后,等待ACK。
• 无损复制在MySQL Server层的Write binlog后,等待ACK。
主从数据一致性
• 半同步复制意味着在Master节点上,这个刚刚提交的事物对数据库的修改,对其他事物是可见的。
• 无损复制在write binlog完成后,就传输binlog,但还没有去写commit log,意味着当前这个事物对数据库的修改,其他事物也是不可见的。
半同步相关参数
rpl_semi_sync_master_enabled=1
rpl_semi_sync_slave_enabled=1
rpl_semi_sync_master_timeout=1000
rpl_semi_sync_master_wait_for_slave_count=1
rpl_semi_sync_master_wait_point=AFTER_SYNC
rpl_semi_sync_master_wait_for_slave_count=1
半同步相关事件统计
Rpl_semi_sync_master_tx_avg_wait_time
--开启Semi_sync,平均需要额外等待的时间
Rpl_semi_sync_master_net_avg_wait_time
--事务进入等待队列后,到网络平均等待时间Semi-sync的网络消耗有多大。
Rpl_semi_sync_master_status
-- 则表示当前Semi-sync是否正常工作
Rpl_semi_sync_master_no_times
--可以知道一段时间内,Semi-sync是否有超时失败过,记录了失败次数。
multi-source
然而在MySQL 5.7版本中,提供了多源复制,多源复制的出现对于分库分表的业务提供了极大的便利,目前我们已经部署了多套多源复制供统计使用。
如上图,多源复制采用多通道的模式,和普通的复制相比,就是使用FOR CHANNEL进行了分离。
CHANGE MASTER TO .... FOR CHANNEL ‘m1';
CHANGE MASTER TO .... FOR CHANNEL ‘m2';
上面我们也说到,为了提高复制效率,很多DBA会根据业务进行DB拆分,但拆分后又面临一个新的问题,就是join,join绝对是关系型数据库中最常用一个特性,然而在分布式的环境中,join是最难解决的一个问题,使用多源复制就能很好的解决这个问题。
如果数据库,表名一致如何使用多源复制?,其实只要解决了数据冲突的问题就可以使用。
如上图的分库分表架构,可以使用以下参数实现奇偶插入的方式去解决。
auto_increment_offset=1…n
auto_increment_increment=n
但这种方式需要提前考虑扩展性。
参考:
http://dev.mysql.com/doc/
WeChat:mysqlcode
https://www.percona.com/blog/2013/09/13/enabling-crash-safe-slaves-with-mysql-5-6/
http://hamilton.duapp.com/detail?articleId=42
浅析 MySQL Replication(转)的更多相关文章
- 浅析 MySQL Replication(本文转自网络,非本人所写)
作者:卢飞 来源:DoDBA(mysqlcode) 0.导读 本文几乎涵盖了MySQL Replication(主从复制)的大部分知识点,包括Replication原理.binlog format.复 ...
- 浅析 MySQL Replication(本文转自网络)
作者:卢飞 来源:DoDBA(mysqlcode) 0.导读 本文几乎涵盖了MySQL Replication(主从复制)的大部分知识点,包括Replication原理.binlog format.复 ...
- MySQL Replication浅析
MySQL Replication是MySQL非常出色的一个功能,该功能将一个MySQL实例中的数据复制到另一个MySQL实例中.整个过程是异步进行的,但由于其高效的性能设计,复制的延时非常小.MyS ...
- MySQL Replication需要注意的问题
MySQL Replication 大家都非常熟悉了,我也不会写怎么搭建以及复制的原理,网上相关文章非常多,大家可以自己去搜寻.我在这里就是想总结一下mysql主从复制需要注意的地方.有人说主从复制很 ...
- mysql replication principle--转
原文地址:http://www.codeweblog.com/mysql-replication-principle/ 1, the replication process Mysql replica ...
- 浅析MySQL数据碎片的产生(data free)
浅析MySQL数据碎片的产生 2011-03-30 09:28 核子可乐译 51CTO 字号:T | T MySQL列表,包括MyISAM和InnoDB这两种最常见的类型,而根据经验来说,其碎片的产生 ...
- MySql Replication配置
一.前言 Mysql Replication作为读写分离的廉价解决方案,支持一主多备的方式进行数据存储,采用二进制日志传送,目前存在着广泛应用,网上相关概念也比较多,不再重复介绍.引用一张官方提供的R ...
- MySQL Replication 优化和技巧、常见故障解决方法
MySQL 主从同步错误(error)解决(转) sql_slave_skip_counter参数 附: 一些错误信息的处理,主从服务器上的命令,及状态信息. 在从服务器上使用show slave s ...
- 浅谈MySQL Replication(复制)基本原理
1.MySQL Replication复制进程MySQL的复制(replication)是一个异步的复制,从一个MySQL instace(称之为Master)复制到另一个MySQL instance ...
随机推荐
- Linux内核分析第五周 扒开系统调用的三层皮(下) (20135304 刘世鹏)
作者:刘世鹏20135304 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.给MenuOS增加t ...
- 20145325张梓靖 《Java程序设计》第16周课程总结
20145325张梓靖 <Java程序设计>第16周课程总结 实验报告链接汇总 实验一 "Java开发环境的熟悉" 实验二 "Java面向对象程序设计&quo ...
- [微信开发] - weixin4j关键类解析
TokenUtil : get()获取我方自定义的token(从配置文件或数据库) checkSignature(Str..... (服务器配置连接验证有效性) /* * 微信公众平台(JAVA) S ...
- MySQL分页查询大数据量优化方法
方法1: 直接使用数据库提供的SQL语句 语句样式: MySQL中,可用如下方法: SELECT * FROM 表名称 LIMIT M,N适应场景: 适用于数据量较少的情况(元组百/千级)原因/缺点: ...
- Android Studio之高德地图实现定位和3D地图显示
在应用开发中,地图开发是经常需要使用的“组件”,国内比较出名的是就是百度地图和高德地图. 此博客讲的是高德地图实现定位和3D地图显示,并标注相应位置,话不多说,先看看效果,在上代码. 效果如图: 首先 ...
- javascript 时间与时间戳的转换
一:时间转时间戳:javascript获得时间戳的方法有五种,都是通过实例化时间对象 new Date() 来进一步获取当前的时间戳 1.var timestamp1 = Date.parse(new ...
- Unsupported major.minor version 51.0解决办法(转)
我使用的是Eclipse-jee-indigo + JDK 1.6.23环境,结果使用时出现Unsupported major.minor version 51.0错误提示,下面我来介绍Unsuppo ...
- 297. Serialize and Deserialize Binary Tree *HARD*
Serialization is the process of converting a data structure or object into a sequence of bits so tha ...
- IOS-网络(发送JSON数据给服务器和多值参数)
三步走: 1.使用POST请求 2.设置请求头 [request setValue:@"application/json" forHTTPHeaderField:@"Co ...
- LINUX 操作记录到syslog,并发送到syslog服务器上
首先配置命令记录到syslog中: 在客户端的/etc/bashrc 下添加: logger -p local3.info \"`who am i` ================== ...