MySQL复制

 

As we know,当今社会,信息化发展十分迅猛,信息对于每个人来说都是至关重要的,那么对于一个对数据十分敏感的IT人来说,数据的安全性是至关重要的,今天我们就从数据的复制来浅谈怎样保证数据的安全性。

目前,对于任何的行业,信息量都十分大,那么我们的服务器硬件设备可能就会满足不了当前的发展,这就成为了制约系统性能的一个瓶颈,因此如果要扩展系统性能两种方式:向上扩展(scale up)和向外扩展(scale out)

一般来说,向上扩展就是扩展硬件(比如增加大型机等),这种方式有一个最大的缺陷就是计算能力的增加跟经济消耗是不成正比的,换句话说,系统性能增加的程度远远低于经济消耗水平。因此目前很多公司都比较倾向于购买商业硬件来替代这些产品

对于数据库服务器来讲,在有限的条件下,既想让我们的服务器性能很好,又不想在资金方面投入太多的话,这就是复制出现的原因,

MySQL的复制架构:

就是对于任何影响数据的请求都记录到本地的二进制日志文件中,从服务器中的I/O thread可以不停的向主服务器发送请求监控二进制日志文件中产生的每个二进制事件,一旦有事务产生,向主服务器发起复制请求,一旦发现主服务器上的事件与从服务器上的不一致,那么主服务器就会启动dump thread 将新的事件读取出来并发送给I/O threadI/O thread 再将二进制日志文件存放到中继日志中。而后在从服务器中再启动一个线程,即sql thread,把中继日志中的二进制日志文件产生的事件读取过来,在本地服务器上执行一遍,因此每当主服务器上产生一个新的数据时,从服务器上面就会更新,并且拿来应用,这就是所谓的复制。

//dump thread:位于主服务器上的线程,用于专门接收来自从服务器I/O线程发送的请求

//I/O thread:位于从服务器,主要功能:向主服务器发起复制请求,一旦发现主服务器上的事件与从服务器上的不一致,那么主服务器就会启动dump thread 将新的事件读取出来并发送给I/O threadI/O thread 再将二进制日志文件存放到中继日志中。

//sql thread:负责从中继日志中依次把事件读取过来,并在本地数据库上执行一次。(众所周知,二进制日志中的事件其实就是sql语句,因此在从服务器上执行一次,等于在本地生成一个和主服务器同样的结果)

但在这种复制并不是单纯的简单的把主服务器上的数据文件复制,而是将主服务器上任何可以改变数据变化的语句复制到中继日志文件中,而复制的方式是通过二进制日志文件中的事件来完成的,而后由一个独立的线程将其读取过来,在本地服务器上再应用一次,这就是MySQLReplication。这样就保证了主服务器和从服务器的数据一致性。

那么这样的复制过程又简单的分为几种情况:

异步复制:一旦事务产生,那么就会记录在主服务器的二进制日志文件中,他就会立即向客户端返回响应结果,主服务器是不关心从服务器是否已经把数据复制过去了,而是要靠从服务器本身通过各种机制把数据同步过去;这样虽然速度提升上去了,但是也会产生一些问题,比如说,当主从服务器都运行很长时间后,可能会发现主从服务器之间的数据可能会不一致,那是因为主服务器从来不等待从服务器,或许因为网络延迟等各种原因,时间久了后,从服务器可能就从主服务器上找不到一些事件,就会产生主从服务器之间数据不一致的情况。这就是从服务器的滞后性。

产生这种滞后性的重要原因主要是:在主服务器上,众所周知,同一时刻可能会运行多个事务,在主服务器上可以并行,然后在从服务器上只能运行一个进程来依次获取主服务器上的二进制日志文件,因此对于繁忙的主服务器来说,产生滞后性的可能性是非常大的。

同步复制:客户端提交事务,首先在本地数据区域中存储下来,而后事件写入二进制日志文件中,同时二进制日志文件要写入到从服务器的中继日志文件中去,且有从服务器的某一线程在本地服务器上应用一次,然后告诉主服务器同步完成,再响应给客户端。基于同步复制是非常漫长的,因此这种方法是不可用的,所以大部分都是异步的

我们在做主从架构的时候需要注意几点,如果主服务器和从服务器都是新的,数据都是从零开始这个不需要太多的考虑;如果主服务器已经运行很久,从服务器是新添加上去的,那么就需要取得主服务器上的一个完全备份在从服务器上恢复,再告诉怎么去主服务器上覆制。

关于数据安全:

前面我们知道,在主服务器上,一个事务被提交了以后,为了保证这个事务以后能够用二进制恢复回来,我们一般将这个事件写入到二进制日志中去,但是我们易知二进制日志文件其实就是磁盘上的物理文件,那么如果直接的把事件写入到二进制日志中的话,对于一台繁忙的服务器来说,就会额外的增加了许多I/O操作,而且速度还很慢,所以为了加速这样的操作,我们运用了buffer(缓冲,即内核维护的一段内存空间),任何写入操作都在buffer中完成,这样就大大加快了速度,会在很短的时间内响应给客户端写入成功,只不过会在稍后才把数据同步到事务日志或二进制日志文件(如果事务涉及到了写语句)中去,通过刷写的频率,一旦事务被提交,我们就根据刷写频率把事务提交到事务日志中去, 同时根据刷写的规则,可以立即刷写到磁盘上,这就保证了事务的安全可靠性,即使发生意外,这也可以保证我们事务的完整性;如果一个事务提交以后,此事务的相关语句要被提交到二进制文件中去,为了加速二进制的操作,我们都是在内核的缓冲去中进行的,那么如果系统断电或发生别的意外情况,我们的二进制日志文件就会丢失,等再次开机后就会造成事务的不完整性,这样就导致了主服务器和从不服务的数据不一致性。

