mysql 5.5中的半同步复制-阿里云开发者社区

开发者社区> 数据库> 正文

mysql 5.5中的半同步复制

简介: <p><span style="font-family:Helvetica,Tahoma,Arial,sans-serif; font-size:14px; line-height:25.1875px">先来看下MYSQL异步复制的概念: </span><br style="font-family:Helvetica,Tahoma,Arial,sans-serif; font-size:1

先来看下MYSQL异步复制的概念: 
  异步复制:MySQL本身支持单向的、异步的复制。异步复制意味着在把数据从一台机器拷贝到另一台机器时有一个延时 – 最重要的是这意味着当应用系统的事务提交已经确认时数据并不能在同一时刻拷贝/应用到从机。通常这个延时是由网络带宽、资源可用性和系统负载决定的。然而,使用正确的组件并且调优,复制能做到接近瞬时完成。 
  
   当主库有更新的时候,主库会把更新操作的SQL写入二进制日志(Bin log),并维护一个二进制日志文件的索引,以便于日志文件轮回(Rotate)。在从库启动异步复制的时候,从库会开启两个I/O线程,其中一个线程连接主库,要求主库把二进制日志的变化部分传给从库,并把传回的日志写入本地磁盘。另一个线程则负责读取本地写入的二进制日志,并在本地执行,以反映出这种变化。较老的版本在复制的时候只启用一个I/O线程,实现这两部分的功能。 

同步复制:同步复制可以定义为数据在同一时刻被提交到一台或多台机器,通常这是通过众所周知的“两阶段提交”做到的。虽然这确实给你在多系统中保持一致性,但也由于增加了额外的消息交换而造成性能下降。 

使用MyISAM或者InnoDB存储引擎的MySQL本身并不支持同步复制,然而有些技术,例如分布式复制块设备(简称DRBD),可以在下层的文件系统提供同步复制,允许第二个MySQL服务器在主服务器丢失的情况下接管(使用第二服务器的复本)。要了解更多信息, 

  MYSQL 5。5开始,支持半自动复制。之前版本的MySQL Replication都是异步(asynchronous)的,主库在执行完一些事务后,是不会管备库的进度的。如果备库不幸落后,而更不幸的是主库此时又出现Crash(例如宕机),这时备库中的数据就是不完整的。简而言之,在主库发生故障的时候,我们无法使用备库来继续提供数据一致的服务了。 

Semisynchronous Replication则一定程度上保证提交的事务已经传给了至少一个备库。 
Semi synchronous中,仅仅保证事务的已经传递到备库上,但是并不确保已经在备库上执行完成了。 

此外,还有一种情况会导致主备数据不一致。在某个session中,主库上提交一个事务后,会等待事务传递给至少一个备库,如果在这个等待过程中主库Crash,那么也可能备库和主库不一致,这是很致命的。(在主库恢复后,可以通过参数Rpl_semi_sync_master_no_tx观察) 

     如果主备网络故障或者备库挂了,主库在事务提交后等待10秒(rpl_semi_sync_master_timeout的默认值)后,就会继续。这时,主库就会变回原来的异步状态。 

    MySQL在加载并开启Semi-sync插件后,每一个事务需等待备库接收日志后才返回给客户端。如果做的是小事务,两台主机的延迟又较小,则Semi-sync可以实现在性能很小损失的情况下的零数据丢失。 

   主机Crash时的处理 

备库Crash时,主库会在某次等待超时后,关闭Semi-sync的特性,降级为普通的异步复制,这种情况比较简单。 

主库Crash后,那么可能存在一些事务已经在主库Commit,但是还没有传给任何备库,我们姑且称这类事务为"墙头事务"。"墙头事务"都是没有返回给客户端的,所以发起事务的客户端并不知道这个事务是否已经完成。 

