zoukankan      html  css  js  c++  java
  • 浅析MySQL复制

    MySQL的复制是基于binlog来实现的。

    流程如下

    涉及到三个线程,主库的DUMP线程,从库的IO线程和SQL线程。

    1. 主库将所有操作都记录到binlog中。当复制开启时,主库的DUMP线程根据从库IO线程的请求将binlog中的内容发送到从库。

    2. 从库的IO线程接受到主库DUMP线程发送的binlog事件后,将其写到本地的relay-log。

    3. 从库的SQL线程重放relay-log中的事件。

    实际上,在MySQL 4.0之前,复制只有两个线程,master和slave端各一个。在Slave端,该线程同时负责接收主库发来的binlog事件,也负责事件的重放,所以没有使用relay-log,这样容易导致,当binlog事件的重放速度较慢时,会影响binlog事件的接受。

    复制的搭建

    基本步骤如下:

    1. 配置主库和从库

    2. 创建复制的账号

    3. 创建主库一致性快照

    4. 根据主库的快照,建立从库

    5. 开启复制

    详细步骤如下

    1. 配置主库和从库

    主库

    开启binlog并设置server-id

    [mysqld]
    log-bin=mysql-bin
    server-id=1

    在一组复制结构中,每个服务器必须配置一个唯一的server-id。该值的有效范围为1~232-1。

    如果server-id设置为0的话,则MySQL会自动将它更改为1。此时,对复制没有影响。

    如果server-id没有显式设置的话,则MySQL同样会将它设置为1,但是从连接的时候,IO线程会报错

    Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Misconfigured master - server_id was not set'

    从库

    设置server-id

    [mysqld]
    server-id=2

    在从服务器上,可以选择不开启binlog。当开启了binlog后,如果想把重放的时间同样也记录到binlog中,可将log_slave_updates参数设置为1。

    设置完毕后,重启数据库

    2. 创建复制账号

    主库上执行

    mysql> CREATE USER 'repl'@'%.mydomain.com' IDENTIFIED BY 'slavepass';
    mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%.mydomain.com';

    3. 创建主库一致性快照

    在这里,我用mysqldump来创建数据库快照

    # mysqldump --master-data=2  -R --single-transaction -A > 3306_20160815.sql

    在生成的备份文件中,我们可以得到在对数据库执行一致性快照时主的状态,包括二进制文件的名称及位置

    # head -30 3306_20160815.sql

    ...
    -- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000016', MASTER_LOG_POS=120;
    ...

    4. 根据主库的快照,建立从库

    # mysql < 3306_20160815.sql

    5. 开启复制

    根据第3步获取到的主库状态执行CHANGE MASTER TO命令

    mysql> CHANGE MASTER TO
             MASTER_HOST='master_host_name',
             MASTER_USER='replication_user_name',
             MASTER_PASSWORD='replication_password',
             MASTER_LOG_FILE='recorded_log_file_name',
             MASTER_LOG_POS=recorded_log_position;

    在执行CHANGE MASTER TO命令后,从库并不会连接到主库,而只是将这些信息写入到从库数据目录下的master.info和relay-log.info中。如果没有显式指定MASTER_LOG_FILE,则默认为空,因为此时还没有和主库建立连接,并不知道主库binlog的文件名称,只有等到和主库建立连接时才能知道。如果MASTER_LOG_POS没有显式指定,则默认为4,即忽略binlog的头4个字节,从第一个事件开始读取。

    开启复制功能

    mysql> start slave;

    查看复制的状态

    mysql> show slave statusG

    重点关注以下两个变量,如果为YES,则代表复制搭建成功。

    ...
    Slave_IO_Running: Yes
    Slave_SQL_Running: Yes
    ...

    注:以上搭建场景是基于主库上已经有一定的数据。如果在全新的环境中搭建,实际上会更简单。

    只需获取主库的状态信息即可

    mysql> show master status;
    +------------------+----------+--------------+------------------+-------------------+
    | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
    +------------------+----------+--------------+------------------+-------------------+
    | mysql-bin.000016 |      120 |              |                  |                   |
    +------------------+----------+--------------+------------------+-------------------+
    1 row in set (0.00 sec

    MySQL复制的格式

    MySQL的复制有三种格式:

    Statement-based replication(SBR)

    基于语句的复制,即master上执行的SQL语句原封不动的在slave上重放。该复制格式在MySQL 3.23即出现了。

    优点:

    1. 节省binlog的空间。

    2. 可用于审核,毕竟所有的DML语句都是直接记录在binlog中。

    缺点:

    1. 很多函数在主从上执行的结果并不一致

    LOAD_FILE(),UUID(), UUID_SHORT(),USER(),FOUND_ROWS(),SYSDATE(),GET_LOCK(),IS_FREE_LOCK(),IS_USED_LOCK(),MASTER_POS_WAIT(),RAND(),RELEASE_LOCK(),SLEEP(),VERSION()

    2. DELETE和UPDATE操作,带了LIMIT子句,却没有带ORDER BY,可能导致主从执行的结果并不一致。

    3. 相对于基于行的复制,master上执行INSERT ... SELECT操作需要更多的行锁。

    4. 自定义函数(UDF)必须确保执行的结果是确定的。

    Row-based replication(RBR)

    基于行的复制,MySQL 5.1引入的,相对于SBR,它记录的是DML操作涉及到的行。

    优点:

    1. 安全。master上所有的变更都能复制到slave上。

    2. 在执行以下操作时,只需更少的行锁。

        INSERT ... SELECT

        带有AUTO_INCREMENT列的INSERT操作

        UPDATE和DELETE中,WHERE条件没有用上索引。

    缺点:

    1. 会产生大量的日志。

    譬如一张表有1w条记录,如果我不带任何条件执行delete操作,则在基于statement的复制中,在binlog中只会记录delete from table这一条记录,但是在基于row的复制中,则会记录1w笔记录,每笔记录类似于delete from table where ..。

    这会带来以下问题

     1> 如果利用binlog进行恢复,会需要更长的时间.

     2> 在写数据到binlog中时,因为数据量大,会导致binlog的锁定时间较长,影响数据库的并发。

     3> 较大的日志会对磁盘IO和网络IO产生较大的压力。

     4> 增大slave的延迟。

    2. 不会对二进制日志进行校验。

    3. 不推荐基于库级别的复制

        包括--replicate-do-db, --replicate-ignore-db, --replicate-rewrite-db

    MIXED

    MIXED是上述两者的的结合,会根据执行的语句和涉及的存储引擎自动在这两种模式间切换。默认情况下,采用的是基于语句的复制模式,在遇到unsafe statements时,会切换为基于行的复制模式。

    关于切换的条件,可参考官方文档:http://dev.mysql.com/doc/refman/5.7/en/binary-log-mixed.html

    在MySQL 5.7.7之前,默认的是基于语句的复制模式,从MySQL 5.7.7开始,默认基于行的复制模式。

    复制中涉及的文件

    relay-log

    relay-log保存着从库IO线程从主库读取到的binlog事件。和binlog格式一样,可通过mysqlbinlog解析其中的内容。

    可通过配置relay_log和relay_log_index参数设置relay-log和relay-log.index文件的名称。

    relay-log在如下情况下会发生切换:

    1. slave IO线程启动的时候。

    2. 执行FLUSH LOGS操作的时候。

    3. 达到参数max_relay_log_size设置的大小,默认为0,即以max_binlog_size的值作为max_relay_log_size的大小。

    slave SQL线程在重放完一个relay-log文件中的所有事件后,会自动删除relay-log文件(由relay_log_purge参数控制),所以没有显式删除relay-log的命令。

    master.info

    该文件保存了主库的主机名,端口,复制账号的用户名和密码,以及从库接受主库binlog事件的位置信息,通过这些位置信息,从库的IO线程知道下次从哪里获取主库的binlog事件。

    该位置信息对应于show slave statusG中的Master_Log_File和Read_Master_Log_Pos。

    如下所示:

    # cat master.info

    23
    mysql-bin.000014
    120
    192.168.244.10
    repl
    repl
    3306
    60
    0
    
    
    
    
    
    0
    1800.000
    
    0
    cad449f2-5d4f-11e6-b353-000c29c64704
    86400
    
    
    0

    relay-log.info

    该文件记录从库的重放信息,这样即便数据库发生重启,SQL线程也知道该从哪里开始重放。

    该位置信息对应于show slave statusG中的Relay_Master_Log_File和Exec_Master_Log_Pos。

    # cat relay-log.info

    7
    ./mysqld-relay-bin.000024
    283
    mysql-bin.000014
    120
    0
    0
    1
    1

    Crash-Safe Replication

    slave每次接受binlog或者应用relay-log时,都要修改master.info或relay-log.info的信息并同步到磁盘中,这会导致大量的磁盘操作,所以,一般都是采用异步方式来对这两个文件进行更改。虽然每次都会修改这些文件,但是持久化到磁盘却留给操作系统处理。在内存与磁盘中的信息不一致时,如果此时操作系统宕机,内存中的信息将无法及时同步到磁盘中。操作系统恢复后,master.info和relay-log.info的数据依然是旧的,所以会从已经执行的部分重新执行。

    MySQL 5.6为了改善这个问题,提供了两个参数,可将master.info和relay-log.info中的内容保存在表中而不是磁盘文件中。

    master-info-repository

    可设置为TABLE或FILE,如果使用FILE,则复制的位置信息依旧保存在master.info中,如果设置为TABLE,则信息报保存在mysql.slave_master_info中,默认为FILE。

    relay-log-info-repository

    可设置为TABLE或FILE,如果使用FILE,则应用relay-log的信息会保存在relay-log.info中,如果设置为TABLE,则保存在mysql.slave_relay_log_info中,默认为FILE。

    通过将上述两个变量设置为TABLE,可实现“Crash-Safe Replication”,上述的相关操作都会放到一个事务中进行。

    总结

    1. 启用复制功能并不会增加服务器太多的开销,主要是开启binlog带来的开销,包括binlog文件的追加写操作开销,以及系统调用fsync带来的开销。

    2. MySQL的复制功能具有向后兼容性,因为较新版本的MySQL的binlog中会进入新的事件类型。所以,可以将较新版本的MySQL作为从库。

    3. MySQL复制是异步的。

    4. MySQL 5.6开始新增延迟复制功能,由master_delay参数来控制。

    参考

    1. http://dev.mysql.com/doc/refman/5.7/en/replication-configuration.html

    2. MariaDB原理与实现

        

        

  • 相关阅读:
    【设计】概要设计-详细设计-到底需要输出什么???
    【Java】Eclipse代码格式化-代码模板
    【Scala】Scala学习资料
    【Java】阿里巴巴Java开发手册(纪念版)
    【Storm】学习笔记
    【HBase】学习笔记
    【Hadoop】Combiner的本质是迷你的reducer,不能随意使用
    【Hadoop】mapreduce采用多进程与spark采用多线程比较
    【ES】elasticsearch学习笔记
    【MySQL】MySQL统计NULL字段处理
  • 原文地址:https://www.cnblogs.com/ivictor/p/5764978.html
Copyright © 2011-2022 走看看