zoukankan      html  css  js  c++  java
  • 《MySQL数据库》MySQL主从复制搭建与原理

    前言

    主从复制:两台或者更多的数据库实例,通过二进制日志,实现数据同步。为什么需要主从复制,主从复制的作用是什么,答:为了预防灾难。

    搭建

    第一步:准备多实例环境。如何创建多实例见:

    第二步:确保每一个实例的server_id 不同。

    检查各自实例图中(my.cnf)的配置是否不同。

    第三步:主库检查binlog 是否开启

    第四步:主库创建复制用户

    grant replication slave on *.* to repl@'%' identified by 'repl';

    第五步:主库和从库在主从之前要保证数据结构一致。

    主库备份,恢复到从库:https://www.cnblogs.com/jssj/p/13514597.html

    第六步:主从连接(重点)

    从库中执行以下语句,告知从库连接信息,同步开始点等(我这里有两个从库就两个从库都登入执行) 

    CHANGE MASTER TO
      MASTER_HOST='127.0.0.1',                 -- 主库ip
      MASTER_USER='repl',                      -- 主从专用用户
      MASTER_PASSWORD='repl',                  -- 用户密码
      MASTER_PORT=3307,                        -- 主库ip
      MASTER_LOG_FILE='mysql-bin.000001',      --复制开始点的binlog文件
      MASTER_LOG_POS=653,                      --binlog 文件中的开始点
      MASTER_CONNECT_RETRY=10;                 -- 重连次数
      MASTER_DELAY = 300;                      -- 从库SQL线程延时时间设置,(一般一主二从的时候,一从不加延时,一从加延时,这样逻辑误操作可以及时修复)

    第七步:从库中启动专用主从线程

    start slave ;      -- 启动主从
    stop slave;     -- 关闭主从

    扩展:

    start slave sql_thread  -- 单独启动从库sql线程
    start slave io_thread    -- 单独启动从库I/O线程
    stop slave sql_thread   -- 单独停从库sql线程
    stop slave io_thread     -- 单独停从库I/O线程

    第八步:验证主从复制是否正常

    查看从库线程

    mysql -uroot -S /usr/local/mysql/data/3308/mysql.sock -e "show slave statusG | grep Running"

    还有就是在主库上创建数据库,创建表等操作,看看从库是否和主库一致。

    如果搭建失败:

    执行:(没有问题别执行),然后重新执行以上步骤。  reset slave all  表示重置主从配置信息。

    mysql -uroot -S /usr/local/mysql/data/3308/mysql.sock -e "stop slave; reset slave all;"

    好了,到这里我们已经搭建完毕。

    原理

    文件部分

    从库文件(以下文件都默认放在数据文件目录下):

    主机名-relay-bin.000001      -- 默认叫这个名字,从主库接收到的binlog信息记录在这里

    主机名-relay-bin.000002      -- 默认叫这个名字,从主库接收到的binlog信息记录在这里

    主机名-relay-bin.index          -- 默认叫这个名字,从主库接收到的binlog信息记录在这里

    master.info                            --从库的配置信息: CHANGE MASTER TO ... 的信息。

    relay-log.info                         --存储接收的binlog

    mysql> select @@master_info_repository;     -- 设置从库配置信息存放的方式:文件/表

    mysql> select @@relay_log_info_repository;    -- relay-log存放方式:文件/表,默认文件

    mysql> select @@relay_log_purge;      -- relay_log是否开启删除已经被使用过的relay_log

    主库文件就是binlog 已经再之前文档讲过,这里不在说明https://www.cnblogs.com/jssj/p/13472394.html

    线程:

    主库下执行以下命令,查询线程:

    show processlist;

    图中可以看到两个 Binlog Dump的主从线程。 

    从库线程:搭建的第八步已经给出。两个线程一个I/O,一个SQL。

    主从复制的原理图:

    额外补充: 主库有变化会通过从库,从库就会及时去主库获取新的变化,MySQL的主从复制是通过这种方式来保证实时性的。

    参数

    mysql> show slave hosts;     -- 查看主库中被连接的从库信息

    mysql> show slave status G;    --查看从库信息

    重点字段说明

    change master to 的配置信息

    Master_Host: 127.0.0.1                             
    Master_User: repl                                      
    Master_Port: 3307                                     
    Connect_Retry: 10                                    
    Master_Log_File: mysql-bin.000004         
    Read_Master_Log_Pos: 154                    

    Relay_Log_File的执行情况:

    Relay_Log_File: iZm5e5v2zi93osbr5z21fvZ-relay-bin.000005      
    Relay_Log_Pos: 367                                                                      
    Relay_Master_Log_File: mysql-bin.000004

    Exec_Master_Log_Pos: 154

    从库线程状态:
    Slave_IO_Running: Yes              -- no 或者 connecting 都表示不正常。  网络,端口,防火墙,用户密码 ,权限replication slave,连接数上限,版本不一致等。
    Slave_SQL_Running: Yes         

    mysql> select @@max_connections;      -- 最大连接数

    从库线程报错信息:

    Last_IO_Errno: 0
    Last_IO_Error:
    Last_SQL_Errno: 0
    Last_SQL_Error:

    过滤复制相关信息:

    Replicate_Do_DB:
    Replicate_Ignore_DB:
    Replicate_Do_Table:
    Replicate_Ignore_Table:
    Replicate_Wild_Do_Table:
    Replicate_Wild_Ignore_Table:

    主从延时

    Seconds_Behind_Master: 0     -- 单位为秒(主二进制文件的事件和从库获取二进制文件的事件差,所以这个时间并不能说明主从没有延时)

    延时从库的配置信息:

    SQL_Delay: 0                          -- 通过主从配置的时候设置的 MASTER_DELAY; 

    SQL_Remaining_Delay: NULL

    GTID相关复制信息:从库显示的就是主库的GTID 和从库执行到的GTID。

    Retrieved_Gtid_Set:
    Executed_Gtid_Set:

    故障

    主从不一致的时候,会出现从库SQL线程down掉。

    先看参数: 报错内容

    Last_SQL_Errno: 0
    Last_SQL_Error:

    处理方式一:

    stop slave;                 --  停主从
    set global sql_slave_skip_counter = 1;     -- 设置参数跳过本次主从同步操作。 
    start slave;

    处理方式二:

    从库反操作一下:比如从库中已经存在主键记录,先把主键记录删除,重启start slave; 让其再同步一次。

    处理方式三(统一处理一下重复报错,不推荐):

    在MySQL参数配置文件:/etc/my.cnf 中设置

    slave-skip-errors = 1032,1062,1007      -- 常见错误代码:1007:对象已存在;1032:无法执行DML;1062:主键冲突,或约束冲突

    终极方式:重新搭建主从。

    一般情况:MySQL主从搭建从库是不需要有其他的操作的,也是为了减少不必要的主从问题,所以会设置一个参数:

    mysql> select @@read_only;     -- 1:只读,0:不是 (针对普通用户)

    mysql> select @@super_read_only;   -- 1:只读,0:不是 (针对普通管理员用户)

    主从延时

    主从延时监控:

    主库binlog执行到的位置点:

    从库relaylog执行到的位置点,

    是否存在差异,差异越大延时越严重。

    主从延时原因:

    1. 网络太慢。 

    2. 硬件性能。

    3. 主库业务繁忙。

    4. 从库太多。

    5. 5.6版本没有开启GTID(串行传输日志)。  -- 开启GTID,或者升级5.7 ,5.7默认支持并发传输日志。

    6. 锁也会导致延时。

    7.从库SQL线程串行执行,效率低,导致延时, 需要开启多个SQL线程来保证效率(必须开启GTID).并且5.7 版本还有逻辑时钟保证并发执行。 MTS

    恢复

    1. 如果是物理损坏, 主从非常简单的就可以恢复数据。 直接将从库数据导出,导入主库, 或者直接将从库当成主库使用。 

    stop slave;      -- 停掉主从服务
    reset slave all;     -- 去掉主从配置

    然后就可以临时当主库使用。

    2. 如果数逻辑损坏,比如drop了数据库。

    上面的情况下,我们就需要使用延时从库的功能了, 因为该从库是延时执行操作的, 故主库出现问题的时候从库是正常的。  所以可以通过从库恢复数据:

    CHANGE MASTER TO MASTER_DELAY = 300;   -- 设置延时

    1. 登录从库数据库停从库sql线程:

    stop slave sql_thread

    2. 查看relay.info 的位置点是否主库一致,表示日志文件已经同步:

    3. 恢复从库:

    截取relay_bin log位置点的起点

    show slave status G;

    截取relay_bin log位置点的终点

    找到使用的relay-bin 文件,然后使用下面的命令找到终点

    show relaylog events in 'iZm5e5v2zi93osbr5z21fvZ-relay-bin.000002'    -- 查看relaybinlog 文件

    获取pos字段就可以了,

    起点,终点都有了,然后截取命令:

    mysqlbinlog --start-position=634 --stop-position=861  /usr/local/mysql/data/3309/data/iZm5e5v2zi93osbr5z21fvZ-relay-bin.000002 > /usr/local/mysql/relay.sql

    恢复从库数据:

    mysql> set sql_log_bin = 0;    -- 关闭binlog日志
    mysql> source /usr/local/mysql/relay.sql;     -- 导入sql脚本(通过binlog截取出来的)
    mysql> set sql_log_bin = 1;    -- 开启binlog日志

    检查数据:

    4. 恢复主库:

    参考:https://www.cnblogs.com/jssj/p/13514597.html  的恢复章节。 导出从库数据库文件,导入主库。

    5. 恢复主从:

    从新设置主从:参考本文第一部分。

    过滤主从

    图中 数据库C 不需要主从复制。

    1. 主库设置不同步,不产生binlog 即可(不推荐)

    其中:binlog_Do_DB  是包含哪些库需要生成binlog日志;      binlog_ignore_DB 忽略掉一些数据库产品binlog日志

    2. 从库设置SQL线程不执行不需要复制的数据库(推荐)。

    [root@db01 ~]# vim my.cnf           -- 打开参数文件设置
    replicate_do_db=test                -- 需要写入从库的数据库
    replicate_do_db=test1               -- 需要写入从库的数据库

    重启数据库实例生效。

    扩展:

    replicate_do_db=test                -- 需要写入从库的数据库
    replicate_ignore_db=test1         -- 需要忽略写入从库的数据库
    
    replicate_do_table=test.test      -- 需要写入从库的数据库的表
    replicate_ignore_db=test1.test  -- 需要忽略写入从库的数据库的表
    
    replicate_wild_do_db=test.t*         -- 需要写入从库的数据库的模糊的表
    replicate_wild_ignore_db=test1.t*  -- 需要忽略写入从库的数据库模糊的表

    半同步主从

    在上面的主从复制的框架中有一个问题,就是主库不关心从库是否接收到数据,写入磁盘,容易出现从库和主库不一致的情况。

    已经属于历史功能,基本已经不使用了。

    原理:

    1. 主库执行新的事务,commit时,更新 show master statusG ,触发一个信号给
    2. binlog dump 接收到主库的 show master statusG信息,通知从库日志更新了
    3. 从库IO线程请求新的二进制日志事件
    4. 主库会通过dump线程传送新的日志事件,给从库IO线程
    5. 从库IO线程接收到binlog日志,当日志写入到磁盘上的relaylog文件时,给主库ACK_receiver线程
    6. ACK_receiver线程触发一个事件,告诉主库commit可以成功了
    7. 如果ACK达到了我们预设值的超时时间,半同步复制会切换为原始的异步复制.

    INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';  -- 主库加载插件
    INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';  --从库加载插件
    show plugins;       -- 查看加载情况
    SET GLOBAL rpl_semi_sync_master_enabled = 1;   -- 主库设置半同步
    SET GLOBAL rpl_semi_sync_slave_enabled = 1;     -- 从库设置半同步
    STOP SLAVE IO_THREAD;     -- 停止I/O线程
    START SLAVE IO_THREAD;    -- 启动I/O线程
    show status like 'Rpl_semi_sync_master_status';    -- 主库查看半同步状态
    show status like 'Rpl_semi_sync_slave_status';      -- 从库查看半同步状态

    GTID 主从复制(推荐)

    搭建GTID主从要注意一点:MySQL的data文件需要清理之后,从新搭建。

    my.cnf的配置文件如下:

    cat > /usr/local/mysql/data/3307/my.cnf <<EOF
    [mysqld]
    basedir=/usr/local/mysql/mysql-5.7.22-linux-glibc2.12-x86_64
    datadir=/usr/local/mysql/data/3307data
    socket=/usr/local/mysql/data/3307/mysql.sock
    log_error=/usr/local/mysql/data/3307/mysql.log
    port=3307
    server_id=7
    log_bin=/usr/local/mysql/log/3307/mysql-bin
    secure-file-priv=/tmp
    binlog_format=row
    autocommit=0
    gtid-mode=on                  #开启GTID
    enforce-gtid-consistency=true    #开启GTID
    log-slave-updates=1          #主从一至
    [mysql]
    prompt=db01 [\d]>
    EOF

    重新初始化数据:

    mysqld --initialize-insecure --user=mysql --basedir=/usr/local/mysql/mysql-5.7.22-linux-glibc2.12-x86_64  --datadir=/usr/local/mysql/data/3307/data

    启动实例:

    mysqld --defaults-file=/usr/local/mysql/data/3309/my.cnf &

    重新构建主从:主库

    grant replication slave on *.* to repl@'%' identified by 'repl';

    从库执行命令(和普通主从有区别):

    -- 主从配置信息
    change master to 
    master_host='127.0.0.1',
    MASTER_PORT=3307,  
    master_user='repl',
    master_password='repl' ,
    MASTER_AUTO_POSITION=1;     -- 主动获取主库的的位置点,根据从库的relay-bin.info去判断
    -- 开启主从
    start slave;

    原理:

    GTID 备份数据,然后复制到从库,从库启动后会自动判断到那些GTID被执行过,可以自动获取下一个GTID. 需要结合--set-gtid-purged。 默认自动开启。

    总结

    数据安全非常重要,所以数据库保证数据的安全是必须要实现的,这也是为什么会出现主从复制的原因,备份恢复操作比较麻烦,而且物理损坏修复也比较麻烦。主从演变到现在已经比较靠谱和完善了。

    This moment will nap, you will have a dream; But this moment study,you will interpret a dream.
  • 相关阅读:
    docker
    电商项目查询模块思路(ElasticSearch)
    Elasticsearch简单的使用步骤以及查询模块的实现
    string常用方法
    通用 Mapper常用方法
    Linux防火墙操作
    简单SQL语句
    InnoDB基础
    浅析索引
    python爬虫面试题集锦及答案
  • 原文地址:https://www.cnblogs.com/jssj/p/13546087.html
Copyright © 2011-2022 走看看