Mysql主从复制

China☆狼群 提交于 2019-12-09 16:54:59

Mysql传统主从复制

参考文章

一、基本概念和原理

  • 概念

    官方文档Replication enables data from one MySQL database server (the master) to be copied to one or more MySQL database servers (the slaves). Replication is asynchronous by default; slaves do not need to be connected permanently to receive updates from the master. Depending on the configuration, you can replicate all databases, selected databases, or even selected tables within a database

    大致的含义:将数据从主数据库服务器复制到一个或者多个从服务器上,复制默认是异步进行的,从服务器不要一直接受主服务器的更新。根据你的配置,你可以复制主服务器上全部的数据库或者选择其中的数据库,设置是一个库中选定的表

  • 原理

    mysql.jpg

  1. 主数据库服务器的操作记录到二进制日志binary log,这个操作需要主服务器开启二进制日志记录,log-bin = mysql-binlog-bin指定了二进制日志文件名称
  2. 从库服务器IO线程负责连接主服务,监控和接受主服务器的二进制日志,当主服务器的二进制服务器发生变化时候,IO进程将其读取并复制写入到replay log文件中.
  3. 从服务器SQL 进程用于监控,读取replay log,将日志文件中记录的事务在本地执行,存储到本地
  4. 在从库服务器读取二进制日志文件需要指定当前二进制文件以及binary log的偏移量position

主服务器复制的在复制进行前,slave上必须具有master上部分完整内容作为复制基准数据。例如,master上有数据库A,二进制日志已经写到了pos1位置,那么在复制进行前,slave上必须要有数据库A,且如果要从pos1位置开始复制的话,还必须有和master上pos1之前完全一致的数据。如果不满足这样的一致性条件,那么在replay中继日志的时候将不知道如何进行应用而导致数据混乱。也就是说,复制是基于binlog的position进行的,复制之前必须保证position一致。(注:这是传统的复制方式所要求的)

二、复制的好处

  • 读写分离:Scale-out solutions - spreading the load among multiple slaves to improve performance. In this environment, all writes and updates must take place on the master server. Reads, however, may take place on one or more slaves. This model can improve the performance of writes (since the master is dedicated to updates), while dramatically increasing read speed across an increasing number of slaves.
  • **数据安全:**Data security - because data is replicated to the slave, and the slave can pause the replication process, it is possible to run backup services on the slave without corrupting the corresponding master data.
  • **数据分析:**Analytics - live data can be created on the master, while the analysis of the information can take place on the slave without affecting the performance of the master.
  • **负载均衡:**Long-distance data distribution - you can use replication to create a local copy of data for a remote site to use, without permanent access to the master

三、复制的方法和同步类型

  • 复制的方式

**官方文档: **MySQL 5.7 supports different methods of replication. The traditional method is based on replicating events from the master’s binary log, and requires the log files and positions in them to be synchronized between master and slave. The newer method based on global transaction identifiers (GTIDs) is transactional and therefore does not require working with log files or positions within these files, which greatly simplifies many common replication tasks. Replication using GTIDs guarantees consistency between master and slave as long as all transactions committed on the master have also been applied on the slave。

这里简单的介绍一下MySQL 5.7 支持的基本复制方式,传统的复制是依据主数据库的二进制文件,从服务器请求主服务器的二进制日志和偏移量,最新的方式是依据全事务ID(GTIDS),不需要确认二进制日志的位置,通过事务提交保证主从库的一致性

  • 同步类型

    MySQL支持4种不同的同步方式:同步(synchronous)、半同步(semisynchronous)、异步(asynchronous)、延迟(delayed)。所以对于复制来说,就分为同步复制、半同步复制、异步复制和延迟复制

四、传统复制的异步实现方式

(一)、实验环境

服务器 ip Mysql版本 状态
master 10.18.0.220 Mysql 5.7.27 存在待同步的数据库
slave 10.18.0.226 Mysql 5.7.27

(二)、同步准备

