马丁传奇

导航

MySQL 5.5 主从复制

 

MySQL 5.5 主从复制的原理、过程
 
分为同步复制和异步复制,实际复制架构中大部分为异步复制。复制的基本过程如下: 
1)、Slave上面的IO进程连接上Master,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容;  

2)、Master接收到来自Slave的IO进程的请求后,通过负责复制的IO进程根据请求信息读取指定日志指定位置之后的日志信息,返回给Slave的IO进程。返回信息中除了日志所包含的信息之外,还包括本次返回的信息已经到Master端的bin-log文件的名称以及bin-log的pos位置;  

3)、Slave的IO进程接收到信息后,将接收到的日志内容依次添加到Slave端的中继日志(relay-log)文件的最末端,并将读取到的Master端的bin-log的文件名和位置记录到master.info文件中,以便在下一次读取的时候能够清楚的告诉Master“我需要从某个bin-log的哪个pos位置开始往后的日志内容,请发给我”;

4)、Slave的sql进程检测到relay-log中新增加了内容后,会马上解析relay-log的内容成为在Master端真实执行时候的那些可执行的内容,并在自身执行。   

Slave端的双进程复制提升可靠性
Mysql为了解决这个风险并提高复制的性能,将Slave端的复制改为两个进程来完成。提出这个改进方案的人是Yahoo!的一位工程师“Jeremy Zawodny”。这样既解决了性能问题,又缩短了异步的延时时间,同时也减少了可能存在的数据丢失量。当然,即使是换成了现在这样两个线程处理以后,同样也还是存在Slave数据延时以及数据丢失的可能性的,毕竟这个复制是异步的。只要数据的更改不是在一个事物中,这些问题都是会存在的。如果要完全避免这些问题,就只能用mysql的cluster来解决了。不过mysql的cluster是内存数据库的解决方案,需要将所有数据都load到内存中,这样就对内存的要求就非常大了,对于一般的应用来说可实施性不是太大。

常用主从复制架构 
Mysql复制环境90%以上都是一个Master带一个或者多个Slave的架构模式,主要用于读压力比较大的应用的数据库端廉价扩展解决方案。因为只要master和slave的压力不是太大(尤其是slave端压力)的话,异步复制的延时一般都很少很少。尤其是自slave端的复制方式改成两个进程处理之后,更是减小了slave端的延时。而带来的效益是,对于数据实时性要求不是特别的敏感度的应用,只需要通过廉价的pc server来扩展slave的数量,将读压力分散到多台slave的机器上面,即可解决数据库端的读压力瓶颈。这在很大程度上解决了目前很多中小型网站的数据库压力瓶颈问题,甚至有些大型网站也在使用类似方案解决数据库瓶颈。


一、准备实验环境:
    主(Master)机IP: 192.168.137.26
    从(Slave) 机IP: 192.168.137.27
    两MySQL服务器均是源码包编译安装

二、向主(Master)机添加远程登录的授权用户
    1.向主(Master)服务器添加用户:
      @ 用户名: slave4
      @ 密  码: 789
      @ 允许自: 192.168.137.27 机器登录

      授权方式1: 此种授权是可远程登录Master,仅用于主从复制没有其它任何select insert update等权限【推荐】
      mysql> grant replication slave on *.* to 'slave4'@'192.168.137.27' identified by '789';

      授权方式2: 此种授权是对用户不但可远程登录Master,还可拥有对Master包括主从复制的其它所有select insert update等权限
      mysql> grant all on *.* to 'slave6'@'192.168.137.28' identified by '789';

    2.刷新授权表:
      mysql> flush privileges;

    3.查看授权结果:
      mysql> show grants for 'slave4'@'192.168.137.27';

    4.测试从Slave端登录远程主(Master)机:
      # /usr/local/mysql/bin/mysql -uslave4 -p789 -h192.168.137.26

    5.从主(Master)机查看所有连接登录本机的客户端情况:
      mysql> show processlist \G


三、主(Master)机配置
    vi编辑打开mysql配置文件
    # vi /usr/local/mysql/etc/my.cnf

    找到从约第56行开始确认以下三项:
    [mysqld]
    log-bin=mysql-bin    # 确认开启binlog日志
    binlog_format=mixed  # 确认binlog日志格式为mixd混合类型
    server-id = 1        # 在整个主从架构内指定一个唯一的server-id,范围:1^32