这时,如果客户端不做切换,只是等Crash的主库恢复后,继续在主库进行操作,客户端会发现前面的"墙头事务"都已经完成,可以继续进行后续的业务处理;另一种情况,如果客户端Failover到备库上,客户端会发现前面的“墙头事务”都没有成功,则需要重新做这些事务,然后继续进行后续的业务处理。 

   可以做多个备库,任何一个备库接收完成日志后,主库就可以返回给客户端了。 

网络传输在并发线程较多时,一次可能传输很多日志,事务的平均延迟会降低。 

"墙头事务"在墙头上的时候,是可以被读取的,但是这些事务在上面Failover的场景下,是被认为没有完成的。 

     默认情况下MySQL的复制是异步的,Master上所有的更新操作写入Binlog之后并不确保所有的更新都被复制到Slave之上。异步操作虽然效率高,但是在Master/Slave出现问题的时候,存在很高数据不同步的风险,甚至可能丢失数据。 
MySQL5.5引入半同步复制功能的目的是为了保证在master出问题的时候,至少有一台Slave的数据是完整的。在超时的情况下也可以临时转入异步复制,保障业务的正常使用,直到一台salve追赶上之后,继续切换到半同步模式。 
Master: 
INSTALL PLUGIN rpl_semi_sync_master SONAME ‘semisync_master.so’; 
SET GLOBAL rpl_semi_sync_master_enabled=1; 
SET GLOBAL rpl_semi_sync_master_timeout=1000; (1s, default 10s) 
Slave: 
INSTALL PLUGIN rpl_semi_sync_slave SONAME ‘semisync_slave.so’; 
SET GLOBAL rpl_semi_sync_slave_enabled=1; 
复制心跳(用户检测复制是否中断) 

MySQL5.5提供的新的配置master_heartbeat_period,能够在复制停止工作和出现网络中断的时候帮助我们迅速发现问题。 

启用方法: 
STOP SLAVE; 
CHANGE MASTER TO master_heartbeat_period= milliseconds; 
START SLAVE; 


Slave自动恢复同步 

在MySQL5.5版本之前,MySQL Slave实例在异常终止服务之后,可能导致复制中断,并且relay binlog可能损坏,在MySQL再次启动之后并不能正常恢复复制。在MySQL5.5中这一问题得到了解决,MySQL可以自行丢弃顺坏的而未处理的数据,重新从master上获取源数据,进而回复复制。 
跳过指定复制事件 

在多Master或环形复制的情况下,处于复制链条中间的服务器异常,可以通过 
CHANGE MASTER TO MASTER_HOST=xxx IGNORE_SERVER_IDS=y 
跳过出问题的MySQL实例。 

自动转换字段类型 
MySQL5.1在基于语句的复制下,支持部分的字段转换,但是行级的会报错。MySQL5.5语句和行级复制都已支持。还可以通过 SLAVE_TYPE_CONVERSIONS 控制转换的方向。 


赠送:


一、MySQL复制概述

   ⑴、MySQL数据的复制的基本介绍

   目前MySQL数据库已经占去数据库市场上很大的份额,其一是由于MySQL数据的开源性和高性能,当然还有重要的一条就是免费~不过不知道还能免费多久,不容乐观的未来,但是我们还是要能熟练掌握MySQL数据的架构和安全备份等功能,毕竟现在它还算是开源界的老大吧!

   MySQL数据库支持同步复制、单向、异步复制,在复制的过程中一个服务器充当主服务,而一个或多个服务器充当从服务器。主服务器将更新写入二进制日志文件,并维护文件的一个索引以跟踪日志循环。这些日志可以记录发送到从服务器的更新。当一个从服务器连接主服务器时,它通知主服务器从服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那时起发生的任何更新,然后封锁并等待主服务器通知新的更新。