Tip: 本人使用的是windows系统,命令执行一般使用Git bash,但是Git bash是不支持交互式命令的,如果使用mysql的连接命令需要在前面加上winptywinpty是window类Unix的接口包,如果连接数据库命令是winpty mysql -u root -p

  • 主从服务器具有相同的状态
  1. 可以使用mysqldump工具进行导出备份,使用选项与mysql连接选项基本一致

    参考资料:https://www.cnblogs.com/f-ck-need-u/p/9013458.html

    • 连接选项
    -u, --user=name    指定用户名
    -S, --socket=name   指定套接字路径
    -p, --password[=name] 指定密码
    -P, --port=          指定端口
    -h, --host=name    指定主机名
    
    • 筛选选项
    --all-databases, -A  
    指定dump所有数据库。等价于使用--databases选定所有库
    --databases, -B  
    指定需要dump的库。该选项后的所有内容都被当成数据库名;在输出文件中的每个数据库前会加上建库语句和use语句
    --ignore-table=db_name.tbl_name  
    导出时忽略指定数据库中的指定表,同样可用于忽略视图,要忽略多个则多次写该选项
    -d, --no-data       
    不导出表数据,可以用在仅导出表结构的情况。
    --events, -E  
    导出事件调度器
    --routines, -R   
    导出存储过程和函数。但不会导出它们的属性值,若要导出它们的属性,可以导出mysql.proc表然后reload
    --triggers  
    导出触发器,默认已开启
    --tables 
    覆盖--databases选项,导出指定的表。但这样只能导出一个库中的表。格式为--tables database_name tab_list
    --where='where_condition', -w 'where_condition'  
    指定筛选条件并导出表中符合筛选的数据,如--where="user='jim'"
    

    1.1 将主服务器要同步的数据库枷锁,避免同步时数据发生改变

    mysql>use db;
    mysql>flush tables with read lock;  
    

    1.2 将主服务器数据库中数据导出

    [root@localhost ~]# mysqldump —R -uroot -p cloud >cloud.sql
    

    1.3 解锁数据库

    mysql>unlock tables;
    

    4、将初始数据导入从服务器数据库

    mysql>create database db;
    mysql>use db;
    mysql>source db.sql;
    
  2. 可以数据库工具Navicat工具进行备份(仅适合测试环境)

(三)、配置服务器

配置文件详解:

  1. 为master和slave设定不同的server-id,这是主从复制结构中非常关键的标识号。到了MySQL 5.7,似乎不设置server id就无法开启bin log。设置server id需要重启Mysql实例。
  2. 开启master的binlog。刚安装并初始化的Mysql默认未开启binlog,建议手动设置binlog且为其设定文件名,否则默认以主机名为基名时修改主机名后会找不到日志文件。
  3. 最好设置master上的变量sync_binlog=1(MySQL 5.7.7之后默认为1,之前的版本默认为0),sync_binlog=0,表示MySQL不控制binlog的刷新,由文件系统自己控制它的缓存的刷新。这时候的性能是最好的,但是风险也是最大的。因为一旦系统Crash,在binlog_cache中的所有binlog信息都会被丢失.如果sync_binlog>0,表示每sync_binlog次事务提交,MySQL调用文件系统的刷新操作将缓存刷下去。最安全的就是sync_binlog=1了,表示每次事务提交,MySQL都会把binlog刷下去,是最安全但是性能损耗最大的设置。这样的话,在数据库所在的主机操作系统损坏或者突然掉电的情况下,系统才有可能丢失1个事务的数据。但是binlog虽然是顺序IO,但是设置sync_binlog=1,多个事务同时提交,同样很大的影响MySQL和IO性能。虽然可以通过group commit的补丁缓解,但是刷新的频率过高对IO的影响也非常大。对于高并发事务的系统来说,“sync_binlog”设置为0和设置为1的系统写入性能差距可能高达5倍甚至更多,MySQL DBA设置的sync_binlog并不是最安全的1,而是100或者是0。这样牺牲一定的一致性,可以获得更高的并发和性能
  4. 最好设置master上的redo log的刷盘变量innodb_flush_log_at_trx_commit=1(默认值为1),这样每次提交事务都会立即将事务刷盘保证持久性和一致性。
  5. 在slave上开启中继日志relay log。这个是默认开启的,同样建议手动设置其文件名。
  6. 建议在master上专门创建一个用于复制的用户,它只需要有复制权限replication slave用来读取binlog。
  7. 确保slave上的数据和master上的数据在"复制的起始position之前"是完全一致的。如果master和slave上数据不一致,复制会失败。
  8. 记下master开始复制前binlog的position,因为在slave连接master时需要指定从master的哪个position开始复制。
  9. 考虑是否将slave设置为只读,也就是开启read_only选项。这种情况下,除了具有super权限(mysql 5.7.16还提供了super_read_only禁止super的写操作)和SQL线程能写数据库,其他用户都不能进行写操作。这种禁写对于slave来说,绝大多数场景都非常适合
