摆摊也要抽时间学的MySQL主从复制

前言

听说大家现在都在积极响应国家号召,没事的时候会推着三轮车去街角、天桥摆个地摊。博主刚刚收摊回来,顺手写了篇MySQL。

MySQL相信大家都很熟悉了,单节点MySQL出现性能瓶颈的时候,大家首先想到的是优化SQL。但是单节点毕竟能力有限,所以在优化之后,还是无法满足性能要求时,就会想到部署MySQL读写分离,也就是主从复制。除了性能瓶颈之外,还有单节点故障、单节点容量等问题,都必须依靠集群才能解决。本篇主要讲解MySQL从单机到集群的原理和实践。

环境

  • VMware Workstation 15
  • CentOS Linux release 7.7.1908
  • MySQL 5.7.30

注意事项

  • 三个节点ip分别为192.168.1.101192.168.1.102192.168.1.103
  • 确保三个节点都能访问互联网,并且三个节点能够相互通信
  • 确保Linux的yumwget等基础命令可用
  • 建议先关闭防火墙,Centos 7操作如下
    firewall-cmd --state ## 查看防火墙状态 not running表示已经关闭
    systemctl stop firewalld.service ## 关闭防火墙
    systemctl disable firewalld.service ## 禁止开机启动防火墙
    

需要搭建的主从复制集群如下
MySQL主从复制

单机安装

安装

整个过程请保持网络畅通

wget -i -c http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm
yum -y install mysql57-community-release-el7-10.noarch.rpm
yum -y install mysql-community-server

到这一步,MySQL服务的安装已经完成

启动

启动MySQL

systemctl start  mysqld.service

查看运行状态

systemctl status mysqld.service

执行结果

● mysqld.service - MySQL Server
   Loaded: loaded (/usr/lib/systemd/system/mysqld.service; enabled; vendor preset: disabled)
   Active: active (running) since 二 2020-06-02 21:58:25 CST; 11s ago
     Docs: man:mysqld(8)
           http://dev.mysql.com/doc/refman/en/using-systemd.html
  Process: 2160 ExecStart=/usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid $MYSQLD_OPTS (code=exited, status=0/SUCCESS)
  Process: 2111 ExecStartPre=/usr/bin/mysqld_pre_systemd (code=exited, status=0/SUCCESS)
 Main PID: 2163 (mysqld)
   CGroup: /system.slice/mysqld.service
           └─2163 /usr/sbin/mysqld --daemonize --pid-file=/var/run/mysqld/mysqld.pid

6月 02 21:58:18 localhost.localdomain systemd[1]: Starting MySQL Server...
6月 02 21:58:25 localhost.localdomain systemd[1]: Started MySQL Server.

根据日志可以看到MySQL Server已经成功启动

找到临时密码

在MySQL的启动日志中,会打印一个临时密码用于登录,用户名是root

cat /var/log/mysqld.log |grep password

执行结果

2020-06-02T13:58:21.946584Z 1 [Note] A temporary password is generated for root@localhost: cScTwtyMl4;*

可以看到我此处的临时密码是cScTwtyMl4;*
用这个密码登录,登录之后需要修改密码,才能进行其他的操作,且密码要满足一定的复杂度

alter user 'root'@'localhost' identified by 'your password';

因为安装了Yum Repository,以后每次yum操作都会自动更新,需要把这个卸载掉

yum -y remove mysql57-community-release-el7-10.noarch

至此,此时MySQL的单机安装已经完成。其余节点均可按照此方法安装。

异步复制

原理

不仅是MySQL,几乎所有的主从复制集群,都是master\slave模式,也就是slave节点从master节点上同步数据。MySQL主从复制的整个过程如下图所示
MySQL主从复制
整个过程可以分为三个步骤

  • master节点把对数据的修改记录到bin log中,所以master节点必须开启bin log
  • slave节点会从指定的位置(logfile和偏移量pos)开始读取masterbin log,把读取到的日志写入自己的relay log
  • slave节点根据relay log中的日志进行重放(replay),slave节点可以配置是否需要写入自己的bin log

了解了MySQL主从复制的基本原理,再来进行主从复制的搭建,就会容易理解很多。

