zoukankan      html  css  js  c++  java
  • MySQL学习笔记十七:复制特性

    一、MySQL的复制是将主数据库(master)的数据复制到从(slave)数据库上,专业一点讲就是将主数据库DDL和DML操作的二进制日志传到从库上,然后从库对这些二进制日志进行重做,使得主数据库与从数据库的数据保持同步。

    二、MySQL复制的一些优点:

    1. 可以将大部分的查询任务放在从库上进行,降低主库的负载,提高性能,但要注意实时性要求高的数据仍需在主库上读取。
    2. 如果主库出现了宕机,可以快速切换到从库上,提高了可用性。
    3. 可以在从库上进行数据备份,降低在备份期间对主库的影响。
    4. 将数据挖掘和分析等工作放在从库上进行,可以降低对主库的性能影响。

    三、MySQL复制处理数据的三种模式:

    1. 基于语句复制:也称为SBR(Statement Based Replication),基于实际执行的SQL语句来进行复制的方案,BINLOG_FORMAT=STATEMENT。
    2. 基于行的复制:也叫RBR(Row Bases Replication),BINLOG_FORMAT=ROW。
    3. 混合复制模式:也成MBR,基于SQL语句复制和行的复制,BINLOG_FORMAT=MIXED。

    查看二进制日志的格式:

    mysql> show global variables like 'binlog_format';
    +---------------+-----------+
    | Variable_name | Value     |  ---value的值有三种:statement,row,mixed
    +---------------+-----------+
    | binlog_format | STATEMENT |  
    +---------------+-----------+
    1 row in set (0.00 sec)

    设置二进制日志的格式:

    mysql> set global binlog_format='row';   --设置全局binlog_format,可以使用set session binlog_format='row'来设置当前会话的binlog_format
    Query OK, 0 rows affected (0.00 sec)
    mysql> show GLOBAL variables like 'binlog_format';
    +---------------+-------+
    | Variable_name | Value |
    +---------------+-------+
    | binlog_format | ROW   |
    +---------------+-------+
    1 row in set (0.00 sec)

    在SQL中查看日志文件中的事件:

    mysql> show binlog events in 'mysql-bin.000027' from 107; --from指定从日志哪个位置开始
    +------------------+-----+------------+-----------+-------------+---------------------------------------------+
    | Log_name         | Pos | Event_type | Server_id | End_log_pos | Info                                        |
    +------------------+-----+------------+-----------+-------------+---------------------------------------------+
    | mysql-bin.000027 | 107 | Query      |      3306 |         175 | BEGIN                                       |
    | mysql-bin.000027 | 175 | Query      |      3306 |         264 | use `test`; insert into t1 values (10)      |
    | mysql-bin.000027 | 264 | Query      |      3306 |         333 | COMMIT                                      |
    | mysql-bin.000027 | 333 | Query      |      3306 |         401 | BEGIN                                       |
    | mysql-bin.000027 | 401 | Query      |      3306 |         495 | use `test`; update t1 set id=70 where id=60 |
    | mysql-bin.000027 | 495 | Query      |      3306 |         564 | COMMIT                                      |
    | mysql-bin.000027 | 564 | Stop       |      3306 |         583 |                                             |
    +------------------+-----+------------+-----------+-------------+---------------------------------------------+
    7 rows in set (0.00 sec)

    基于SQL语句的二进制日志记录原始SQL操作,而基于ROW格式的二进制日志记录的是每行数据的变更,采用64位编码,使用mysqlbinlog查看时须搭配--base64-output='decode-rows' --vv参数来解码查看。

    四、MySQL复制流程

     MySQL复制基于二进制日志,开启二进制日志功能是必须的。当从库启动复制时(start slave),首先创建一个I/O线程连接主库,主库接着创建Binlog Dump线程读取二进制日志事件发送给从库的I/O线程,I/O线程获取数据后更新从库的中继日志Relay Log,然后从库的SQL线程读取中继日志中更新的数据库事件并应用,如下图所示:


    可以使用SHOW PROCESSLIST命令在主库和从库上分别执行,查看主库BINLOG DUMP线程和从库SQL线程状态:

    ----------------------在主库上-------------
    mysql> show processlistG
    *************************** 3. row ***************************
         Id: 18
       User: repl
       Host: localhost:2275
         db: NULL
    Command: Binlog Dump
       Time: 76
      State: Master has sent all binlog to slave; waiting for binlog to be updated
       Info: NULL
    3 rows in set (0.00 sec)
    --------------------在从库上---------------
    *************************** 2. row ***************************
         Id: 27
       User: system user
       Host:
         db: NULL
    Command: Connect
       Time: 301
      State: Waiting for master to send event
       Info: NULL
    *************************** 3. row ***************************
         Id: 28
       User: system user
       Host:
         db: NULL
    Command: Connect
       Time: 246703
      State: Slave has read all relay log; waiting for the slave I/O thread to update it
       Info: NULL

    五、搭建复制环境

    由于本人苦逼学生一枚,只有一台电脑,所以只能在一台电脑上开启多个MySQL服务,开启过程如下所示:

      1.停止mysql服务

      2.copy mysql安装目录到指定目录E:,这里随意,不要和原目录重叠即可

      3.copy mysql data数据文件到E:data

      4.copy一份my.ini文件到上面指定的目录下

      5.修改复制后的配置文件my.ini,内容如下:

      [client]

      port=3307 #第一个数据库的默认端口是3306 这里需要另外启用一个端口

      # The TCP/IP Port the MySQL Server will listen on

      port=3307

      # Path to installation directory. All paths are usually resolved relative to this.

      basedir="E:MySQLMySQL Server 5.5"         #第二个数据库basedir

      # Path to the database root

      datadir="E:MySQLMySQL Server 5.5data"    #第二个数据库datadir

      6.创建新的mysql服务

      mysqld install MySQLSLAVE  --defaults-file="E:MySQLMySQL Server 5.5my.ini"

      7.修改注册表,如下:

      KEY_LOCAL_MACHINE-->SYSTEM-->CurrentControlSet-->Services

      找到刚才创建的MySQLSLAVE,将ImagePath修改成如下":

      "E:MySQLMySQL Server 5.5inmysqld" --defaults-file="E:MySQLdatamy.ini" mysqlsalve

    复制环境搭建过程如下:

      1.修改主数据库的配置文件my.ini,修改内容如下:

    server-id=3306
    #主从复制是通过二进制文件来进行,所以要开启日志功能
    log-bin=mysql-bin
    #主机,读写都可以
    read-only=0
    #需要备份数据,多个写多行
    binlog-do-db=test
    #不需要备份的数据库,多个写多行
    binlog-ignore-db=mysql

      2.修改从数据库的配置文件my.ini,修改内容如下:

    #主从配置
    server-id=3307
    log-bin=mysql-bin
    #如果从服务器发现主服务器断掉,重新连接的时间差(秒)
    #master-connect-retry=60
    #只复制某个库
    replicate-do-db=test
    #不复制某个库
    replicate-ignore-db=mysql

      3.保持主从的test库初始状态一致

    mysql> flush tables with read lock;  
    Query OK, 0 rows affected (0.05 sec)
    ---首先锁定表为读有效,防止数据库有更新操作,然后利用COPY/CP命令将数据文件目录复制到从库数据目录下
    ---或者直接关闭mysql服务,手动复制数据文件目录到指定目录下
    ---拷贝完后,恢复写操作

     mysql> unlock tables;
     Query OK, 0 rows affected (0.00 sec)

     

      4.在主库上创建一个专门用来复制的用户repl

    mysql> GRANT REPLICATION SLAVE ON *.* TO 'REPL'@'127.0.0.1' IDENTIFIED BY '1234567';
    Query OK, 0 rows affected (0.31 sec)

      5.重启主库,然后执行show master status,记下file和position字段对应的参数

    mysql> show master status;
    +------------------+----------+--------------+------------------+
    | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
    +------------------+----------+--------------+------------------+
    | mysql-bin.000031 |      262 | test         | mysql            |
    +------------------+----------+--------------+------------------+
    1 row in set (0.00 sec)

      6、在从库设置它的master:

    mysql> change master to master_host='127.0.0.1',master_port=3306,master_user='repl',master_password='asdf',master_log_file='mysql-bin.000031',master_log_pos=262;
    
    Query OK, 0 rows affected (0.19 sec)
    ----这里的master_log_file和master_log_pos对应刚才show master status记下的参数。

      7.在从库上开启复制start slave

    mysql> start slave;
    Query OK, 0 rows affected, 1 warning (0.00 sec)  --这里有个warning,是因为我已经开启了slave

      8.验证复制搭建是否成功

    mysql> show processlistG;
    *************************** 2. row ***************************
         Id: 27
       User: system user
       Host:
         db: NULL
    Command: Connect
       Time: 6349
      State: Waiting for master to send event
       Info: NULL
    *************************** 3. row ***************************
         Id: 28
       User: system user
       Host:
         db: NULL
    Command: Connect
       Time: 580
      State: Slave has read all relay log; waiting for the slave I/O thread to update it
       Info: NULL
    3 rows in set (0.00 sec)
    ----以上信息表名slave已经连上了master,并开始接收和执行日志---

      9.使用show slave status来查看slave信息

    mysql> show slave statusG
    *************************** 1. row ***************************
                   Slave_IO_State: Waiting for master to send event
                      Master_Host: 127.0.0.1
                      Master_User: repl
                      Master_Port: 3306
                    Connect_Retry: 60
                  Master_Log_File: mysql-bin.000031
              Read_Master_Log_Pos: 262
                   Relay_Log_File: Lenovo-PC-relay-bin.000059
                    Relay_Log_Pos: 408
            Relay_Master_Log_File: mysql-bin.000031
                 Slave_IO_Running: Yes  --I/O线程已开启
                Slave_SQL_Running: Yes --SQL线程也开启
                  Replicate_Do_DB: test
              Replicate_Ignore_DB: mysql
               Replicate_Do_Table:
           Replicate_Ignore_Table:
          Replicate_Wild_Do_Table:
      Replicate_Wild_Ignore_Table:
                       Last_Errno: 0
                       Last_Error:
                     Skip_Counter: 0
              Exec_Master_Log_Pos: 262
                  Relay_Log_Space: 714
                  Until_Condition: None
                   Until_Log_File:
                    Until_Log_Pos: 0
               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
    Master_SSL_Verify_Server_Cert: No
                    Last_IO_Errno: 0  --I/O没有错误
                    Last_IO_Error:
                   Last_SQL_Errno: 0  --sql应用也没有错误
                   Last_SQL_Error:
      Replicate_Ignore_Server_Ids:
                 Master_Server_Id: 3306
    1 row in set (0.00 sec)

      10.验证复制的正确性

    -------在主库上的test库创建表cc------
    mysql> create table cc (id int not null);
    Query OK, 0 rows affected (0.10 sec)
    
    mysql> insert into cc values (10),(20);
    Query OK, 2 rows affected (0.00 sec)
    Records: 2  Duplicates: 0  Warnings: 0
    -------在从库上查看是否存在表cc-----
    mysql> show tables like 'cc';
    +---------------------+
    | Tables_in_test (cc) |
    +---------------------+
    | cc                  |
    +---------------------+
    1 row in set (0.00 sec)
    
    mysql> select *  from cc;
    +----+
    | id |
    +----+
    | 10 |
    | 20 |
    +----+
    2 rows in set (0.00 sec)
    ------------说明复制搭建已经成功------

    六、半同步复制

    MySQL复制默认采用异步的同步机制,主库和从库的数据之间存在一定的延时,不能保证数据的一致性和及时性。因此有必要开启半同步复制,而半同步复制模式是由mysql插件来实现,主从库使用不同的插件(semisync_master.so/semisync_slave.so),安装插件如下所示。

    检查mysql服务是否支持动态加载插件

    mysql> show variables like '%dynamic_loading%';
    +----------------------+-------+
    | Variable_name        | Value |
    +----------------------+-------+
    | have_dynamic_loading | YES   |
    +----------------------+-------+
    1 row in set (0.00 sec)
    ----也可以直接执行select @@have_dynamic_loading

    安装插件

    mysql> install plugin  rpl_semi_sync_master soname 'semisync_master.dll';
    ERROR 1125 (HY000): Function 'rpl_semi_sync_master' already exists   --我已经安装了该插件

    查看插件安装是否成功

    mysql> select * from mysql.plugin;
    +----------------------+---------------------+
    | name                 | dl                  |
    +----------------------+---------------------+
    | rpl_semi_sync_master | semisync_master.dll |
    +----------------------+---------------------+
    1 row in set (0.03 sec)

    从库也使用同样的方法安装semisync_slave插件

    mysql> select * from mysql.plugin;
    +---------------------+--------------------+
    | name                | dl                 |
    +---------------------+--------------------+
    | rpl_semi_sync_slave | semisync_slave.dll |
    +---------------------+--------------------+
    1 row in set (0.00 sec)

    打开半同步复制,因为mysql默认是关闭的

    mysql> show variables like '%semi_sync%';
    +------------------------------------+-------+
    | 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    |
    +------------------------------------+-------+
    ---------主库------
    mysql> set global rpl_semi_sync_master_enabled=on;
    Query OK, 0 rows affected (0.01 sec)
    ---------从库-------------
    mysql> set global rpl_semi_sync_slave_enabled=on;
    Query OK, 0 rows affected (0.00 sec)
    ----重启I/O线程
    mysql> stop slave io_thread;
    Query OK, 0 rows affected (0.01 sec)
    
    mysql> start slave io_thread;
    Query OK, 0 rows affected (0.00 sec)

    半同步复制配置完毕后,查看半同步复制的状态信息,在主库上执行show global status like '%semi_sync%';

    mysql> show global status like '%semi_sync%';
    +--------------------------------------------+-------+
    | Variable_name                              | Value |
    +--------------------------------------------+-------+
    | Rpl_semi_sync_master_clients               | 1     |
    | Rpl_semi_sync_master_net_avg_wait_time     | 0     |
    | Rpl_semi_sync_master_net_wait_time         | 0     |
    | Rpl_semi_sync_master_net_waits             | 0     |
    | Rpl_semi_sync_master_no_times              | 0     |
    | Rpl_semi_sync_master_no_tx                 | 0     | --表示不是通过半同步复制及时响应的事务数
    | Rpl_semi_sync_master_status                | ON    | --表示当前半同步复制已经打开
    | Rpl_semi_sync_master_timefunc_failures     | 0     |
    | Rpl_semi_sync_master_tx_avg_wait_time      | 0     |
    | Rpl_semi_sync_master_tx_wait_time          | 0     |
    | Rpl_semi_sync_master_tx_waits              | 0     |
    | Rpl_semi_sync_master_wait_pos_backtraverse | 0     |
    | Rpl_semi_sync_master_wait_sessions         | 0     |
    | Rpl_semi_sync_master_yes_tx                | 0     | --表示通过半同步模式复制到从库的事务数
    +--------------------------------------------+-------+
    14 rows in set (0.00 sec)

    半同步同步还有一个超时时间,超过了这个时间,主库将关闭半同步复制模式,改为异步复制。如果这时从库重新连接主库,主库将自动切换到半同步复制模式。查看超时时间

    mysql> show variables like '%semi%time%';
    +------------------------------+-------+
    | Variable_name                | Value |
    +------------------------------+-------+
    | rpl_semi_sync_master_timeout | 10000 | --10s
    +------------------------------+-------+
    1 row in set (0.00 sec)

    七、MySQL复制主要启动参数

    1.master_host,master_port,master_user,master_password这些参数主要用来记录需要复制的主库的地址,端口,用户,密码等信息,就不具体介绍了。

    2.log_slave_updates:用来指定从库的更新操作是否记录到二进制日志中去,如果要搭建的是主-主复制,则该参数必须指定为ON(set global log_slave_updates=on或在配置文件中永久启动)

    3.read-only:用来限制普通用户对从库的更新操作,只接收超级用户的更新操作。

    4.master_connect_retry:指定当和主库丢失连接时重试的时间间隔,默认为60。

    5.replicate_do_db,replicate_ignore_db,replicate_do_table,replicate_ignore_table:这些参数用来指定复制的数据库或表,比如指定复制的表为replicate_do_table=test.cc,其他的表则不会复制。

    6.slave_skip_errors:用来指定从库复制中可以跳过的错误号或跳过全部错误,slave_skip_errors=[err_code1,err_code2...|all]

    7.master_delay:用来指定延时复制的时间隔间

    八、复制的管理维护

    1.查看从库状态

    mysql> show slave statusG
    *************************** 1. row ***************************
                   Slave_IO_State: Waiting for master to send event
                      Master_Host: 127.0.0.1
                      Master_User: repl
                      Master_Port: 3306
                    Connect_Retry: 60
                  Master_Log_File: mysql-bin.000031
              Read_Master_Log_Pos: 736
                   Relay_Log_File: Lenovo-PC-relay-bin.000060
                    Relay_Log_Pos: 442
            Relay_Master_Log_File: mysql-bin.000031
                 Slave_IO_Running: Yes
                Slave_SQL_Running: Yes
                  Replicate_Do_DB: test
              Replicate_Ignore_DB: mysql
               Replicate_Do_Table:
           Replicate_Ignore_Table:
          Replicate_Wild_Do_Table:
      Replicate_Wild_Ignore_Table:
    ----截取部分信息

    2.主库和从库同步

    -----在主库上执行-----
    mysql> flush tables with read lock;
    Query OK, 0 rows affected (0.00 sec)
    -----在从库上执行-----
    mysql> select master_pos_wait('mysql-bin.000031',' 736');
    +--------------------------------------------+
    | master_pos_wait('mysql-bin.000031',' 736') |
    +--------------------------------------------+
    |                                          0 |
    +--------------------------------------------+
    1 row in set (0.03 sec)
    --master_pos_wait的参数值可以在主库执行show master status得到
    --该select语句会阻塞到从库达到指定的日志文件的偏移量后,返回0,表示与主库同步了
    --完了之后在主库上执行unlock tables

    3.从库复制出现错误

    在从库应用中继日志时,可能会出现一些错误,例如表结构不对,函数不存在等,如果是不太重要的错误,则可使用sql_slave_skip_counter变量来忽略更新失败的语句。示例如下:

    mysql> stop slave;
    Query OK, 0 rows affected (0.02 sec)
    
    mysql> set global sql_slave_skip_counter=1;
    ----如果是autoincrement或last_insert_id()则为2
    
    mysql> start slave;
    Query OK, 0 rows affected (0.00 sec)

    4.主-主复制时自增变量冲突的问题

    主-主复制需要定制auto_increment_increnment和auto_increment_offset的值来避免重复冲突,这两个变量的值默认为1,这也是重复冲突的源头

    mysql> show variables like 'auto_increment_%';
    +--------------------------+-------+
    | Variable_name            | Value |
    +--------------------------+-------+
    | auto_increment_increment | 1     |
    | auto_increment_offset    | 1     |
    +--------------------------+-------+
    2 rows in set (0.00 sec)

    采用以下的设置可以避免重复

    master1:auto_increment_increment=2,auto_increment_offset=1
    master1:auto_increment_increment=2,auto_increment_offset=0

    5.提高复制性能

    方案一:采用一主多从的复制架构,利用replicate_do_db,replicate_ignore_db等参数使得不同的从库复制不同的库/表,降低每个从库的写入压力。

    方案二:利用5.6版本的多线程并发复制,通过设置变量slave_parallel_workers来实现。

    stop slave
    set global slave_parallel_works=2;
    start slave;
    ---或者在my.ini中天加slave_parallel_workers=2

    6.主从切换

    1.在每个从库上执行stop slave io_thread,停止接收日志,接着执行show processlist,如果state字段值为Has read all relay log,表示更新都应用完毕。

    2.在需要提升为主库的从库上执行stop slave,reset slave和reset master,将从库重置成主库。

    3.其他的从库执行都执行stop slave,然后执行change master to master_host=新的主库地址。

    4.所有应用指向新的主库。

  • 相关阅读:
    leetcode之String to Integer (atoi)
    初次思考
    leetcode之Reverse Words in a String
    Leetcode之Database篇
    在项目中添加类
    创建项目
    配置Eclipse

    递归
    多态
  • 原文地址:https://www.cnblogs.com/zmxmumu/p/4467589.html
Copyright © 2011-2022 走看看