首页 > 代码库 > MySQL主从复制 - 基于二进制日志(理论篇)

MySQL主从复制 - 基于二进制日志(理论篇)

mysql日志类型

1    二进制日志 

2    事务日志

3    一般查询日志

4    中继日志

5    慢查询日志


二进制日志

二进制日志通常记录的是可能潜在引起数据库发生改变的操作,每一个操作我们称为一个event。

二进制日志记录一个event的时候,通常还会记录timestamp,position(偏移量offset),server-id,event本身。

二进制日志的数据存储形式,形如mysql-bin.xxxxxx这种,二进制日志除了mysql-bin.xxxxxx之外,还有mysql-bin.index(二进制日志索引文件)

二进制日志滚动条件:容量达到定义的最大上限,flush logs ,服务器重启

二进制日志删除:一般不建议用rm直接删除,建议用mysql的PURGE命令清除

                 语法:PURGE {MASTER | BINARY} LOGS TO ‘log_name‘    # 删除指定的日志
                           PURGE {MASTER | BINARY} LOGS BEFORE ‘date‘  # 删除日期之前的日志,BEFORE变量的date自变量可以为‘YYYY-MM-DD hh:mm:ss‘格式
                     如:(MASTER 和BINARY 在这里都是等效的)
                           PURGE MASTER LOGS TO ‘test-bin.000001‘;   
                           PURGE MASTER LOGS BEFORE ‘2011-01-0100:00:00‘;

二进制日志格式:statement(mysql官方不推荐)

                           row(mysql 5.6以后推荐)

                           mixed

二进制日志查看:     

                查看当前mysql使用的二进制文件及处在哪个position上:SHOW MASTER STATUS;

                查看当前mysql上使用的二进制文件列表:SHOW BINARY LOGS;

                查看某个二进制日志文件的具体内容:SHOW BINARY EVENTS IN ‘mysql-bin.1234567‘;

二进制日志用途:

               二进制日志可以即时点还原,因为二进制日志中记录的是潜在引起数据库发生改变的操作。要注意的是,通过二进制日志恢复的数据可能跟原始数据不一样,在多颗cpu并行工作的情况下,会同时执行多个事务,如果mysql的隔离级别较低,事务之间可能交叉执行(互相影响),当前能够被使用的二进制日志只有一个,写入二进制日志的方式是串行写入,而事务是并行执行的,事务执行的次序和记录在二进制日志中的次序可能不一致。


mysql隔离级别:(由低到高)

READ-UNCOMMITTED

READ-COMMITTED

REPEATABLE-READ(缺省隔离级别)

SERIALIZABLE

如果你的mysql隔离级别是REPEATABLE-READ,二进制日志格式是statement,在某些场景下绝对会出现通过二进制日志恢复的数据和原始数据不一致的情况。

如果你的mysql隔离级别是READ-COMMITED,二进制日志格式推荐row。


主从复制原理

 wKiom1RW29TD3qFuAAHbdj0sjjU883.jpg

      

主从复制模式

mysql支持一主多从

同步: 确保event发送到所有的slave

半同步:  只要本地event写入本地的二进制日志文件中即可,但是不确保event一定发送到slave,它是不管的

异步: 确保event发送到其中一个slave

注:mysql 5.5 之前是不支持半同步的(google贡献的mysql半同步补丁)

 

多级复制

一个从可以是某个主的从,也可以是某个从的从。

wKiom1RVoQqjs1JrAACqJyDPcY8372.jpg

中继日志(relay log)不能发送给其它节点


复制的作用:

    实现备份

    高可用

    异地容灾

    分摊负载(scale out)


Mysql一主多从、读写分离架构

wKiom1RV5dSDkEAkAALXMT6hq50726.jpg

分析:这种架构随着mysql从服务器的增加会消耗mysql主服务器的性能(cpu、IO、内存),因为从服务器直接接受二进制日志中的event。有几个从服务器接受主服务器发送的event,相应地mysql主服务器就要启几个线程,这些mysql线程各自独立地从二进制日志中读取数据,读完后发送给对应的mysql从服务器,所以下面引入新架构。


Mysql一主多从、读写分离、多级复制架构

wKiom1RV7ULTswXpAAMkXVG_j6I684.jpg

分析:"主的从,从的主" mysql server实际上它只是起把二进制日志的event从主服务器发送到从服务器的中间件而已,实在没有必要把数据持久化存储下来,浪费IO。但是从中继日志中读取的event不在本地执行写入数据文件是不会记录到二进制日志文件中的,没有二进制日志就不能发送event给从服务器了。


解决思路:

mysql有种存储引擎叫black hole,功能类似于linux的/dev/null,"主的从,从的主" mysql 数据库使用black hole存储引擎,这样从中继日志中读取的event在本地执行完后,数据并没有保存下来。


主从架构中,如果不使用mysql-proxy,如何到主服务器写,到从服务器读?

就lamp架构来说,可以在前端程序中指定到哪个主服务器写,到哪个从服务器读;如果有多个从服务器,还可以在程序中使用rr轮询调度访问,增加了前端程序的复杂度。


mysql实际上是支持双主模型的,

双主模型可以减轻读操作,但是无法减轻写操作,所有在第一个节点的写操作,第二个节点也同样要执行一遍,不然就出现数据不一致了。

一般来说,在生产环境中绝对不建议使用双主模型


双主模型原理实现预测

wKioL1RWJ_Sx5c39AALFNYgOdAU446.jpg



双主模型很容易出问题,举个例子:

keystone数据库的user表:

字段: id  name  default_project_id

id  name default_project_id

1     user1     111

2     user2     222

server1: update user set name=‘yao‘ where default_project_id=‘111‘;

server2: update user set default_project_id=‘123‘ where name=‘user1‘

最后怎么合并呢,就会出现数据不一致了,双主模型存在这种 mysql逻辑问题


Mysql集群规模扩大

当一个服务器承受的压力过大的时候,两种方式提升它的性能:

scale on:纵向扩展,增加单台服务器的性能

scale out: 横向扩展,增加服务器分摊负载


当规模越来越大的时候,我们的主服务器怎么都无法承担写操作的时候,怎么办?

数据库服务器之所以压力大,那是因为库里面有很多张表,每个表可能都需要读写操作;双主也无法减轻写操作,需要垂直拆分(分库),就是将一个大的数据库拆分成n个小的数据库,把那些查询(联合查询)或操作的时候相关联的表放在一起,每一个小的数据库放在一个物理服务器上;

当需要对某张表操作的时候,我们只需要联系这张表所在的数据库,但是垂直拆分治标不治本,数据库的数据也是有热区的,比如说我们有50G的数据,其中有2G的数据最繁忙,而这2G的数据都在同一张表上,这时候就需要水平拆分(分表)了,分表的目的就是把热区数据分开。

wKiom1RY21GQjTXeAAGV8-oWnqk774.jpg

注:拆分是根据业务来拆的,不了解业务是不行的。

一般来说,能不拆尽量不拆,一旦出现问题,trouble shooting起来将变得很困难。


实现读写分离的开源软件

mysql-proxy(mysql官方)

amoeba(阿里巴巴贡献,java编写)

cobar(在amoeba基础上开发,java编写,这实际上是一个数据拆分后实现路由的软件)




本文出自 “the-way-to-cloud” 博客,请务必保留此出处http://iceyao.blog.51cto.com/9426658/1571865

MySQL主从复制 - 基于二进制日志(理论篇)