mysql主从复制以及扩展

一、MySQL简单复制相关概念:

   1. mysql复制的意义:Mysql复制是使得mysql完成高性能应用的前提

   2. mysql复制的机制: 

           SLAVE端线程: 

     IO thread: 向主服务请求二进制日志中的事件

                        当读取完毕后,IO线程将进行睡眠,当主服务器有新数据时,则主服务器唤醒从服务器的IO线程

     SQL thread:从中继日志读取事件并在本地执行,

                        如果二进制日志开启式,同样会记录二进制日志,但为了节约空间和提高性能,需要关闭

     从服务器不能执行写操作,如果执行写操作则和主服务器不同步。 

   MASTER端:

     binlog dump: 将IO thread请求的事件发送给对方;

    默认为异步工作模式:主要主服务器自己写完,不管从服务器是否写完,就将返回

二、MySQL复制的常见构架

    1. 主从构架

        1)对于一从多主,只有新版本Mysql可以实现。 通常来说,一个从只能有一个主服务器,但是可以轮换。在某一时刻只能有一台主服务器。 

              MariaDB-10:支持多主模型,多源复制(multi-source replication)

        2)一主多从:执行写操作只能对主服务器进行。 多从会增大主服务器压力。 

             此时需要一个调度器,来分离读写请求到主从服务器上。所谓读写分离

        3)读写分离:主从模型下,让前端分发器能识别读/写,并且按需调度至目标主机;

                  amoeba,mysql-proxy可以实现读写分离调度

              读服务器进行负载均衡,使用一致性哈希算法,虚拟节点来分配访问。

   2.双主构架

    1) 使用server_id来避免循环赋值

    2) 必须设定双方的自动增长属性,以避免冲突, 一个使用偶数一个实用技术

           第一台服务器:

                auto_increment_increment=1 定义自动增长字段起始值

                auto_increment_offset=2 步长

          第二台服务器

                auto_increment_increment=2 定义自动增长字段起始值

                auto_increment_offset=2 步长

                通过以上设定来解决冲突问题。 

    3) 数据不一致; 在双主模型下某些时刻会导致数据不同步。

          第一个服务器锁定第一个字段改第二个字段

          第二台服务器锁定第二个字段改第一个字段

            例如一个表包含: Age, Salary

            如果一个人的年龄为31而工资2900,执行以下操作

                 A: update t1 set Salary=salary+1000 WHERE Age>=30;

                 B: update t1 set Age=Age-3 WHERE Salary < 3000;

            会导致:

                 服务器A Salary 变为3900,年龄31

                 服务器B Salary 变为年龄28, 工资290

    4) 功能:

          不能分摊写请求,两个服务器写压力一致。 

三、复制构架扩展

    1. 主从服务器之间的差距

长时间运行后,主从可能不同步。 因为主服务器可以写并发,但是从服务器的同步只能是但进程。 

        从服务器落后,有时候需要认为设计,来做备份。 

    2. 一主多从的环境: 

        1) 一主多从的环境中,为了利用各从服务器的缓存能力。需要一些负载均衡算法,来绑定特定查询到特定服务器上,来使得缓存命中。这是这样做使得均衡效果被打破,使得有的服务器过于繁忙。

        2) 为了解决此问题,可以引入中心缓存服务器。

        3) 由于换从服务器工作在旁路模式下,所以是否缓存取决于客户端程序。

            memcached:可以提供缓存能力+API 

            公共缓存服务器,性能比Mysql自身差

    3. 多级复制: 主指向一个从,从同时也作为其他从服务器的主 

            master –> slave/master —> slave

            中间服务器需要开启二进制日志和中继日志 

            多级复制可以降低主服务器产生mysqldump的压力,把压力分摊给下一集。 但是可能使得数据不能更好跟新。 

            可以把中间服务器的读写引擎改为black hole,来降低本地压力,只生成二进制日志作为中继服务器(relay server),然后把二进制日志发送给下游服务器

    4. 模拟一从多主模型: 

            根据时间,来却换不同的主。 

            通常用于在不同服务器之间做数据收集。 

    5. 环状模型: 

            每台服务器都是下一台服务器的主服务器同时也是上一台服务器的从服务器,使得每台服务器都是主从,形成传递环。

            每台服务器的修改都会同步到环上任何一台服务器中。 

                    server_id 不能相同。 

    6. 常见mysql构架

        1)一主一从,并且读取分离 

        2)一主多从,主负责读,从负责写

        3)一主多从外加一个冷备服务器, 只用于备份。 每一段时间关掉进行备份。 

        4)多主模型: 通过心跳信息探测主服务器的健康状态,如果一个主挂掉,马上切换另一个主

            潜在问题: 第一台服务器上未提交的事务,切换时将被回滚。 

                GTID(GLOBAL TRANSACTION id): 保证在特定服务器上的事务是完整的,如果执行不成功就回滚。 

    7.高级应用架构: 

        读写分离+负载均衡: 读直到从服务器上面读,写只在主服务器上面写。 需要在读写分离器之前加memocached

                amoeba, mysql proxy

    8. 异地同步: 主要避免自然灾害

