MySQL 复制 - 性能与扩展性的基石 1:概述及其原理
1. 复制概述
MySQL 内置的复制功能是构建基于 MySQL 的大规模、高性能应用的基础,复制解决的基本问题是让一台服务器的数据与其他服务器保持同步。
接下来,我们将从复制概述及原理、复制的配置、常见的问题及解决方法来学习 MySQL 的复制功能。
1.1 复制解决的问题
下面是复制常见的用途:
- 数据分布。Mysql 复制通常不会对带宽造成很大压力,但在 5.1 版本中引入的基于行的复制会比传统的基于语句的复制模式产生更大的带宽压力。你可以随意地停止或开始复制,并在不同的地理位置来分布数据备份,例如不同的数据中心。另外,即使在不稳定的网络环境下,远程复制也可以工作。但如果未来保存很低的复制延迟,最好有一个稳定、低延迟的连接。
- 负载均衡。通过 Mysql 复制,可以将读操作分布到多个服务器上,实现对读密集型应用的优化,并且很容易实现,通过简单的代码修改就能实现基本的负载均衡。对应小规模的应用,可以简单的使用 DNS 轮询(将一个机器名指向多个 IP 地址)。
- 备份。对于备份来说,负载是一项很有意义的技术补充。
- 高可用性和故障切换。负载能够帮助应用避免 Mysql 单点失败,一个使用复制的设计良好的系统能够显著的缩短宕机时间。
- Mysql 升级测试。这是比较常见的做法,在更新 Mysql 版本前,先使用将要更新的版本作为备库,保证更新版本不会对系统造成影响。
1.2 复制是如何工作的?
在详细介绍如何设置复制之前,让我们先看看 Mysql 实际上是如何进行数据复制的。
总的来说,复制有三个步骤:
- 在主库上把数据更改写入到二进制日志(Binary Log)中(这些记录被称为二进制日志事件)。
- 备库将主库上的日志复制到自己的中继日志(Relay Log)中。
- 备库读取中继日志中的事件,将其更改同步到备库。
以上是复制的简单概述,下图描述了复制的细节:
整体复制过程:
- 在主库上记录二进制日志。在每次准备提交事务完成 数据更新前,主库将数据更新的事件记录到二进制日志中。Mysql 会按事务提交的顺序而非每条语句的执行顺序来记录二进制日志。在记录二进制日志后,主库会告诉存储引擎可以提交事务了。
- 备库将主库的二进制日志复制到其本地的中继日志中。首先,备库会启动一个工作线程,称为 I/O 线程,I/O 线程跟主库建立一个普通的客户端连接,然后在主库上启动一个特殊的二进制转储(binlog dump)线程,这个二进制转储线程会读取主库二进制日志中的事件。它不会对时间进行轮询。如果该线程“追赶”上了主库,它将进入睡眠状态,直到主库发送信号量通知它有新的事件产生才会被换新,备库 I/O 线程会将接收到的事件记录到中继日志中。
- 备库启动 SQL 线程,执行最后一步。该线程从中继日志中读取事件并在备库执行,从而实现备库数据的更新。当 SQL 线程追赶上 I/O 线程时,中继日志通常已经在系统缓存中,所以中继日志的开销很低。SQL 线程执行的事件也可以通过配置项来决定是否写入自身的二进制日志中,这对于备库再配置备库的常见非常有用。
这种复制架构实现了获取事件和重放事件的解耦,允许这两个过程异步进行。也就是说 I/O 线程能够独立于 SQL 线程之前工作。但是,这种架构也限制了复制的过程,其中最重要的一点是,在主库上并发运行的查询在备库上只能串行化执行,因为只有一个 SQL 线程来重放中继日志中的事件。
不过值得高兴的是,5.7 版本已经支持从库的并行复制了。基于二进制日志的并行复制,是在日志内容中新增了 last_committed 和 sequence_number,分别 表示事务提交的时间和上次事务提交的编号。如果事务具有相同的时间,表示这些事务是在一组内,可以进行并行回放。
2. 复制的原理
我们已经了解了复制的一些基本概念,接下来我们要更深入的了解复制,看看复制究竟是如何工作的,有哪些优缺点。
2.1 基于语句的复制
在 Mysql 5.0 及之前的版本中只支持基于语句的复制(也称为逻辑复制)。基于语句的复制模式,主库会记录那些造成数据更改的 SQL 语句,当备库读取并重放这些事件时,实际上只是把主库执行过的 SQL 再执行一遍。这种方式既有优点,也有缺点。
优点是:
- 实现简单。理论上来说,只要简单地记录和执行 SQL 语句,就能够让主备保持同步。
- 二进制日志不会对带宽产生较大影响。二进制日志里的事件更加紧凑,占用带宽较小。
但事实上,基于语句的方式可能并不如其看起来那么便利,其缺点是:
- 主库上的数据除了执行的语句外,可能还依赖其他因素。当主库使用 CURRENT_USER() 函数的语句,存储过程和触发器在使用基于语句的复制模式时就可能会出现问题。
2.2 基于行的复制
Mysql 5.1 开始支持基于行的复制。这种方式会将实际数据记录在二进制日志中。同样的,它也有其自身的优缺点。
它的优点是可以更加准确的复制数据,而缺点,则是可能造成较大的开销。比如一个工资表中有一万个用户,我们把每个用户的工资+1000,那么基于行的复制则要复制一万行的内容,由此造成的开销比较大,而基于语句的复制仅仅一条语句就可以了。
由于没有哪种模式是对所有情况都是完美的,Mysql 就使复制模式可以动态切换。默认情况下使用的是基于语句的复制方式,但如果发现语句无法被正确地复制,就切换到基于行的复制模式。还可以根据需要来设置会话级别的变量 binlog_format,控制二进制日志格式。
2.3 复制文件解读
复制过程中会使用到一些文件。前面已经介绍了二进制日志文件和中继日志文件,除此之外,还有其他的文件会被用到。
- mysql-bin.index:当在服务器上开启二进制日志时,同时会生成一个和二进制日志同名,但以 .index 作为后缀的文件,该文件用于记录磁盘上的二进制日志文件。这里的 index 并不是表的索引,而是说这个文件的每一行包含了二进制文件的文件名。Mysql 依赖这个文件识别二进制日志文件。
- mysql-relay-bin-index:中继日志的索引文件,和 mysql-bin.index 的作用类似。
- master.info:保存备库连接主库所需要的信息文件。格式为纯文本(每行一个值),不同的 Mysql 版本,记录的信息也可能不太。此文件不能删除,否则备库再重启后不能连接主库。这个文件以文本的方式记录了复制用户的密码,所以要注意此文件的权限控制。
- relay-log.info:记录当前备库复制的二进制日志和中继日志位置文件。
使用这些文件来记录 Mysql 复制和日志状态是一种非常粗糙的方式。更不幸的是,它们不是同步写的。如果服务器断电并且文件数据没有被刷新到磁盘,在重启服务器后,文件中记录的数据可能是错误。不过好在这些问题以及在 5.5 版本里做了改进。
2.4 发送复制事件到其它备库
log_slave_update 选项可以让备库编程其它服务器的主库。在设置该选项后,Mysql 会将其执行过的事件记录到它自己的二进制日志中。这样它的备库就可以从其日志中检索并执行事件。下图阐述了这一过程:
在这种场景下,主库将数据更新事件写入二进制日志,第一个备库提取并执行这个事件。这个时候一个事件的生命周期应该已经结束了。但由于设置了 log_slave_updates,备库会将这个事件写到它自己的二进制日志中。这样第二个备库就可以从第一个备库中,将事件提取到它的中继日志中并执行。
这意味着作为源服务器的主库可以将其数据变化传递给没有与其直接相连的备库上。默认情况下,这个选项是被打开的,这样在连接到备库时就不需要重启服务器。
当第一个备库把自主库获得的事件写入到其它二进制日志中时,这个事件在备库二进制日志中的位置与其主库二进制日志中的位置几乎肯定是不相同的,可能在不同的日志文件或文件内不同的位置。这意味着你不能假定所有拥有同一逻辑复制点的服务器拥有相同的日志坐标。
小结
- 复制功能是 MySQL 高扩展性的基础,常见的读写分离就使用了复制。
- 复制使用了三个线程。master 的日志线程,将事件写入 binlog,slave 的 IO 线程获取 binlog,并将其写入 relaylog,SQL 线程重放 relaylog 日志。
- 复制有基于语句复制和基于行的复制。
MySQL 复制 - 性能与扩展性的基石 1:概述及其原理的更多相关文章
- MySQL 复制 - 性能与扩展性的基石:概述及其原理
原文:MySQL 复制 - 性能与扩展性的基石:概述及其原理 1. 复制概述 MySQL 内置的复制功能是构建基于 MySQL 的大规模.高性能应用的基础,复制解决的基本问题是让一台服务器的数据与其他 ...
- MySQL 复制 - 性能与扩展性的基石 3:常见问题及解决方案
主备复制过程中有很大可能会出现各种问题,接下来我们就讨论一些比较普遍的问题,以及当遇到这些问题时,如何解决或者预防问题发生. 1 数据损坏或丢失 问题描述:服务器崩溃.断电.磁盘损坏.内存或网络错误等 ...
- MySQL 复制 - 性能与扩展性的基石 2:部署及其配置
正所谓理论造航母,现实小帆船.单有理论,不动手实践,学到的知识犹如空中楼阁.接下来,我们一起来看下如何一步步进行 MySQL Replication 的配置. 为 MySQL 服务器配置复制非常简单. ...
- MySQL 复制 - 性能与扩展性的基石 4:主备切换
一旦使用 MySQL 的复制功能,就很大可能会碰到主备切换的情况.也许是为了迭代升级服务器,或者是主库出现问题时,将一台备库转换成主库,或者只是希望重新分配容量.不过出于什么原因,都需要将新主库的信息 ...
- Java并发编程:性能、扩展性和响应
1.介绍 本文讨论的重点在于多线程应用程序的性能问题.我们会先给性能和扩展性下一个定义,然后再仔细学习一下Amdahl法则.下面的内容我们会考察一下如何用不同的技术方法来减少锁竞争,以及如何用代码来实 ...
- Zend server最大化应用程序的性能、扩展性和可用性
如果我有8个小时去砍到一棵树,我会花6个小时磨斧子”——林肯(美国总统) 你可以知道? 世界页面访问量的峰值超过7000万每分钟. CloudFare公司服务器问题,导致785000站点崩溃一小时. ...
- 深入NGINX:我们如何设计它的性能和扩展性
为了更好地理解设计,你需要了解NGINX是如何工作的.NGINX之所以能在性能上如此优越,是由于其背后的设计.许多web服务器和应用服务器使用简单的线程的(threaded).或基于流程的 (proc ...
- idou老师教你学Istio 04:Istio性能及扩展性介绍
Istio的性能问题一直是国内外相关厂商关注的重点,Istio对于数据面应用请求时延的影响更是备受关注,而以现在Istio官方与相关厂商的性能测试结果来看,四位数的qps显然远远不能满足应用于生产的要 ...
- MySQL - 扩展性 1 概述:人多未必力量大
我们应该接触过或者听说过数据库的性能瓶颈问题.对于一个单机应用而言,提升数据库性能的最快路径就是氪金 - 买更高性能的数据库服务器,只要钱到位,性能不是问题. 但是当系统性能增加到一定地步时,你会发现 ...
随机推荐
- Effective Java 第三版——41.使用标记接口定义类型
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Python 基础【二】 下
str()的方法 字符串练习 1.str.capitalize str.capitalize #返回首字母大写,其他字母小写的字符串 >>> a = 'gwdsr' >> ...
- 请求转发(forward)和重定向(redirect)的区别
转发不会改变地址栏,重定向会. 转发是请求一次,重定向请求两次. 转发过程中只有一个request对象产生,重定向是两个. 转发不能转发到站外,重定向可以发送到站外. 重定向的第2个请求的请求方式是什 ...
- git进阶
一.刚提交的代码,发现需要微调一下 刚刚最新提交了一段代码,然后跟前端说,接口好了.过了2分钟,前端跟你说,哎,兄弟,那个金额能不能返回整数,不要小数点. 这个时候一般我们通常会修改一下之后,再提交一 ...
- post 和 get 的区别,直指本质
在我们初入java编程之路的时候,面试往往会有一个面试题:get和post的区别是什么?那么你真的知道他们的区别吗?接下来抽丝剥茧,让我们看看get和post到底什么东西,首先从本质的角度看get和p ...
- Jenkins通过Publish over SSH插件实现远程部署
Jenkins通过Publish over SSH插件实现远程部署 步凑一.配置ssh免秘钥登录 部署详情地址:http://www.cnblogs.com/Dev0ps/p/8259099.html ...
- Spring Boot实战笔记(三)-- Spring常用配置(Bean的初始化和销毁、Profile)
一.Bean的初始化和销毁 在我们的实际开发的时候,经常会遇到Bean在使用之前或之后做些必要的操作,Spring对Bean的生命周期操作提供了支持.在使用Java配置和注解配置下提供如下两种方式: ...
- 【NumberValidators】大陆身份证验证
需要说明的是这里的大陆身份证识别并不是公安局联网的识别,而是按国标GB 11643进行的验证,所以其验证结果只能说符合国标规范,但不能保证该身份证一定真实存在,如果你实际需求是希望身份证一定真实存在, ...
- Zookeeper学习
http://www.cnblogs.com/caosiyang/archive/2012/11/09/2763190.html http://www.cnblogs.com/haippy/tag ...
- SpringMVC中Controller的方法返回值
1. 返回ModelAndView对象 controller方法中定义ModelAndView对象并返回,对象中可添加model数据.指定view. 实例 @RequestMapping(" ...