请注意当你进行复制时,所有对复制中的表的更新必须在主服务器上进行。否则,你必须要小心,以避免用户对主服务器上的表进行的更新与对从服务器上的表所进行的更新之间的冲突。
   单向复制有利于健壮性、速度和系统管理:

   健壮性:主服务器/从服务器设置增加了健壮性。主服务器出现问题时,你可以切换到从服务器作为备份。

   速度快:通过在主服务器和从服务器之间切分处理客户查询的负荷,可以得到更好的客户响应时间。SELECT查询可以发送到从服务器以降低主服务器的查询处理负荷。但修改数据的语句仍然应发送到主服务器,以便主服务器和从服务器保持同步。如果非更新查询为主,该负载均衡策略很有效,但一般是更新查询。

   系统管理:使用复制的另一个好处是可以使用一个从服务器执行备份,而不会干扰主服务器。在备份过程中主服务器可以继续处理更新。

   ⑵、MySQL数据复制的原理

   MySQL复制基于主服务器在二进制日志中跟踪所有对数据库的更改(更新、删除等等)。因此,要进行复制,必须在主服务器上启用二进制日志。

   每个从服务器从主服务器接收主服务器已经记录到其二进制日志的保存的更新,以便从服务器可以对其数据拷贝执行相同的更新。

   认识到二进制日志只是一个从启用二进制日志的固定时间点开始的记录非常重要。任何设置的从服务器需要主服务器上的在主服务器上启用二进制日志时的数据库拷贝。如果启动从服务器时,其数据库与主服务器上的启动二进制日志时的状态不相同,从服务器很可能失败。

   将主服务器的数据拷贝到从服务器的一个途径是使用LOAD DATA FROM MASTER语句。请注意LOAD DATA FROM MASTER目前只在所有表使用MyISAM存储引擎的主服务器上工作。并且,该语句将获得全局读锁定,因此当表正复制到从服务器上时,不可能在主服务器上进行更新。当我们执行表的无锁热备份时,则不再需要全局读锁定。

   MySQL数据复制的原理图大致如下:

从上图我们可以看出MySQL数据库的复制需要启动三个线程来实现:

   其中1个在主服务器上,另两个在从服务器上。当发出START SLAVE时,从服务器创建一个I/O线程,以连接主服务器并让它发送记录在其二进制日志中的语句。主服务器创建一个线程将二进制日志中的内容发送到从服务器。该线程可以识别为主服务器上SHOW PROCESSLIST的输出中的Binlog Dump线程。从服务器I/O线程读取主服务器Binlog Dump线程发送的内容并将该数据拷贝到从服务器数据目录中的本地文件中,即中继日志。第3个线程是SQL线程,是从服务器创建用于读取中继日志并执行日志中包含的更新。

   在前面的描述中,每个从服务器有3个线程。有多个从服务器的主服务器创建为每个当前连接的从服务器创建一个线程;每个从服务器有自己的I/O和SQL线程。

   这样读取和执行语句被分成两个独立的任务。如果语句执行较慢则语句读取任务没有慢下来。例如,如果从服务器有一段时间没有运行了,当从服务器启动时,其I/O线程可以很快地从主服务器索取所有二进制日志内容,即使SQL线程远远滞后。如果从服务器在SQL线程执行完所有索取的语句前停止,I/O 线程至少已经索取了所有内容,以便语句的安全拷贝保存到本地从服务器的中继日志中,供从服务器下次启动时执行。这样允许清空主服务器上的二进制日志,因为不再需要等候从服务器来索取其内容。

二、实列说明MySQL的主从复制架构和实现详细过程

     主从架构数据库的复制图如下:

其配置详细过程如下:

   1、环境架构:

       RedHat Linux Enterprise 5.8         mysql-5.5.28-linux2.6-i686.tar

       Master:172.16.7.1/16                 Slave:172.16.7.2/16

   2 、安装mysql-5.5.28,需要在主节点和备节点上安装mysql

       Master:

       安装环境准备:

[sql] view plain copy
 print?
  1. 为mysql的安装提供前提环境和初始化安装mysql  
  2. 创建数据库目录  
  3. # mkdir /mydata/data –pv  
  4. 创建mysq用户  
  5. # useradd -r mysql  
  6. 修改权限  
  7. # chown -R mysql.mysql /mydata/data/  
  8. 使用mysql-5.5通用二进制包安装  
  9. 解压mysql软件包  
  10. # tar xf mysql-5.5.28-linux2.6-i686.tar.gz-C /usr/local/  
  11. 创建连接,为了方便查看mysql的版本等信息  
  12. # cd /usr/local/  
  13. #ln –sv mysql-5.5.28-linux2.6-i686.tar.gzmysql  
  14. 修改属主属组  
  15. # cd mysql  
  16. # chown -R root.mysql ./*  
  17. 初始化数据库  
  18. # scripts/mysql_install_db –user=mysql --datadir=/mydata/data/  
  19. 提供配置文件  
  20. # cp support-files/my-large.cnf /etc/my.cnf  
  21. 提供服务脚本  
  22. # cp support-files/mysql.server/etc/rc.d/init.d/mysqld  
  23. 添加至服务列表  
  24. # chkconfig --add mysqld  
  25. # chkconfig --list mysqld  
  26. # chkconfig mysqld on  
  27. 编辑配置文件,提供数据目录  
  28. # vim /etc/my.cnf  
  29. # The MySQL server  修改mysqld服务器端的内容  
  30. log-bin=master-bin 主服务器二进制日志文件前缀名  
  31. log-bin-index=master-bin.index  索引文件  
  32. innodb_file_per_table= 1     开启innodb的一表一个文件的设置  
  33. server-id       = 1          必须是唯一的  
  34. datadir =/mydata/data        数据目录路径  
  35. 启动mysql服务  
  36. # servicemysqld start  
  37. 为了便于下面的测试,设置环境变量  
  38. # vim/etc/profile.d/mysql.sh  
  39. export PATH=$PATH:/usr/local/mysql/bin  
  40. 执行环境变量脚本,使其立即生效  
  41. # . /etc/profile.d/mysql.sh  



 启动服务并进行相关的测试:

 mysql的安装配置完成,下面增加一个用于同步数据的账户并设置相关的权限吧!

[sql] view plain copy
 print?
  1. 建立用户账户  
  2. mysql> grant replication slave on *.* to 'chris'@'172.16.%.%' identified by 'work';  
  3. 刷新数据使其生效  
  4. mysql> flush privileges;  

   至此我们mysql的Master设置完成,下面进行slave端的设置吧!

   Slave:

   安装环境配置:

[sql] view plain copy
 print?
  1. 创建mysql数据库目录  
  2. # mkdir /mydata/data –pv  
  3. 创建mysql用户  
  4. # useradd -r mysql  
  5. 修改数据目录权限  
  6. # chown -R mysql.mysql /mydata/data/  
  7. 使用mysql-5.5通用二进制包安装mysql  
  8. 解压mysql软件包  
  9. # tar xf mysql-5.5.28-linux2.6-i686.tar.gz-C /usr/local/  
  10. 创建连接,便于查看mysql的版本等信息  
  11. # cd /usr/local/  
  12. # ln –sv mysql-5.5.28-linux2.6-i686.tar.gzmysql  
  13. 修改mysql属主属组  
  14. # cd mysql  
  15. # chown -R root.mysql ./*  
  16. 初始化mysql数据库  
  17. # scripts/mysql_install_db –user=mysql--datadir=/mydata/data/  
  18. 提供mysql配置文件  
  19. # cp support-files/my-large.cnf /etc/my.cnf  
  20. 提供服务脚本  
  21. # cp support-files/mysql.server /etc/init.d/mysqld  
  22. 添加至服务列表  
  23. # chkconfig --add mysqld  
  24. 编辑配置文件  
  25. # vim /etc/my.cnf  
  26. # The MySQL server  
  27. #log-bin=mysql-bin      禁用二进制日志,从服务器不需要二进制日志文件  
  28. datadir = /mydata/data  mysql的数据目录  
  29. relay-log = relay-log   设置中继日志  
  30. relay-log-index = relay-log.index  中继日志索引  
  31. innodb_file_per_table = 1  
  32. server-id       = 2    id不要和主服务器的一样  
  33. 设置环境变量  
  34. # vim/etc/profile.d/mysql.sh  
  35. export PATH=$PATH:/usr/local/mysql/bin  
  36. 执行此脚本(导出环境变量)  
  37. # . /etc/profile.d/mysql.sh  
  38. 启动服务  
  39. # service mysqld start  


  到这slave服务的mysql安装和配置完成,下面启动slave复制吧,开启之前先查看下从服务上的二进制文件吧