四、 简单主从构架配置过程

    1. 配置需留意

         1)版本注意:主从版本一致,或者主版本高于从版本

         2)从哪儿开始复制:

                1. 都从0开始:

                2. 主服务器已经运行一段时间,并且存在不小的数据集:

            把主服务器备份,然后在从服务恢复,从主服务器上备份时所处的位置开始复制;

    2. 配置过程:

        主服务器:

            1. 改server-id: 配置文件中写入

        vim /etc/my.cnf 在服务器段写入
            server_id=1        
        mysql> SHOW GLOBAL  VARIABLES LIKE 'server_id'; 
        +---------------+-------+
        | Variable_name | Value |
        +---------------+-------+
        | server_id     | 1     |
        +---------------+-------+
        1 row in set (0.01 sec)

            2. 启用二进制日志

        log_bin=/data/binlog/mysql-bin 同样写在配置文件的服务器段       
        mysql> SHOW GLOBAL  VARIABLES LIKE 'log_bin%';
        +---------------------------------+------------------------------+
        | Variable_name                   | Value                        |
        +---------------------------------+------------------------------+
        | log_bin                         | ON                           |
        | log_bin_basename                | /data/binlog/mysql-bin       |
        | log_bin_index                   | /data/binlog/mysql-bin.index |

            3. 创建有复制权限的帐号

        mysql> GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO 'slaveUser'@'192.168.98.133' IDENTIFIED BY 'slaveuser' ;        
        mysql> FLUSH PRIVILEGES ;

        从服务器:

            1. 改server-id, 写在配置文件中

        server_id=11

            2. 启用中继日志,关闭二进制日志,写入配置文件中

        log_bin=OFF        
        relay_log=/data/relay_log/relay_bin

            3. 连接主服务器

        命令: CHANGE MASTER TO            
            MASTER_HOST = '',  主服务器地址
            MASTER_USER='', 使用哪个用户连接
            MASTER_PASSWORD='',  密码
            MASTER_LOG_FILE='',  用来复制特定的哪一个二进制文件
            MASTER_LOG_POS=;从这个二进制文件的哪个位置开始复制
            最重要的参数只有前三个,就可以开始工作
        mysql> CHANGE MASTER TO MASTER_HOST='192.168.98.129',MASTER_USER='slaveUser',MASTER_PASSWORD='slaveuser';

            4. 启动复制线程

        mysql>START SLAVE;
              这里其实可以单独操作两个线程,可以独自控制1/O线程或者SQL线程开启
        # tail /var/log/mysql.log             
            2015-12-07 15:54:35 8511 [Note] Slave SQL thread initialized, starting replication in log 'FIRST' at position 0, relay log '/data/relay_log/relay_bin.000001' position: 4
        mysql>SHOW SLAVE STATUS \G; 重点查看一下几行 
              Master_Host: 192.168.98.129
              Master_User: slaveUser
              Master_Port: 3306
              Connect_Retry: 60
              Master_Log_File: mysql-bin.000001
              Read_Master_Log_Pos: 8443
              Relay_Log_File: relay_bin.000002
              Relay_Log_Pos: 8606
              Relay_Master_Log_File: mysql-bin.000001
              Slave_IO_Running: Yes
              Slave_SQL_Running: Yes
              Exec_Master_Log_Pos: 8443
              Relay_Log_Space: 8773

        简单主从复制实验过程的一些总结: 

            1)主服务器二进制日志如果在数据库初始化的时候开启了,则从服务器需要指定初始化结束后的日志进行复制。否则貌似会出现一些奇怪的错误。也许是因为无法再次创建系统库所致

            2)主服务器最好在系统库初始化完成后再开启二进制日志。 这样从服务器就可以直接从第一个二进制日志开始复制。 

            3)如果错误日志中出现错误通常就是slave sql 线程,Slave I/O 产生的。 如果slave I/O出问题通常与权限和链接有关。 Slave sql出问题通常与二进制日志在从服务器执行有关。 

    3. 在主从架构中跟复制相关的文件: 

        1) master.info: 用于保存了从服务器连接到主服务器需要的信息。每一行有一个值。 不同的mysql版本格式不一样。 如果不想链接,直接删了就好了

        2)relay-log.info: 二进制日志和中继日志的位置, 日志坐标, 会不停的自动更新。由于更新不会马上执行,会存在缓冲区,如果断电,信息会丢失

            为了复制安全性,需要在从服务器上,需要在从服务器上开启一下参数。

        sync_master_info  =1     
        sync_relay_log    =1   
        sync_relay_log_info =1

        3)从服务器意外崩溃时,建议使用pt-slave-start命令来启动slave; 

    4. 基于行和基于语句的复制: 

        1) 基于语句: 

            优点: 数据量小,易于查看和识别,适应性强

            缺点: 有些语句无法精确复制,使用触发器存储过程等代码的应用实现精确复制。 

        2)基于行复制: 

            优点: 都能精确完成复制,包括出发器存储过程,能完成几乎所有的复制功能, 较少占用CPU资源,可以减少锁的使用

            缺点: 通过日志无法判断执行了哪些语句, 数据可能略大。 

        3)单独使用基于语句的场景几乎不存在,默认为混合模式。 

    5. 从服务器落后于主服务器如何检测: 

    mysql> SHOW SLAVE STATUS \G; 可以查看     
    Seconds_Behind_Master: 0
    这里显示落后主服务器多少秒。 
    如果主服务器繁忙,这个值通常都为正值, 如果此值在波动而不是变大。都可以接受。

     6. 评估主从服务器表数据是否一致: 

            procona-toolkit里面的一些工具可以进行监控 

            pt-table-checksum  在主服务器上面运行,可以自动寻找哪个表不同步

        不同步的解决方法: 

            1.从新备份,并在从服务器上导入数据。 

            2.使用pt-table-sync完成同步

                pt-summary 可以得到一些mysql的统计数据,有些时候有用

    7. 为了提高复制时的数据安全性,在主服务器上的设定:

        sync_binlog = 1    
        innodb_flush_log_at_trx_commit = 1
    此参数的值设定为1,性能下降会较严重;因此,一般设定为2等,此时,主服务器崩溃依然有可能导致从服务器无法获取到全部的二进制日志事件;
    如果主服务器意外崩溃,有二进制日志中事件没复制完损坏,可以在从服务器使用如下参数忽略: 
        sql_slave_skip_counter = 0
    数据目录磁盘空间不足,也可导致复制无法进行。需要结合监控工具做整体评估。 
    主服务器修改过大,使得带宽不够用。