四、从(Slave)机配置-【基本】
    vi编辑打开mysql配置文件
    # vi /usr/local/mysql/etc/my.cnf

    找到从约第56行开始确认以下三项: 
    [mysqld]
    log-bin=mysql-bin    # 确认也开启binlog日志
    binlog_format=mixed  # 确认binlog日志格式为mixd混合类型
    server-id = 2        # 在整个主从架构内指定一个唯一的server-id,范围:1^32 ◆


    从(Slave)机配置-【可选】
    下面是生产阶段可能要用的功能,这些功能只能在从机的配置文件的[mysqld]区块里手工配置,无法通过 change master to ...命令实现。
    1.白名单 - 只想复制某(些)个库:
      replicate_do_db=zyyshop                 # 追加复制zyyshop库
      replicate_do_db=test                    # 追加只复制test库
      总结: 相当于只复制 zyyshop、test 两个库
            如果采用完全在配置文件里配置主(Master)机信息的方法,此项须添加,否则可能导致mysqld启动不了 

    2.白名单 - 只想复制某(些)个库(的所有表)
      replicate_wild_do_table=zyyshop.%       # 追加复制zyyshop库的所有表
      replicate_wild_do_table=test.%          # 追加复制test库的所有表
      总结:也是相当于只复制 zyyshop、test 两个库。

    3.白名单 - 只想复制某(些)个库(的部分表)
      replicate_wild_do_table=zyyshop.stu     # 追加zyyshop.stu表
      replicate_wild_do_table=test.project    # 追加test.project表
      总结:相当于只复制zyyshop.stu、test.project两个表。

    4.黑名单 - 想忽略对mysql和test数据库的复制
      replicate_ignore_db=mysql               # 追加mysql库为忽略
      replicate_ignore_db=test                # 追加test库为忽略
      总结:相当于将mysql和test两数据库追加到忽略列表,将不会被复制。
    
    5.黑名单 - 想忽略对某些库的某些表的复制
      replicate_wild_ignore_table=mysql.users # 追加mysql.users表为忽略
      总结:本步骤是相当于追加了mysql.users具体的表被忽略,其它表照常会被复制。
      
    6.如果想实现“主-->从-->从”的链式架构,因为在默认情况下,from主(Master)机copy过来的数据不会写入从(Slave)机的binlog日志里,
      而是写入中继日志(localhost-relay-bin.00000x)里,所以本机如果还需要充当其它机器的主机,就将从主机复制来的数据写入从库时同
      时也显式地写入本地binlog日志,添加如下配置:
      log-slave-updates =1

五、在主(Master)机端操作:执行命令刷新主机binlog日志记录,查看主机的最后日志文件及最后pos起始点
    mysql> flush logs;
    mysql> show master status;
    +------------------+----------+--------------+------------------+
    | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
    +------------------+----------+--------------+------------------+
    | mysql-bin.000009 |      107 |              |                  |
    +------------------+----------+--------------+------------------+