2.1 master数据库配置
  • master服务器数据库配置文件 [mysqld]添加如下配置
#主数据库端ID号
server_id = 1           
 #开启二进制日志                  
log-bin = mysql-bin    
#需要复制的数据库名,如果复制多个数据库,重复设置这个选项即可                  
binlog-do-db = db                             
#控制binlog的写入频率,参考下面配置详细解释
sync_binlog = 100                    
  • 重启mysql服务

  • 添加新用户,赋予复制权限

    mysql>create user 'warren'@'10.18.0.226' identified by '123456';
    mysql>grant REPLICATION SLAVE on *.* to 'warren'@'10.18.0.226';
    mysql>flush privileges;
    
  • 查看主服务器状态

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

    File 是主数据库的二进制文件 Position偏移量 ,

2.2 slave数据库配置
  • slave服务器数据库配置文件 [mysqld]添加如下配置
# 指定relay-log 名称
relay-log=slave-bin
# service-id 必须唯一,一般是选择ip配置
server-id=111
replicate-do-db = db         
#MySQL主从复制的时候,当Master和Slave之间的网络中断,但是Master和Slave无法察觉的情况下(比如防火墙或者路由问题)。Slave会等待slave_net_timeout设置的秒数后,才能认为网络出现故障,然后才会重连并且追赶这段时间主库的数据
slave-net-timeout = 60 
  • 执行同步命令

    mysql> change master to 
            master_host='192.168.100.20',
            master_port=3306,
            master_user='warren',
            master_password='123456',
            master_log_file='master-bin.000002',
            master_log_pos=33984361;
    mysql> start slave;
    
  • 查看slave状态

    mysql> show slave status\G;
    *************************** 1. row ***************************
                   Slave_IO_State: Waiting for master to send event
                      Master_Host: 10.18.0.220
                      Master_User: account
                      Master_Port: 3306
                    Connect_Retry: 60
                  Master_Log_File: mysql-bin.000002
              Read_Master_Log_Pos: 2598
                   Relay_Log_File: localhost-relay-bin.000002
                    Relay_Log_Pos: 1538
            Relay_Master_Log_File: mysql-bin.000002
                 Slave_IO_Running: Yes
                Slave_SQL_Running: Yes
                  Replicate_Do_DB: db
              Replicate_Ignore_DB:
               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: 2598
                  Relay_Log_Space: 3188
                  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
                    Last_IO_Error:
                   Last_SQL_Errno: 0
                   Last_SQL_Error:
      Replicate_Ignore_Server_Ids:
                 Master_Server_Id: 1
                      Master_UUID: 302302d1-ec19-11e9-aa5b-0242ac120003
                 Master_Info_File: /usr/local/mysql/data/master.info
                        SQL_Delay: 0
              SQL_Remaining_Delay: NULL
          Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
               Master_Retry_Count: 86400
                      Master_Bind:
          Last_IO_Error_Timestamp:
         Last_SQL_Error_Timestamp:
                   Master_SSL_Crl:
               Master_SSL_Crlpath:
               Retrieved_Gtid_Set:
                Executed_Gtid_Set:
                    Auto_Position: 0
             Replicate_Rewrite_DB:
                     Channel_Name:
               Master_TLS_Version:
    1 row in set (0.00 sec)
    
    ERROR:
    No query specified
    

    Slave_IO_Running及Slave_SQL_Running进程必须正常运行,即Yes状态,否则说明同步失败
    若失败查看mysql错误日志中具体报错详情来进行问题定位

(五)、常见的1236错误

**转载:**Mysql error 1236原因和解决方法: https://www.cnblogs.com/zhoujinyi/p/4760184.htmll

1.1 logevent超过max_allowed_packet 大小

  1. Got fatal error 1236 from master when reading data from binary log: 'log event entry exceeded max_allowed_packet; Increase max_allowed_packet on master; the start event position from ‘mysql-bin.006730’ at 290066246, the last event was read from '/u01/my3309/log/mysql-bin.006730