五、MySQL简单复制应用扩展

    1. 主从服务器需要保证时间同步,可以使用ntp服务

    2. 如何限制从服务器制度

        read_only=ON 定义在[mysqld]

        注意: 对于不具有super权限的用户有效,因此管理员依然有效,切勿使用管理员权限在从服务器上修改数据。 

        想限制所有用户:

        mysql> FLUSH TABLES WITH READ LOCK;

    3. 如何主从复制时的事务安全

        当主服务器事务,尚未同步到二进制日志中时, 如果主服务器宕机,则从服务器无法获取完整的事务,当从服务器指向其它主服务器时候,有可能导致事务回滚。从而使得事务丢失。 

        在主服务器上配置一下参数解决, 只要事务提交,则立即将事务从二进制缓冲区同步到二进制日志中。

        sync_binlog=1
        innodb_flush_log_at_trx_commit=1

        此变量设置后,会产生一些性能损耗,主要原因是MyISAM或者Innodb是默认自动提交事务的。为了提高性能可以关掉自动提交,同时开启以上选项用。 

        全同步: 主服务器写操作 –> 写操作同步到二进制日志 –> 写操作被复制到从服务器的二进制日志中 –> 才从服务器上执行写操作 –> 然后返回给主服务器

    4. 使用半同步复制(semi-synchronously)机制可以在主服务器性能一定损失的前提下实现更好地同步.

        前面部分与全同步相同,只是在对于一主多从的场景中,主服务器只等待一个最快的从服务器范围写完成状态。 

        半同步的配置: mysql5.5以后google提供,在lib/plugin目录下的两个插件semisync_master.so, semisync_slave.so。

    主服务器配置: 
        装载semisync_master.so模块
            mysql> INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
        装载后,将会多出几个选项
            mysql> SHOW GLOBAL VARIABLES LIKE '%semi%'; 
                +------------------------------------+-------+
                | Variable_name                      | Value |
                +------------------------------------+-------+
                | rpl_semi_sync_master_enabled       | OFF   |
                | rpl_semi_sync_master_timeout       | 10000 |
                | rpl_semi_sync_master_trace_level   | 32    |
                | rpl_semi_sync_master_wait_no_slave | ON    |
                +------------------------------------+-------+
            rpl_semi_sync_master_enabled : 控制是否开启半同步 
            rpl_semi_sync_master_timeout : 半同步超时时长,多长时间半同步从服务器还为回复时,跳过半同步继续执行。 单位为毫秒,默认为10秒钟
            rpl_semi_sync_master_wait_no_slave : 如果半同步服务器不回应,则跳过半同步服务器继续执行。
        修改修改前两个参数: 
            mysql> SET GLOBAL rpl_semi_sync_master_enabled='ON'; 
            mysql> SET GLOBAL rpl_semi_sync_master_timeout=2000;
    从服务器配置: 
        装载semisync_master.so模块 
            mysql> INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
        装载后会出现以下参数 
            mysql> SHOW GLOBAL VARIABLES LIKE '%semi%';
            +---------------------------------+-------+
            | Variable_name                   | Value |
            +---------------------------------+-------+
            | rpl_semi_sync_slave_enabled     | OFF   |
            | rpl_semi_sync_slave_trace_level | 32    |
            +---------------------------------+-------+
        从服务器这里只需要把第一个开启就好: 
            mysql> SET GLOBAL rpl_semi_sync_slave_enabled='ON'; 
            mysql> STOP SLAVE IO_THREAD;
            mysql> START SLAVE IO_THREAD;
            如果不重启I/O 线程,则半同步从服务器特性不能被主服务器识别,此时主服务器上进行操作,会超时,然后跳过半同步。 
        查看状态
            mysql> SHOW GLOBAL STATUS LIKE '%semi_sync%'; 
            +--------------------------------------------+-------+
            | Variable_name                              | Value |
            +--------------------------------------------+-------+
            | Rpl_semi_sync_master_clients               | 1     |
            这里显示,半同步客户端有一个,说明半同步正常使用。 
            如果由于网络或其他原因,检测到半同步超时,则可以重启从服务器的1/O线程,来重启半同步功能。

    5. 在主从复制架构中,仅复制一部分数据解决方案,使用复制过滤器实现

        主服务器过滤: 主服务器仅往二进制日志中记录像样的服务器

                优缺点:主服务器磁盘I/O 带宽节约

                缺点:但是其他数据库数据不安全,无法完成时间点还原

            参数: 

        binlog_do_db= 
        binlog_igore_db=

         在从服务器上,仅读取相应的信息

                基于库

        replicate_do_db=        
        replicate_ignore_db=

              基于表

        replicate_do_table=db_name.tb_name 
        replicate_ignore_table=

             基于表使用通配符

        replicate_wild_do_table=
        replicate_wild_ignore_table=

    6. 配置多主模型

        1) 两台服务器上各自建立一个具有复制权限的用户;

    主A: 
        mysql> GRANT REPLICATION CLIENT,REPLICATION SLAVE ON *.* TO 'slaveUser'@'192.168.98.129' IDENTIFIED BY 'slaveuser';
        mysql> FLUSH PRIVILEGES ;
    主B: 
        mysql> GRANT REPLICATION CLIENT,REPLICATION SLAVE ON *.* TO 'slaveUser'@'192.168.98.129' IDENTIFIED BY 'slaveuser';
        mysql> FLUSH PRIVILEGES ;

        2) 修改配置文件:

        # 主服务器A上
            [mysqld]
            server_id=1
            log_bin=/data/binlog/mysql-bin
            relay-log=/data/relaylog/relay-bin
            auto-increment-offset=1## 起始位置
            auto-increment-increment=2## 自动增长的步长
        # 主服务器B上
            [mysqld]
            server_id=11
            relay_log=/data/relaylog/relay_bin
            log_bin=/data/binlog/mysql_bin
            auto-increment-offset=2## 起始位置
            auto-increment-increment=2## 自动增长的步长

        3) 相互作为从服务器指向对方 

        mysql> CHANGE MASTER TO MASTER_HOST='192.168.98.133',MASTER_USER='slaveUser',MASTER_PASSWORD='slaveuser',MASTER_LOG_FILE='mysql_bin.000002',MASTER_LOG_POS=120;        
        mysql> CHANGE MASTER TO MASTER_HOST='192.168.98.129',MASTER_USER='slaveUser',MASTER_PASSWORD='slaveuser',MASTER_LOG_FILE='mysql-bin.000004',MASTER_LOG_POS=120; 
            此时就可以相互传数据了: 
        这里有一个奇怪的现象: 
            如果两个服务器一个一个插入数据,则可以总体顺序按照1,2,3,4顺序
            如果一个服务器连续插入两个以上,比如A连续插入两个,B插入两个, 则序号变为1,3,4,6。 
            也就是说不能在已插入位置之前插入序号。

        多主模型和高可用解决方案 

            MMM: Multi Master Mysql 

            MHA: Mysql HA 

    7. 基于SSL进行通信 

        服务器端,验证客户端。 

原创文章,作者:以马内利,如若转载,请注明出处:http://www.178linux.com/10024

联系我们

400-080-6560

在线咨询

工作时间:周一至周五,9:30-18:30,节假日同时也值班

QR code