六、在从(Slave)机启动slave服务
    1.使用root用户登录到从(Slave)机
      # /usr/local/mysql/bin/mysql -uroot -p123456

    2.在从(Slave)上执行命令,动态改变连接到主(Master)机的配置,生成或更新master.info文件:
      注: 在生产环境中,如果心跳感应到主机意外宕机,应用程序应该按预案选定出一台新主机,而其它的从机都需要执行一次下面
          的 change master to ...语句,切换自己从属到新主机,这样比较灵活,操作的实质是更新master.info文件,查看此文件也
          能发现MySQL其实是只能支持“一主多从”架构,而不能像Redis那样还可以支持多主一从架构。

      mysql> change master to master_host='192.168.137.26', master_user='slave4', master_password='789', MASTER_LOG_FILE='mysql-bin.000009', MASTER_LOG_POS=107;

      善于使用?查看详细选项
      mysql> ? change master to

      常用选项:
       master_host='192.168.137.26' 远程主(Master)机IP      
       master_user='slave4',        登录远程主(Master)机 用户名
       master_password='789',       登录远程主(Master)机 密码

      不常用选项:      
       MASTER_LOG_FILE='mysql-bin.000009' 指定从哪个binlog文件复制(如果不加此参数默认是最早的binlog日志)
       MASTER_LOG_POS=107                 指定从哪个binlog文件的哪个pos点开始复制(如果不加此参数默认是最早的pos点)
       MASTER_PORT=3306,                  远程主(Master)机端口
       MASTER_HEARTBEAT_PERIOD=60         多长时间探测一次主服务器是否在线 单位:秒
       MASTER_CONNECT_RETRY=10;           无法连接主服务器的时候重试连接的间隔时间 单位:秒


    3.启动IO线程和SQL线程,生成master.info文件,查看从(Slave)机状态:
      mysql> start slave;
      mysql> show slave status \G;

      如果看到如下状态说明同步成功:             
           Slave_IO_Running: Yes
          Slave_SQL_Running: Yes
      Seconds_Behind_Master: 0


    4.报错处理!如果“Slave_SQL_Running: No”,程序可能在slave上进行了写操作,也可能是slave机器重起后,事务回滚造成的。
      解决方法一: 
      mysql> stop slave;
      mysql> set GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
      mysql> start slave;
      mysql> show slave status \G;

      解决方法二:
      主(Master)上:
      mysql> show master status;  //主机上查看最新的binlog日志名及pos点

      从(Slave)机上:
      mysql> stop slave;          //从机停掉slave服务
      mysql> change master to master_host='192.168.137.26', master_user='slave4', master_password='789', MASTER_LOG_FILE='主机最新binlog日志名', MASTER_LOG_POS=最新pos点;
      mysql> start slave;
      mysql> show slave status \G;
      


七、【实验】如果开始的环境不是主从架构,跑了一段时间主(Master)机已经有了数据,且主机的binlog日志已经不完整了,可由两种方案:

    方案一(推荐):对主(Master)机做一次完整的mysqldump备份,拷贝到从(Slave)机执行从机恢复,然后从机再开启slave服务

      A.【主机操作】备份主机数据(比如:test和zyyshop是需要以后同步的库)
         # /usr/local/mysql/bin/mysqldump -uroot -p123456 -lF --log-error=/root/myDump.err -B test zyyshop > /root/test_zyyshop.sql

      B.【主机操作】立即查看一下主机的最新的binlog日志,并记录binlog日志名和pos点,从机就从这儿开始同步即可:
         # /usr/local/mysql/bin/mysql -uroot -p123456
         mysql> show master status;
         +------------------+----------+--------------+------------------+
         | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
         +------------------+----------+--------------+------------------+
         | mysql-bin.000012 |      107 |              |                  |
         +------------------+----------+--------------+------------------+

      C.【主机操作】将备份的文件直接恢复到远程的从(Slave)机数据库上:     
         方法1:先将 test_zyyshop.sql 备份文件 SCP 拷贝到远程从(Slave)机,再登录到远程从机恢复:
                A.拷贝备份数据到从机:
                  # scp /root/test_zyyshop.sql root@192.168.137.27:/root/masterdb.sql
                  需要两台机器都安装scp才可,scp属于openssh-clients这个包,安装方法:# yum install -y openssh-clients

                B.[从机操作]将从机的备份数据恢复:
                  # /usr/local/mysql/bin/mysql -uroot -p123456 -v < /root/masterdb.sql

         方法2:直接恢复到远程从(Slave)机上:
                # /usr/local/mysql/bin/mysql -uroot -p123456 -h192.168.137.27 -v < /root/test_zyyshop.sql

         至此从机已将主机的备份文件恢复到从机,接下来只要不断向主机同步binlog日志就OK了。

      D.[从机操作] 在从(Slave)上执行命令,动态改变连接到主(Master)机的配置,生成或更新master.info文件:
        # /usr/local/mysql/bin/mysql -uroot -p123456        

        mysql> change master to master_host='192.168.137.26', master_user='slave4', master_password='789', MASTER_LOG_FILE='mysql-bin.000012', MASTER_LOG_POS=107;  

        mysql> start slave;
        mysql> show slave status \G;

        *************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.137.26
                  Master_User: slave4
                  Master_Port: 3306
                Connect_Retry: 10
              Master_Log_File: mysql-bin.000012
          Read_Master_Log_Pos: 107
               Relay_Log_File: zzx-relay-bin.000002
                Relay_Log_Pos: 253
        Relay_Master_Log_File: mysql-bin.000012
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes

        ................

    小结:如果slave启动一切正常,就成功了!



    方案二:打包主机的数据目录拷贝到从(Slave)机进行从机恢复,然后从机再开启slave服务
            ★ 注: 此法适用于MyISAM引擎表,不适用于Innodb引擎表。

      # /usr/local/mysql/bin/mysql -uroot -p123456

      A.【主机操作】对主(Master)机所有表进行“读锁”:     
         mysql> flush tables with read lock;

         查看一下主机的最新的binlog日志,并记录binlog日志名和pos点,从机就从这儿开始同步即可:
         mysql> show master status;
         +------------------+----------+--------------+------------------+
         | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
         +------------------+----------+--------------+------------------+
         | mysql-bin.000012 |      107 |              |                  |
         +------------------+----------+--------------+------------------+

      B.【主机操作】进入数据目录,打包需要的数据库包
        # cd /usr/local/mysql/data/
        # tar -zcvf  test.tar.gz test
        # tar -zcvf zyyshop.tar.gz zyyshop

      C.【主机操作】打包完成对主(Master)机所有表“解锁”:
        mysql> unlock tables;

      D.【主机操作】将两数据库打包文件SCP到从(Slave)机的数据目录中:
        # scp test.tar.gz zyyshop.tar.gz root@192.168.137.27:/usr/local/mysql/data/

      E.[从机操作]进入数据存放目录,解压数据包(生成数据库):
        # cd /usr/local/mysql/data/ 
        # tar -zxvf test.tar.gz
        # tar -zxvf zyyshop.tar.gz

      F.[从机操作] 在从(Slave)上执行命令(改变)连接主(Master)机,生成或更新master.info文件:
        此步同上D步,略......
      
   
      