原因
此类报错和max_allowed_packet相关。首先max_allowed_packet控制着主从复制过程中,一个语句产生的二进制binlog event大小,它的值必须是1024的倍数 。出现此类错误的常见原因是
1 该参数在主备库的配置大小不一样,主库的配置值大于从库的配置值。 从主库传递到备库的binlog event大小超过了主库或者备库的max_allowed_packet大小。
2 主库有大量数据写入时,比如在主库上执行 laod data,insert into … select 语句,产生大事务。
当主库向从库传递一个比从库的max_allowed_packet 大的packet ,从库接收该packet失败,并报 “log event entry exceeded max_allowed_packet“。
如何解决
需要确保主备配置一样,然后尝试调大该参数的值。

  1. set global max_allowed_packet =110241024*1024;
  2. stop slave;
  3. start slave

另外,5.6 版本中的 slave_max_allowed_packet_size 参数控制slave 可以接收的最大的packet 大小,该值通常大于而且可以覆盖 max_allowed_packet 的配置, 进而减少由于上面的问题导致主从复制中断。
1.2 slave 在主库找不到binlog文件

  1. Got fatal error 1236 from master when reading data from binary log:

原因
该错误发生在从库的io进程从主库拉取日志时,发现主库的mysql_bin.index文件中第一个文件不存在。出现此类报错可能是由于你的slave 由于某种原因停止了好长一段是时间,当你重启slave 复制的时候,在主库上找不到相应的binlog ,会报此类错误。或者是由于某些设置主库上的binlog被删除了,导致从库获取不到对应的binglog file。
如何解决
1 为了避免数据丢失,需要重新搭建slave 。
2 注意主库binlog的清理策略,选择基于时间过期的删除方式还是基于空间利用率的删除方式。
不要使用rm -fr 命令删除binlog file,这样不会同步修改mysql_bin.index 记录的binlog 条目。在删除binlog的时候确保主库保留了从库 show slave status 的Relay_Master_Log_File对应的binlog file。
1.3 主库空间问题,日志被截断

  1. Got fatal error 1236 from master when reading data from binary log: 'binlog truncated in the middle of event; consider out of disk space on master; the start event position from ‘mysql-bin.006730’ at 290066434, the last event was read from '/u01/my3309/log/mysql-bin.006730

原因
该错误和主库的空间问题和sync_binlog配置有关,当主库 sync_binlog=N不等于1且磁盘空间满时,MySQL每写N次binary log,系统才会同步到磁盘,但是由于存储日志的磁盘空间满而导致MySQL 没有将日志完全写入磁盘,binlog event被截断。slave 读取该binlog file时就会报错"binlog truncated in the middle of event;"
当sync_binlog 的默认值是0,像操作系统刷其他文件的机制一样,MySQL不会同步到磁盘中去而是依赖操作系统来刷新binary log。
当sync_binlog =N (N>0) ,MySQL 在每写 N次 二进制日志binary log时,会使用fdatasync()函数将它的写二进制日志binary log同步到磁盘中去。
如何解决
在从库重新指向到主库下一个可用的binlog file 并且从binlog file初始化的位置开始,如果master是全新的数据库实例,或者在此之前没有开启过binlog,那么它的坐标位置是position=4。之所以是4而非0,是因为binlog的前4个记录单元是每个binlog文件的头部信息。

  1. stop slave;
  2. change master to master_log_file=‘mysql-bin.006731’, master_log_pos=4;
  3. start slave;

2.4 主库异常断电,从库读取错误的position

  1. 120611 20:39:38 [ERROR] Error reading packet from server: Client requested master to start replication from impossible position ( server_errno=1236)
  2. 120611 20:39:38 [ERROR] Slave I/O: Got fatal error 1236 from master when reading data from binary log: ‘Client requested master to start replication from impossible position’, Error_code: 1236
  3. 120611 20:39:38 [Note] Slave I/O thread exiting, read up to log ‘mysql-bin.000143’, position 664526789

【原因】
该问题也是和sync_binlog=N不等于1有关,多出现在主机异常crash ,比如磁盘损坏,raid 卡损坏,或者主机异常掉电导致binlog 未及时同步到磁盘。从库读取了主库binlog file中的不存在的binlog position ,一般比binlogfile 的end position 的值还要大。
如何解决
1 在从库重新指向到主库下一个可用的binlog file 并且从binlog file初始化的位置开始

  1. stop slave;
  2. change master to master_log_file=‘mysql-bin.000144’, master_log_pos=4;
  3. start slave;

2 主备库设置 sync_binlog=1,但是设置为1的时候,会带来性能下降。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!