当然,MySQL的复制有许多方面,但本文主要讲述其逻辑——复制事件怎样写入主机,怎样传送至复制语句以及他们随后怎样应用。注意,本文并不讲述怎样执行复制,而是介绍复制的工作原理。
复制事件
我在这篇文章中说“复制事件”是因为我不想避免讨论与不同的复制格式有关的东西。 这些都已经非常好地在 in the MySQL manual here谈到了。简单地说,这些事件可以是以下的两种:
基于语句 – 在这种情况下编写查询语句
基于行 – 如果你真要为其归类的话,类似于行变化的差异信息
除些之外,我不会回顾用不同的复制格式来复制, 主要是因为它们在传输数据时差异性很小。
关于master
让我们先来看看master是如何工作的. 对于复制的工作, 首先所有的master需要向一个特别的称之为二进制日志的文件中写入复制事件. 这是个非常轻量的动作(假设事件不会同步到磁盘), 因为写操作是顺序的并且是缓冲的形式. 二进制日志文件存储了之后slave将要读取的数据信息.(master/slave个人觉得还是英文更能体现其深刻意义,故未翻译,译者注)
当slave请求连接到一个master的时候, master会创建一个新的线程 (这个过程和其他的服务器客户端的方式基本一样) 来处理客户端 – slave 的请求. 大部分的操作给slave提供二进制日志中的事件并且通知slave有新的写入事件到二进制日志中.
Slaves最开始的时候很可能会去读取仍存储在master操作系统缓存中的事件, 因此这时在master上还没有任何物理磁盘的读操作. 但是, 当你几小时后甚至几天后连接到一台slave机器上, slave会首先开始读取几小时或几天之前写入的二进制日志 – 此时master很可能不会再有这些数据的缓存, 那么读磁盘操作就不可避免的发生了. 如果master没有任何的空闲的IO资源, 这时你可能会感受到服务震荡.
关于复制
让我们看看slave都干了些什么东东. 当你启动应用的时候, slave会开启二个线程:
1. IO 线程
这个过程会调用IO 线程连接到一台master上, 读取master到来的二进制日志事件然后仅仅是将它们复制到本地的一个叫 中继日志的文件中. 仅仅是这些.
尽管只有一个线程从master上读binlog,同时只有一个线程在slave上去写relay log,但是这种 replication event 被复制的方式,几乎不会被当做导致 replication变得更慢的因素
如果你想了解当前IO线程所处何处, 使用“show slave status\G”来查看具体信息:
Master_Log_File – 从master上复制过来的最近的文件 (多数情况下它和master最近写入的二进制日志文件一样)
Read_Master_Log_Pos – master上二进制日志复制到slave上中继日志的位置.
2. SQL 线程
第二个过程 – SQL 线程 – 从slave本地的中继日志中读取事件 (就是被IO线程写入的文件) 并且尽快的使用它们.
这个线程由于是单线程化的所以饱受人们的批判. 回到 “show slave status\G”, 你可以从下面的变量中获取当前SQL线程的状态信息:
Relay_Master_Log_File – 来自master的二进制日志, 供SQL线程处理 (实际上SQL线程是工作在中继日志上的, 这仅仅是为了展示信息的方便性)
Exec_Master_Log_Pos – SQL线程执行的二进制日志的位置.
复制延迟
在这里,现在我大体上介绍一下复制延迟这个问题。当你遇到复制延迟时,首先你要知道两个复制线程中,是哪一个出问题。大多数情况下是由于SQL线程出现了问题,不过你仍然需要二次检查一下。你可以使用上面提到的(本机)复制状态(show slave status\G)和主机二进制日志状态(使用show master status\G获得)进行比较。
我上面已经提过很多次了,由于IO线程引起的复制延迟是很少见的,如果是IO线程引起的,有一个你可以尝试解决的方法是,使用enabling slave compressed protocol(备机数据压缩协议)。
另外,如果你确认是SQL线程的问题,想搞明白问题的原因,你可以使用vmstat命令了解具体原因。使用这个命令对服务器状态监控一段时间后,观察输出列表中是“r”列还是“b”列占用了大部分时间。如果是“r”列数值较高,那么复制过程主要是CPU密集型操作,否则是IO密集型操作。如果还不是非常确定,可以使用CPU监控命令mpstat,得到更直观的了解。
注意,上面监控的结果是假设你没有其他程序运行在服务器上。如果有一些其他的程序运行在服务器上,你可以了解一下diskstats,使用这个工具查询SQL线程可以生成一个更好的监控图。
如果你确定复制是CPU密集型操作, 这个可能也会对你有用。
如果是IO密集型操作,解决这个问题可能并不容易(也许可能很简单)。让我解释一下吧。如果是IO密集型,这意味着大多数时间,因为读操作是单线程进行的,所以SQL线程不能够快速读到数据。是的,这就是问题所在,读操作限制了复制的性能,而不是写操作。让我更详细地解释一下。
假设你有一个RAID10,带写缓存的硬盘。现在开始写操作,即使写操作是串行操作,因为写数据可以缓冲在缓存控制器,并且RAID卡内部可以并行写数据到多个硬盘。因此具备相似硬件的备机,写速度几乎可以和主机同步。
然后现在开始 读操作。当你的任务集合(workset)不适合在内存中时,已经变化的数据将必须首先从硬盘读出,这时候单线程读操作限制了复制的速度,因为单线程读操作时,某一时刻一个线程仅仅只能从一个硬盘读取数据。
正如刚才所说的,解决IO密集型复制操作性能的问题,可以增加内存容量,使更多的任务集合(workset)可以适合在内存中。另一种方法是更换IO设备,以使单线程每秒钟可以读取更多的数据 - 现在传统最快的硬盘可以达到250个IO操作/每秒,SSDs(固态硬盘)可以达到1000个IO操作/每秒。
以上就是精品为大家整理的MySQL 的复制的工作原理,希望对大家有所帮助。