异步复制缺点

为了了解异步复制的缺点,先看如下图
MySQL异步复制过程
如图所示,描述了一主两从的异步复制集群,相信大家也很容易看出缺点。假设master节点commit之后就宕机了,而此时slave节点可能还没有读到master的全部bin log,就会导致数据丢失

异步复制不仅不能保证masterslave之间的数据一致性,甚至不能保证slaveslave之间的数据一致性。

半同步复制

MySQL5.6对异步复制做了改进,引入半同步复制

半同步复制过程如下
半同步复制
半同步复制在MySQL5.6中被引入,相比于异步复制,主要的改进就是在master写完bin log之后不会直接commit,而是收到slave节点的ACK之后才会commit,期间mastercommit操作被阻塞。当然,为了防止部分slave节点故障导致master迟迟收到不ACKmastercommit操作可以设置超时时间,超时之后,半同步复制降级为异步复制

有经验的同学应该可以看出来,这其实就是两阶段提交master节点commit的时候,slave已经读取了master的完整bin log。即使此时master宕机,slave节点也能通过重放,实现和master节点的数据同步。

基于GTID复制

前文说讲的主从复制集群是依靠logfile + pos的方式实现,除了这种方式外,还有一种就是基于GTID的主从复制。GTID (Global Transaction ID)是全局事务ID

GTID的结构如下:source_id:transaction_id,组成分成两个部分source_idtransaction_id,分别代表执行事务的主机UUID,和事务ID。事务ID是递增的,保证不重复。

  • master节点修改数据时,把GTID写入bin log
  • slave读取master节点的bin log,写入到自己的relay log
  • slave节点的sql_threadrelay log获取GTID,查找自己的bin log中是否有对应的记录
  • 如果有,说明该GTID的事务已经在slave上执行,slave会忽略该事务
  • 如果没有,slave就会从relay log中执行该事务,并记录到bin log

整个过程与logfile + pos方式几乎一致,只是获取执行偏移的方式不同。并且slave节点必须开启bin log

基于GTID的复制和基于日志点的复制有什么区别?

  • 基于日志点的复制是MySQL实现的第一种复制方式,几乎所有的MySQL分支版本都支持
  • 基于日志点的复制,slave请求master的增量日志依赖于日志偏移量
  • 基于日志点的复制配置复制链路时,需要指定master_log_filemaster_log_pos参数,一旦master宕机,很难从新的master中找到正确的偏移量的值
基于日志点的复制 基于GTID的复制
兼容性好 老版本MySQLMariaDB不兼容
支持MMMMHA架构 仅支持MHA架构
主从切换后很难找到新的同步点 基于事务ID的复制,可以很方便的找到未完成的同步的事务ID
可以方便的跳过复制错误 只能置入空事务的方式跳过复制

优先选择基于GTID的复制,不能选择GTID的复制方式时,再使用基于日志点的复制。

实践