[sql] view plain copy
 print?
  1. mysql> show master status; #在Master上执行查看二进制文件  
  2. 在从服务器上开启复制功能  
  3. change master to master_host='172.16.7.1',master_user='chris',master_password='work',master_log_file='master-bin.000001',master_log_pos=407;  
  4. 开启复制功能  
  5. mysql>start slave;  

至此我们的mysql服务器的主从复制架构已经基本完成,下面开启服务并测试测试吧~

在从服务器开启复制进程:mysql>start slave;

   至此我们mysql服务器的主从复制架构已经完成,但是我们现在的主从架构并不完善,因为我们的从服务上还可以进行数据库的写入操作,一旦用户把数据写入到从服务器的数据库内,然后从服务器从主服务器上同步数据库的时候,会造成数据的错乱,从而会造成数据的损坏,所以我们需要把从服务器设置成只读~方法如下:

注意:read-only = ON ,这项功能只对非管理员组以为的用户有效!

OK,此致我们的mysql基于主从架构的复制功能已经搭建全部完成~下面介绍下关于mysql数据目录下面各个文件的功能和作用!

   由于二进制文件的缓冲区内,当我们的服务器宕机的时候,缓存区内的数据并没有同步到二进制日志文件内的时候,那就悲剧了,缓冲区内的数据就无法找回了,为了防止这种情况的发送,我们通过设置mysql直接把二进制文件记录到二进制文件而不再缓冲区内停留。

sync-binlog = ON 在主服务器上进行设置,用于事务安全

  从上面我们可以看到从服务器启动的时候其Slave_IO_Running: Yes和Slave_SQL_Running: Yes是自动启动的,但是有时候我们在主服务上进行的误操作等,也会直接同步到从服务器上的,要想恢复那就难了,所以我们需要关闭其自动执行功能,让其能够停止,skip-slave-start = 1 ,让其不开启自动同步,但是遗憾的是mysql5.28上已经没有了,我们可以通过停止相关线程来实现:

mysql>STOP SLAVE 或STOP SLAVE  IO_THREAF或STOP SLAVE SQL_THREAD

注意:从服务器的所有操作日志都会被记录到数据目录下的错误日志中!

三、MySQL的半同步复制

   实现半同步复制的功能很简单,只需在mysql的主服务器和从服务器上安装个google提供的插件即可实现,

   主服务上使用semisync_master.,从服务器上使用sosemisync_slave.so插件即可实现,插件在mysql通用二进制的mysql/lib/plugin目录内。

其配置步骤如下

1、分别在主从节点上安装相关的插件

master:

[sql] view plain copy
 print?
  1. 安装插件:mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';  
  2. 启动模块:mysql> SET GLOBAL rpl_semi_sync_master_enabled = 1;  
  3. 设置超时时间:mysql> SET GLOBAL rpl_semi_sync_master_timeout = 1000;  

1
2
3
4
slave:
安装插件:msyql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
启动模块:mysql> SET GLOBAL rpl_semi_sync_slave_enabled = 1;
重启进程使其模块生效:mysql> STOP SLAVE IO_THREAD; START SLAVE IO_THREAD;


  上面的设置时在mysql进程内动态设定了,会立即生效但是重启服务以后就会失效,为了保证永久有效,需要把相关配置写到主、从服务器的配置文件my.cnf内:

[sql] view plain copy
 print?
  1. 在Master和Slave的my.cnf中编辑:  
  2. On Master  
  3. [mysqld]  
  4. rpl_semi_sync_master_enabled=1  
  5. rpl_semi_sync_master_timeout=1000   #此单位是毫秒  
  6. On Slave  
  7. [mysqld]  
  8. rpl_semi_sync_slave_enabled=1  

  确认半同步功能已经启用,通过下面的操作进行查看

[sql] view plain copy
 print?
  1. master:  
  2. mysql> CREATE DATABASE asyncdb;  
  3. master> SHOW STATUS LIKE 'Rpl_semi_sync_master_yes_tx';  
  4. slave> SHOW DATABASES;  
  5. 其测试过程如下  

然后把从服务器上的复制进程开启,

  我们至此已经实现了mysql数据库复制的半同步方式的架构,并且通过测试查看了复制功能,下面我们进行双主模型架构吧。

四、MySQL设置主-主复制:master<-->slave 
1、在两台服务器上各自建立一个具有复制权限的用户;让两个数据库互为主从的关系

2、修改配置文件:

把上面的连个数据库的配置文件重新配置,其配置如下 

[sql] view plain copy
 print?
  1. # 主服务器上  
  2. [mysqld]  
  3. server-id = 1  
  4. log-bin = mysql-bin  
  5. relay-log = relay-mysql  
  6. relay-log-index = relay-mysql.index  
  7. auto-increment-increment = 2           #每次跳两个数。  
  8. auto-increment-offset = 1              #从1开始。  


[sql] view plain copy
 print?
  1. [mysqld]  
  2. server-id = 2  
  3. log-bin = mysql-bin  
  4. relay-log = relay-mysql  
  5. relay-log-index = relay-mysql.index  
  6. auto-increment-increment = 2  
  7. auto-increment-offset = 2  

  如果此时两台服务器均为新建立,且无其它写入操作,各服务器只需记录当前自己二进制日志文件及事件位置,以之作为另外的服务器复制起始位置即可

[sql] view plain copy
 print?
  1. master:查看日志文件信息  
  2. mysql> show master status;  
  3. +------------------+----------+--------------+------------------+  
  4. | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |  
  5. +------------------+----------+--------------+------------------+  
  6. | mysql-bin.000001 |      107 |              |                  |  
  7. +------------------+----------+--------------+------------------+  
  8. Slave:查看服务器日志文件信息  
  9. mysql> show master status;  
  10. +------------------+----------+--------------+------------------+  
  11. | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |  
  12. +------------------+----------+--------------+------------------+  
  13. | mysql-bin.000001 |      107 |              |                  |  
  14. +------------------+----------+--------------+------------------+  
  15. 1 row in set (0.00 sec)  

 在各个服务器上建立账号和权限,来进行同步设置

1
2
3
master:
mysql> GRANT REPLICATION SLAVE ON *.* TO 'chrislee'@'172.16.%.%' IDENTIFIED BY 'work';
mysql> flush privileges;

[sql] view plain copy
 print?
  1. slave:  
  2. mysql> GRANT REPLICATION SLAVE ON *.* TO 'chrisli'@'172.16.%.%' IDENTIFIED BY 'work';  
  3. mysql> flush privileges  

在各服务器上指定对另一台服务器为自己的主服务器即可:

[sql] view plain copy
 print?
  1. server1  
  2. mysql> CHANGE MASTER TO MASTER_HOST='172.16.7.2',MASTER_USER='chrisli',MASTER_PASSWORD='work',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=344;  

[sql] view plain copy
 print?
  1. server2:  
  2. mysql> CHANGE MASTER TO MASTER_HOST='172.16.7.1',MASTER_USER='chrislee',MASTER_PASSWORD='work',MASTER_LOG_FILE='mysql-bin.000001',MASTER_LOG_POS=345;  

双主架构配置基本完成,下面在各自上面启动复制进程吧~并进行测试:


转载自:http://chrinux.blog.51cto.com/6466723/1204586


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
数据库
使用钉钉扫一扫加入圈子
+ 订阅

分享数据库前沿,解构实战干货,推动数据库技术变革

其他文章