为了保证事务不会在二进制文件中丢失,那么只要事务commit,就通过刷写操作,把buffer中的二进制数据文件立即同步到磁盘中去。这个参数叫做sync_binlog,通过设置此参数来判定当事务commitbuffer当中后,是否立即同步到磁盘中去

这就是所谓的数据安全。为了尽可能降低数据丢失的可能性,生成环境中,我们一般都要启用这项,当然他也会产生大量的磁盘I/O,加大系统资源开销,损失一部分性能。

说明:

//刷写二进制事务的参数:sync_binlog,此参数相当重要

//刷写事务的参数,对于Innodb引擎来说,此参数相当重要

innodb_flush_log_at_trx_commit={0|1|2}

设定InnoDB同步日志缓冲区(log buffer)数据至日志文件中的方式,以及刷写日志文件至磁盘的方式。其可接受的值中,“0”表示将日志缓冲区每秒一次地写入日志文件,并同时将日志文件刷写至磁盘中,但事务提交时不会采取任何动作;“1”是默认值,表示在有事务提交时将日志缓冲区写入日志文件,并同时将日志文件刷写至磁盘;“2”表示每事务提交或每秒一次将日志缓冲区写入日志文件,但不会同时执行日志文件的刷写操作。当然,由于操作系统进程调度的原因,每秒一次的日志写入或刷写操作并不能得到100%的保证。

完全兼容ACID的场景需要将此变量值设置为1,由于要执行每事务的日志刷写操作,其会阻止I/O调用,直到写操作完成,故其会显著降低InnoDB每秒钟可以提交的事务数。设置为“2”可获得比“1”更好的性能,而且仅在操作系统崩溃时才会丢失最后一秒钟的数据,因此数据安全性也有着不错的表现。设置为“0”则有可能会导致事务最后一秒钟的数据丢失,于是整个事务的数据安全性将无法保证,但其通常有着最好的性能。为了在最大程序上保证复制的InnoDB事务持久性和一致性,应该设置变量innodb_flush_log_at_trx_commit=1以及设置变量sync_binlog=1。

然而需要注意的是,有些磁盘自身也有缓存,这可能会给事务操作带来额外的潜在风险。可以使用hdparm工具或供应商的自有工具等禁用磁盘自身的缓存。当然,高性能事务的最佳配置是把此变量的值设置为1,并且将日志文件放在有备用电池的写入缓存的RAID上。作用范围为全局,可用于选项文件,属动态变量。

对于从服务器来说,I/O thread 从dump thread获得事件后,I/O thread 要把事件写入到中继日志中去的,要知道此操作也属于磁盘的I/O操作,因为为了加速这个过程,在从服务器中也引入了buffer,这种机制带来的直接后果就是从服务器要落后于主服务器,这样也就存在了从服务器数据丢失的可能性。但是只要我们的主服务器中存在数据,从服务器就可以从主服务器上进行恢复。

半同步复制概念的引入:

对于主从数据库服务器而言,从服务器都有可能存在数据的延后性,为了解决这种情况,我们这里引入了半同步复制的概念:当客户端提交事务后,服务器端先将事务写到二进制日志文件中,并通知从服务器端,把二进制文件保存到中继日志中,从服务器解析后,把结果反馈给主服务器,只等待众多从服务器中某一台响应即可,如果没有响应的话,主服务器根据响应时间,放弃半同步模式,进入异步模式,直接响应客户端。因此,如果我们要配置半同步的话最好在同一个机房内,带宽足够大,默认半同步等待时间为:10s,且从服务器是不允许写的。

数据库读写分离概念的引入:

  通过前面我们知道,从服务器是只能读不能写的,而主服务器是具有读写功能的,如果我们的系统是一个具有一定规模的web系统的话,当客户端请求对数据库进行读写操作时,我们的主数据库服务器可以兼具对请求进行相应,这可能就会是主服务器很繁忙,而从服务器比较空闲,为了解决这样的问题,那么我们可以这样设计,即当客户端有读操作时,从服务器直接来响应,当客户端有写操作时,主服务器直接来响应。这样就能平衡资源的利用,缓解主服务器的压力。

然而,当客户端发来请求时,我们的数据库服务器端是无法对读写进行分配过滤的,他还是只能把所有的请求都分配都同一台主机上,为了解决这个问题,我们引入了数据库代理的概念,数据库代理的主要功能就是实现把客户端的读写请求分开发送给主从服务器。能够提供这种功能的有MySQL Proxy。这只是一种框架,脚本需要自己来写的。

读写分离的框架结构为:

比较有名的几种代理:

MySQL Proxy

提供的功能:连接路由、Query分析、查询过滤和修改、负载均衡、简单HA的功能

Amoeba(Java)也是读写分离器,运行数据库切分,在内部实现数据路由

利用Java虚拟机建立起来的功能,

功能:查询路由、查询分析、查询过滤、读写分离、负载均衡、HA功能

 Cobar(Java)基于Amoeba,淘宝的产品

关于双主模型:

当系统的业务量很大的情况下,客户端对主服务器的写操作的并发量很大,那么主服务器可能就会超负荷工作,这就会大大加大发生宕机的概率,为了减小这种概率,这里采用了双主模型,即Master/Master模型。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章