八、主从复制中的几个重要文件
    IO线程只负责从主(Master)机端复制 mysql-bin.00000x 日志,并把复制来的数据全部都放到 localhost-relay-bin.00000n 日志里。
    SQL线程读取中继日志(relay-log.info)里的信息,将 localhost-relay-bin.00000n 日志里的数据写入本地从(Slave)机。

    1.master.info 作用:
      A.记录连接到主(Master)机的账号和密码;
      B.记录复制到主(Master)机的哪个二进制文件和复制到二进制文件的位置(pos点);

    2.relay-log.info 中继日志,作用:
      A.记录了写了多少数据到本地从(Slave)机中;

      
附、show slave status\G 返回信息解析:
    *************************** 1. row ***************************  
                   Slave_IO_State: Waiting for master to send event   # IO的线程的状态  
                      Master_Host: 192.168.137.26                     # 链接主服务器的IP  
                      Master_User: mark                               # 登录主服务器用户名  
                      Master_Port: 3306                               # 登录主服务器端口  
                    Connect_Retry: 10                                 # 主从断开后,多少秒重新链接  
                  Master_Log_File: mysql-bin.000004                   # 从服务器I/O 线程当前读取的主服务器二进制日志文件的名字  
              Read_Master_Log_Pos: 190                                # 从服务器I/O 线程从当前的主服务器二进制日志中读取的位置起点。  
                   Relay_Log_File: ip_lb-relay-bin.000002             # 从服务器SQL 线程当前读取并执行的中继日志文件的名字  
                    Relay_Log_Pos: 336                                # 从服务器SQL 线程当前从中继日志中读取执行的位置起点。  
            Relay_Master_Log_File: mysql-bin.000004                   # 从服务器中的SQL进程中正在执行的语句的位置  
                 Slave_IO_Running: Yes     # 从服务器的IO线程运行是否开启  
                Slave_SQL_Running: Yes     # 从服务器的SQL线程运行是否开启  
                  Replicate_Do_DB:         # 主从需要复制的数据库名  
              Replicate_Ignore_DB:         # 主从不需要复制的数据库名  
               Replicate_Do_Table:         # 主从需要复制的表           
           Replicate_Ignore_Table:         # 主从不需要复制的表  
          Replicate_Wild_Do_Table:         # 可以跨库复制的表  
      Replicate_Wild_Ignore_Table:         # 不能跨库复制的表  
                       Last_Errno: 0       # 最后复制的错误号...0表示没有错误  
                       Last_Error:         # 最后复制的错误信息  
                     Skip_Counter: 0       # 最近被使用的用于SQL_SLAVE_SKIP_COUNTER的值。(这个值表示跳过多少个事件在来执行SQL)  
              Exec_Master_Log_Pos: 190     # SQL线程执行到主服务器log-bin文件的位置.如果这个值与Read_Master_Log_Pos一样.则可以证明    
                  Relay_Log_Space: 492     # 所有原有的中继日志结合起来的总大小。  
                  Until_Condition: None    # 在START SLAVE语句的UNTIL子句中指定的值  
                   Until_Log_File:         # 在START SLAVE语句的UNTIL子句中指定的值  
                    Until_Log_Pos: 0       # 在START SLAVE语句的UNTIL子句中指定的值  
               Master_SSL_Allowed: No      # 这些字段显示了被从属服务器使用的参数。这些参数用于连接主服务器。  
               Master_SSL_CA_File:   
               Master_SSL_CA_Path:   
                  Master_SSL_Cert:   
                Master_SSL_Cipher:   
                   Master_SSL_Key:   
            Seconds_Behind_Master: 0   # 本字段是从属服务器“落后”多少的一个指示。当从属SQL线程正在运行时(处理更新),  
                                         本字段为在主服务器上由此线程执行的最近的一个事件的时间标记开始,已经过的秒数。  
                                         当此线程被从属服务器I/O线程赶上,并进入闲置状态,等待来自I/O线程的更多的事件时,本字段为零。  
                                         总之,本字段测量从属服务器SQL线程和从属服务器I/O线程之间的时间差距,单位以秒计。  
                                         如果主服务器和从属服务器之间的网络连接较快,则从属服务器I/O线程会非常接近主服务器,  
                                         所以本字段能够十分近似地指示,从属服务器SQL线程比主服务器落后多少。  
                                         如果网络较慢,则这种指示不准确;从属SQL线程经常会赶上读取速度较慢地从属服务器I/O线程,  
                                         因此,Seconds_Behind_Master经常显示值为0。即使I/O线程落后于主服务器时,也是如此。  
                                         换句话说,本列只对速度快的网络有用。  
                                         即使主机和从机不具有相同的时钟,时间差计算也会起作用(当从属服务器I/O线程启动时,计算
                                         时间差。并假定从此时以后,时间差保持不变)。  
                                         如果从属SQL线程不运行,或者如果从属服务器I/O线程不运行或未与主服务器连接,  
                                         则Seconds_Behind_Master为NULL(意义为“未知”)。  
                                         举例说明,如果在重新连接之前,从属服务器I/O线程休眠了master-connect-retry秒,则显示NULL,  
                                         因为从属服务器不知道主服务器正在做什么,也不能有把握地说落后多少。  
    Master_SSL_Verify_Server_Cert: No  
                    Last_IO_Errno: 0  
                    Last_IO_Error:   
                   Last_SQL_Errno: 0  
                   Last_SQL_Error:   
      Replicate_Ignore_Server_Ids:   
                 Master_Server_Id: 1  
    1 row in set (0.00 sec)  



参考文档:

MySQL5.5 主从复制 
http://blog.csdn.net/m582445672/article/details/7731565

mysql5.5 主从复制 (触发器,函数,存储引擎,事件处理)说明 
http://blog.csdn.net/m582445672/article/details/7670802

Mysql主从复制[生产环境]
http://wenku.baidu.com/link?url=a-SLn41EKYseSxikYViSqvf9IBwGh7d0NsaKPnBbZjc3sED4VF_NfpjMT5IrUhC3yeuq75geJuglzrz2RXmY41t3mVHcx9-oaNIAG6dRuIu

Slave_SQL_Running: No mysql同步故障解决方法
http://kerry.blog.51cto.com/172631/277414/

 

posted on 2013-12-02 17:31  马丁传奇  阅读(2223)  评论(0编辑  收藏  举报