异步复制

  • 开启bin log,使用如下命令查看bin log是否开启

    show variables like '%log_bin%';
    +---------------------------------+-------+
    | Variable_name                   | Value |
    +---------------------------------+-------+
    | log_bin                         | OFF   |
    | log_bin_basename                |       |
    | log_bin_index                   |       |
    | log_bin_trust_function_creators | OFF   |
    | log_bin_use_v1_row_events       | OFF   |
    | sql_log_bin                     | ON    |
    +---------------------------------+-------+
    6 rows in set (0.00 sec)
    

    log_binOFF表示未开启,可以使用如下方式开启bin log

    vim /etc/my.cnf
    

    配置如下内容

    ## 开启bin log
    log-bin=/var/lib/mysql/mysql-bin
    
    ## 服务节点ID,每个节点不一样
    server-id=101
    
    ## 开启GTID复制模式(如果只想用基于日志点复制,不需要配置这里)
    gtid-mode=on
    enforce-gtid-consistency=1
    

    重启MySQL之后,再次查看bin log开启状态,可以看到bin log已经开启

    show variables like '%log_bin%';
    +---------------------------------+--------------------------------+
    | Variable_name                   | Value                          |
    +---------------------------------+--------------------------------+
    | log_bin                         | ON                             |
    | log_bin_basename                | /var/lib/mysql/mysql-bin       |
    | log_bin_index                   | /var/lib/mysql/mysql-bin.index |
    | log_bin_trust_function_creators | OFF                            |
    | log_bin_use_v1_row_events       | OFF                            |
    | sql_log_bin                     | ON                             |
    +---------------------------------+--------------------------------+
    6 rows in set (0.00 sec)
    

    slave节点均按照此方式配置

  • master创建复制账号并授权
    需要自己指定密码

    create user repl@'192.168.1.%' identified by 'your password';
    grant replication slave on *.* to repl@'192.168.1.%';
    
  • 备份master数据

    mysqldump --single-transaction -uroot -p --routines --triggers --events --master-data=2 --all-databases > sicimike.sql
    

    可以查看备份的文件中,有GTIDlogfile:pos相关的信息
    mysql主从复制
    将备份的文件导入到slave节点的数据库。

  • slave节点上配置复制链路

    ## MASTER_LOG_FILE和MASTER_LOG_POS的值在前一步中可以找到
    change master to master_host='192.168.1.101', MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=2615;
    

    执行成功后,可以查看slave节点的状态

    show slave status\G;
    *************************** 1. row ***************************
                   Slave_IO_State:
                      Master_Host: 192.168.1.101
                      Master_User:
                      Master_Port: 3306
                    Connect_Retry: 60
                  Master_Log_File: mysql-bin.000002
              Read_Master_Log_Pos: 2615
                   Relay_Log_File: localhost-relay-bin.000001
                    Relay_Log_Pos: 4
            Relay_Master_Log_File: mysql-bin.000002
                 Slave_IO_Running: No
                Slave_SQL_Running: No
    			......
    
  • 启动复制链路

    ## 用户名和密码就是在master上配置的用户名和密码
    start slave user='repl' password= 'your password';
    

    再次查看slave节点的状态

    show slave status\G;
    *************************** 1. row ***************************
                   Slave_IO_State: Waiting for master to send event
                      Master_Host: 192.168.1.101
                      Master_User: repl
                      Master_Port: 3306
                    Connect_Retry: 60
                  Master_Log_File: mysql-bin.000002
              Read_Master_Log_Pos: 2615
                   Relay_Log_File: localhost-relay-bin.000002
                    Relay_Log_Pos: 320
            Relay_Master_Log_File: mysql-bin.000002
                 Slave_IO_Running: Yes
                Slave_SQL_Running: Yes
    			......
    

    可以看到Slave_IO_RunningSlave_SQL_Running都变成了Yes状态,这两个线程就是前文主从复制原理图io_threadsql_thread

    其余的节点也是以同样的方式配置成slave节点。

至此,基于logfile:pos模式的异步复制已经配置完成。在master节点上进行数据的修改,马上就会同步到slave库

可以在master节点上执行show slave hosts查看追随自己的所有slave节点

show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID                           |
+-----------+------+------+-----------+--------------------------------------+
|       103 |      | 3306 |       101 | d6532e2a-a592-11ea-99c3-000c297f5b55 |
|       102 |      | 3306 |       101 | 1dbd5375-a4d9-11ea-9eef-000c29cf4cca |
+-----------+------+------+-----------+--------------------------------------+
2 rows in set (0.00 sec)

接下来开始配置半同步复制

半同步复制

  • 首先查看master是否安装了半同步复制插件rpl_semi_sync_master,可以使用如下命令查看
    show plugins;
    
    如果没有安装的话,使用如下命令安装
    install plugin rpl_semi_sync_master soname 'semisync_master.so';
    
  • 配置master相关变量
    首先查看半同步复制相关的变量
    show variables like 'rpl%';
    +-------------------------------------------+------------+
    | 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_for_slave_count | 1          |
    | rpl_semi_sync_master_wait_no_slave        | ON         |
    | rpl_semi_sync_master_wait_point           | AFTER_SYNC |
    | rpl_stop_slave_timeout                    | 31536000   |
    +-------------------------------------------+------------+
    7 rows in set (0.01 sec)
    
    rpl_semi_sync_master_enabled变量需要改成ON
    rpl_semi_sync_master_timeout表示半同步复制的超时时间,可以适当修改
    依然是修改/etc/my.cof文件,配置如下内容
    rpl_semi_sync_master_enabled=on
    rpl_semi_sync_master_timeout=500
    
    配置完成后重启MySQL即可
  • 查看slave是否安装了半同步复制插件rpl_semi_sync_slave可以使用如下命令
    show plugins;
    
    如果没有安装的话,使用如下命令安装
    install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
    
  • 配置slave相关变量
    首先查看半同步复制相关的变量
    show variables like 'rpl%';
    +---------------------------------+----------+
    | Variable_name                   | Value    |
    +---------------------------------+----------+
    | rpl_semi_sync_slave_enabled     | OFF      |
    | rpl_semi_sync_slave_trace_level | 32       |
    | rpl_stop_slave_timeout          | 31536000 |
    +---------------------------------+----------+
    3 rows in set (0.01 sec)
    
    rpl_semi_sync_slave_enabled变量需要改成ON,需要修改/etc/my.cof文件,配置如下内容
    rpl_semi_sync_slave_enabled=on
    
    slave完成配置,重启MySQL后,再次查看slave的状态
    show slave status\G;
    *************************** 1. row ***************************
                   Slave_IO_State:
                      Master_Host: 192.168.1.101
                      Master_User:
                      Master_Port: 3306
                    Connect_Retry: 60
                  Master_Log_File: mysql-bin.000003
              Read_Master_Log_Pos: 194
                   Relay_Log_File: localhost-relay-bin.000005
                    Relay_Log_Pos: 4
            Relay_Master_Log_File: mysql-bin.000003
                 Slave_IO_Running: No
                Slave_SQL_Running: Yes
    			.....
    
    可以看到,Slave_SQL_Running依然是Yes,只有Slave_IO_RunningNO,所以只需要重启slave的IO线程即可
    start slave io_thread user='repl' password = 'your password';
    
    启动完成后,基于logfile:pos模式的半同步复制也就配置完成。

GTID复制

由于上面的实验,我们已经启动了logfile + pos方式的复制链路,所以要改成GTID方式,先要停止slave,再重新配置复制链路

  • 停止slave
    slave节点上执行如下命令
    stop slave;
    
  • 配置复制链路
    change master to master_host='192.168.1.101', master_user='repl', master_password='your password', master_auto_position=1;
    
  • 启动复制链路
    start slave;
    

查看链路状态

show slave status \G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.1.101
                  Master_User: repl
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000003
          Read_Master_Log_Pos: 811
               Relay_Log_File: localhost-relay-bin.000002
                Relay_Log_Pos: 414
        Relay_Master_Log_File: mysql-bin.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              ......
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set:
            Executed_Gtid_Set: 1dbd5375-a4d9-11ea-9eef-000c29cf4cca:1,
81502f9e-a592-11ea-b912-000c2928707c:1-11
                Auto_Position: 1
              ......

可以看到Auto_Position变成了1,说明启动了基于GTID方式的复制。

主从复制延迟

主从复制是一种异步复制模型,延迟自然是不可避免。只要延迟在业务能够接受的范围之内,都是可以容忍的。但是有时候主从复制的延迟会很大,可以总结为以下原因

  • master上执行了大事务,大事务是指耗时很长的事务。改进办法是把大事务转换成多个小事务
  • masterslave之间网络波动
  • 单个master节点下挂载的slave节点过多,可能会把master网卡带宽打满。改进办法就是减少单个master挂载slave的数量
  • master节点会有多个线程同时写入,而slave节点进行replaysql_thread只有一个。改进办法就是使用MySQL 5.7的多线程复制的方式、或者使用MGR复制架构。

总结

本篇主要从理论到实践,完整的讲解了MySQL的几种主从模型。根据复制点的选取方式,可以分成基于日志点的方式和基于GTID的方式。根据master节点事务的提交方式可以分成异步复制半同步复制

至于文中提到的MMMMHA架构,留待下一篇再详细讲解。

参考

  • https://www.cnblogs.com/bigbrotherer/p/7241845.html
  • https://blog.51cto.com/13434336/2178937
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章