背景

本文整理了 MySQLReplication 集群部署操作(一主多从 + 多主多从)

可对比 PXC 集群部署,以提高 MySQL 集群配置能力 —— 【CentOS7 下 PXC 集群部署操作指导】

  • 在此整理一番 MySQL 主从配置的操作
    感觉每次配置总是参考别人的,有时对问题的描述不够详细,
    还是,把自己的操作过程记录下来比较好
    也方便后期的补充扩展, 同时也欢迎道友们参考、指摘 …
  • 准备工作:
    确保主库的 mysql 能够给 外网访问,也就是使用 Navicat 等软件能够连接的上才行(使用宝塔要到端口那里 放行 3306 端口

主从数据库版本 【最好一致】,或者【从库】版本略大于【主库】

  • 操作环境参考
我使用 VMware 创建了两台虚拟机,作为主从分离的宿主
	  主库IP:	192.168.80.221
	  从库IP:	192.168.80.222
 
  linux 系统:	centos7.9
  数据库版本:	mySQL 5.7.32
  • 主从分离原理

    【总结】
> 	主服务器把操作记录到 binary log 
> 	从服务器 执行 "I/O线程",将 binary log 中的数据同步到 relay log(中继日志中)
>	从服务器 执行 "SQL线程",读取 relay log ,进行数据同步操作

对于原理的解释,可参考 —— 【Mysql 主从同步的原理】


主从分离配置步骤

一、【Master主库】配置操作 [192.168.80.221]

①. 编辑【主库】配置文件

  • 找到 my.cnf 文件,比如使用宝塔安装,一般会在目录 "/etc/my.conf"
vi /etc/my.cnf
  • 启用二进制日志文件
    补充或更新如下三个主要配置项
[mysqld]
server-id = 1 #设置 server-id
log-bin=master-bin  #开启二进制日志
log-bin-index=master-bin.index #打开二进制日志文件索引

centos无法复制指令_centos无法复制指令


【注意】:

  • 当前的操作,一般都是认为在 主从数据要全部一致的情况下操作!
    不过,一般实际业务中,可能会涉及到 【指定同步的数据库】,可以考虑配置参数 :"eplicate-wild-do-table" 此处不做赘述,百度好多,也可参考后面步骤: 【三、进行主从数据同步配置-指定同步数据库的一点建议】

②. 重启 mysql 加载配置文件

  • 执行命令:service mysqld restart
  • centos无法复制指令_centos无法复制指令_02


  • 重启后,可以在 mysql 的安装目录下看到:
    生成了以在配置文件中定义 "log_bin=master-bin" 为开头的文件
  • 连接 mysql (当然,也可是使用 Navicat for MySQL 等数据库连接工具)
mysql -uroot -p password

centos无法复制指令_数据_03

③. 查看日志信息

如果前面配置没问题,这一步其实也可以跳过,只是为了确认信息

  • 查看二进制日志是否开启 : show global variables like '%log%';
  • centos无法复制指令_mysql_04


  • 查看主节点二进制日志列表: SHOW MASTER LOGS;
  • centos无法复制指令_数据_05


  • 查看主节点的 server id : SHOW GLOBAL VARIABLES LIKE '%server%';
  • centos无法复制指令_centos无法复制指令_06


④. 在主节点上创建有复制权限的用户

  • 注意参考截图中注释信息 ,可自定义,如 (用户名:repl_moTzxx,密码:201107070
    GRANT REPLICATION SLAVE ON *.* TO 'repl_moTzxx'@'192.168.80.222' IDENTIFIED BY '201107070';
  • centos无法复制指令_主从分离_07


⑤. 刷新权限

  • flush privileges;
  • centos无法复制指令_centos无法复制指令_08

  • 此时,如果条件允许
    为了同步前数据一致,建议锁定一下表 : flush tables with read lock;
  • 然后,查看 【Master(主库)】 状态:SHOW MASTER STATUS; 记录二进制文件名 (masterl-bin.000001) 和位置 (601)
    (如果有多个二进制文件名,取最后一个的名称和位置!!)
  • centos无法复制指令_mysql_09

  • 至此,主服务器配置完成!

二、【Slave从库】配置操作 [192.168.80.222]

①. 编辑从节点配置文件

  • 同前面【主库】操作: vim /etc/my.cnf
  • 开启中继日志 relay-log
[mysqld]
server-id=2 #配置 server id
relay-log=slave-relay-log #打开从服务器中继日志文件
relay-log-index=slave-relay-log.index  #打开从服务器中继日志文件索引

centos无法复制指令_centos无法复制指令_10

②. 修改完配置文件后,启动或者重启 mysqld 服务

  • 执行命令:"service mysqld restart"
  • centos无法复制指令_centos无法复制指令_11


③. 打开 mysql 会话,执行同步 SQL 语句

  • 首先, 保险起见要再次到【主库】 ,
    查看主节点二进制日志列表:"SHOW MASTER STATUS;"
  • centos无法复制指令_centos无法复制指令_12

  • 然后,在【从库】
    打开 mysql : mysql -uroot -p,执行 同步 SQL 语句

注意: 需要主服务器主机名,登陆凭据,二进制文件(最后一个)的名称和位置

  • SQL语句:CHANGE MASTER TO MASTER_HOST='192.168.80.221', MASTER_USER='repl_moTzxx', MASTER_PASSWORD='201107070', MASTER_LOG_FILE='master-bin.000008', MASTER_LOG_POS=333;

④. 启动 【Slave(从库)】 同步进程 :

  • start slave;
  • centos无法复制指令_mysql_13


⑤. 查看 slave 状态

  • show slave status\G;
  • centos无法复制指令_数据库_14

  • 【提示】:
  • 如果,出现问题,那就先停止 【Slave】, 阅读日志,解决后再开启【Slave】
    停止语句:STOP SLAVE; 开启语句:START SLAVE; 查看语句:SHOW SLAVE STATUS;
  • 再次开启 Slave 时,如果指定的 Master 没变,可以只运行如下语句:
    CHANGE MASTER TO MASTER_LOG_FILE='master-bin.000002', MASTER_LOG_POS=154;
  • centos无法复制指令_mysql_15

至此,主从同步配置完成

【拓展】:

如果,当前想停止 主从配置,那就在 【从库】中执行 sql 语句:"STOP SLAVE;"


三、进行主从数据同步配置

现在,要进行最重要的数据同步配置了,一切的目的都是为了 数据同步

█▶ 根据实际业务情况,进行配置

【注】: 在此需要分情况操作:

1.	 如果此时,【主库】中没有需要同步的数据库 db 时
	 根据默认配置信息,基本是满足后续操作的;
	 当在【主库】上创建新的 数据库 db、数据表 table 时,【从库】也会同步创建

2.  如果此时已进行了部分业务,那么【主库】中,是有需要操作的数据库 db 的
	此时,要求 【从库】要把 【主库】中的 db 复制过来
	方便的话也可以使用 Navicat 等客户端操作
  • 以鄙人的操作为例,
    当下我需要对 【主库】中的一个数据库 [tp5_pro]做实际的业务处理
    所以,需要等待我在【从库】中创建数据库[tp5_pro],并导入其中的数据后 …

【注意!注意!】:

如果前面对 【主库】做了锁表操作,此时需要: 对 Master 解除 table(表)的锁定"unlock tables;"

centos无法复制指令_数据_16

  • 这时,在【主库】中,对数据库 [tp5_pro] 中的数据变动后,到【从库】就会发现,数据已同步操作!

█▶ 指定同步数据库的一点小建议

本人建议,指定所要同步数据库 【只需要在主或者从,其中一个配置就可以了】

  • 所以,如果要指定数据库,建议在 【主库】中进行配置
# 不同步哪些数据库  
binlog-ignore-db = mysql
binlog-ignore-db = test
binlog-ignore-db = sys
binlog-ignore-db = information_schema
binlog-ignore-db = performance_schema

# 只同步哪些数据库,除此之外,其他不同步  (注意跟上面的配置只使用一种方式即可)
# binlog-do-db = tp5_pro

☞. 【一主多从】 模式 配置

以上内容中,只是介绍了 【一主一从】,最基础的配置指导

而在实际业务处理中,如果想继续配置多台从库,根据上面的操作,进行扩展就好

【重点】 :

  • 主节点上创建具有复制权限的用户
  • 从节点注意对应配置项的改动
  • 从节点执行同步 SQL 语句
  • 注意对【主库】的锁表、解锁操作 ...
  • 配置完成后,正确的参考结果是:更改【主库】中的数据,所有【从库】都会变动!

不过,一主多从基本不受青睐的,毕竟一旦主机挂掉,直接无法写入数据了!建议至少也要配置个 【两主两从】 …


☞. 【多主多从】 模式 配置

既然已经忙活到了这一步,在此再补充一下 —— 【多主多从】模式的配置吧

♦ 需求分析

  • 相对而言,【多主多从】模式是更为合理的 高可用分布式设计模式 毕竟在【一主多从】中,我们的从数据库在数据安全性上并没有发挥到最好,只是为了提供读写分离和查询负载均衡。
    当主数据库服务器挂掉了,那么就无法进行写入数据,整个数据库就无法正常工作了
    所以,这时就需要【多主多从】的出场了

此处,以最简单的 【两主两从】配置操作为例

♦ 角色分配

在此,我以四台 CentOS7 虚拟机作为 MySQL 数据库的宿主机

|主机名 | ip 地址 |角色|
|–|–|–|–|
| Master1|192.168.80.221 |主库 M1,和 M2 互为主备
| Slave1|192.168.80.222 |从库 S1,是 M1 的从库
| Master2|192.168.80.223 |主库 M2,和 M1 互为主备
| Slave2|192.168.80.224 |从库 S2,是 M2 的从库

  • 关系图设计如下:
- 这种双主双从的模型,
- 只要我们对 M1 或者 M2 任意一个主数据库插入数据,其他3个数据库也会作相应的改动。
- 因为 M1 和 M2 是互为主从数据库,所以两个数据库是互相同步的,
- 另外两个数据库是他们的从数据库,写入操作也会更新从数据库。
- 当 M1 挂掉了,可以启动 M2 作为该数据库的主数据库,保证网站的正确运行。
- 同时在正常情况下,M2、S1、S2 都参与查询的负载均衡 ...

此处只介绍 同步配置,对于读写分离的高可用集群部署,请参考 —— 【CentOS7 下实现 MyCat 部署读写分离】

♦ Master/Slave 配置信息

  • 如果是 Master 数据库,注意添加如下两条信息
auto_increment_increment=2 #每次自增2个
auto_increment_offset=1 
#起始值为1  如果是Master1,则为1;如果是Master2,则起始值变为2
#这样两个mysql同样是递增2则id不会冲突

【说明】

  • 1). 有没有 "log-bin=mysql-bin" 是服务器作为 Master 还是 Slave 的关键内容
  • 2). "server-id" 是每个 mysql 的唯一 id,四个不同服务器的需要配置成不同的数字
  • 3). "auto_increment_offset=1" #起始值为1 如果是另外一个 master 则起始值变为2,这样两个 mysql 同样是递增 2 ,则 id 不会冲突
  • 如果是 Slave 数据库,则配置文件注意 "server-id" 必须唯一、尽量关闭"log_bin" 参数

按照文章前面介绍的 【主从分离配置步骤】,分别将 M1->S1 ,M2->S2 配置为主从关系

♦ M1/M2 互为主备,配置操作

到达这一步,M1->S1 ,M2->S2 已配置为主从关系,但是 M1 和 M2 之间还是没有关系的

  • 首先,在 M1和 M2 的数据库配置文件 "my.cnf"中,添加参数:log-slave-updates
#在作为从数据库的时候,有写入操作也要更新二进制日志文件
log-slave-updates

对于参数"log-slave-updates"的解释,请阅读 —— 【MySQL 配置参数 -- logs-slave-updates】

  • 重启 M1、M2 的 mysql 服务,使得配置文件生效:service mysqld restart

此处展示一下,我对各个数据库的配置参数:

centos无法复制指令_mysql_17

▶ 进行 M1 为主,M2 和 S1 为从的配置操作

按照前面的步骤,进行一下 以 M1为主,M2 为从的主从配置操作

  • 首先,是在 M1 中的执行语句操作如下:
mysql> show master status;
+-------------------+----------+--------------+------------------------------------------------------+-------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB                                     | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------------------------------------------+-------------------+
| master-bin.000003 |      154 |              | mysql,test,sys,information_schema,performance_schema |                   |
+-------------------+----------+--------------+------------------------------------------------------+-------------------+
1 row in set (0.00 sec)

mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl_moTzxx'@'192.168.80.223' IDENTIFIED BY '201107070';
Query OK, 0 rows affected, 1 warning (0.01 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

mysql> flush tables with read lock;
Query OK, 0 rows affected (0.00 sec)
  • 然后,在 M2 中的操作,执行语句如下:
mysql> CHANGE MASTER TO MASTER_HOST='192.168.80.221', MASTER_USER='repl_moTzxx', MASTER_PASSWORD='201107070', MASTER_LOG_FILE='master-bin.000003', MASTER_LOG_POS=154;
Query OK, 0 rows affected, 2 warnings (0.01 sec)

mysql> start slave;
Query OK, 0 rows affected (0.00 sec)

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.80.221
                  Master_User: repl_moTzxx
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000003
          Read_Master_Log_Pos: 611
               Relay_Log_File: localhost-relay-bin.000002
                Relay_Log_Pos: 778
        Relay_Master_Log_File: master-bin.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:

注意,此时我并没有对已配好的 Slave1 进行变动,正常情况下,查看信息依然是同步 Master1 的状态!

▶ 进行 M2 为主,M1和S2 为从的配置操作

  • 首先,是在 M2 中的执行语句操作如下:
mysql> show master status;
+-------------------+----------+--------------+------------------------------------------------------+-------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB                                     | Executed_Gtid_Set |
+-------------------+----------+--------------+------------------------------------------------------+-------------------+
| master-bin.000003 |      611 |              | mysql,test,sys,information_schema,performance_schema |                   |
+-------------------+----------+--------------+------------------------------------------------------+-------------------+
1 row in set (0.00 sec)

mysql>  GRANT REPLICATION SLAVE ON *.* TO 'repl_moTzxx'@'192.168.80.221' IDENTIFIED BY '201107070';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)
  • 然后,在 M1 中的操作,执行语句如下:
mysql> CHANGE MASTER TO MASTER_HOST='192.168.80.223', MASTER_USER='repl_moTzxx', MASTER_PASSWORD='201107070', MASTER_LOG_FILE='master-bin.000003', MASTER_LOG_POS=611;
Query OK, 0 rows affected, 2 warnings (0.01 sec)

mysql> start slave;
Query OK, 0 rows affected (0.01 sec)

mysql> show slave status\G;
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.80.223
                  Master_User: repl_moTzxx
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: master-bin.000003
          Read_Master_Log_Pos: 1068
               Relay_Log_File: localhost-relay-bin.000002
                Relay_Log_Pos: 321
        Relay_Master_Log_File: master-bin.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:

注意,此时我并没有对已配好的 Slave2 变动,正常情况下,查看信息依然是同步 Master2 的状态!


♦ 测试配置成果

测试之前,我建议确认下 M1、S1、M2、S2 的 slave 状态是否都为 Yes,否则,需要回溯问题所在,正确配置!

mysql> show slave status\G;
*************************** 1. row ***************************
...
Slave_IO_Running: Yes
Slave_SQL_Running: Yes

分析可知,此时对 M1 和 M2 中任意一个的数据进行了操作变化,其他三个的数据应该都会同步!

在进行数据库同步操作时,如果前面对【主库】做了锁定,记得要将【主库】解锁!"unlock tables;"

  • 此时
    方便起见,直接使用 Navicat for MySQL 工具,进行连接操作即可
    M1,进行插入、更新数据后,会发现:M2、S1、S2 都会同步变化
  • centos无法复制指令_数据_18

  • 当然, 对 M2,进行插入、更新数据后会发现:M1、S1、S2 都会同步变化
  • 只有对 S1S2 进行数据操作时,
    会发现,其他主库不会同步
    毕竟它们只是作为 从库的存在!

【提示1】:在真实的项目中,不应该对从数据库(slave)做写入操作,这样会破坏数据的一致性!(测试而已)

【拓展】:

  • 最近,涉猎知识中,根据有经验的道友提醒,
    可以通过 mycat 来实现读写分离
    "mycat 连接多个数据库,数据源只需要连接 mycat" 毕竟,对于开发人员而言:
    不需要根据不同业务来选择不同的库(不便于动态变化)
    此处,提供一下我在 mycat中的配置演示
  • centos无法复制指令_数据_19


  • 配置后的效果便是:
    如果是读操作,会从 M2/S1/S2 中读取
    如果是写操作,会写入 M1,当 M1宕机时,会转到 M2 中进行写操作

【提示2】: 有此需求的建议移步姊妹篇 —— 【CentOS7 下使用 MyCat 实现 MySQL 读写分离/主从切换】

综上,即为 最简单的 【双主双从】配置步骤,进行扩展配置即可形成【多主多从】 …


☺•☹ MySQL 主从分离实际应用

首先声明下,毕竟鄙人只是一个 PHPer,不可能有DBA那样充足的见识!吼吼吼 ~~~

▶. ThinkPHP5.1 中的分布式配置

  • 因为我常用的开发框架为 ThinkPHP5.1,那么一般需要的配置信息可参考如下:
//------------- 主从分离配置参考----------------------------------
    'hostname'        => '192.168.80.221,192.168.80.222',
    'database'        => 'tp5_pro',
    'username'        => 'root',
    'password'        => ['MT123456','TM123456'],
    'prefix'          => 'tp5_',//前缀而已,不要太在意
    'hostport'        => '',
    'deploy'          => 1,
    'rw_separate'     => true,
//-------------------------------------------------------------

▶. 数据库多节点集群部署

毕竟,“Replication 主从分离” 的集群思维,难以绕过 "【数据同步延迟】"

  • 对于重要数据,比如订单、购物券、支付信息这里数据
    此时,建议考虑使用 PXC 集群部署 正在摸索中 …

附录

①. 操作建议

在进行数据库同步操作时,尽量先将【主库】锁定,配置【从库】完毕,记得再将【主库】解锁!

②. MySQL 用户操作指令

  • 查看 MySQL 数据库中所有用户
    SELECT DISTINCT CONCAT('User: ''',user,'''@''',host,''';') AS query FROM mysql.user;
  • 查看数据库中具体某个用户的权限
    show grants for 'repl_moTzxx'@'192.168.80.224'
  • 删除一个用户 drop user 'repl_moTzxx'@'192.168.80.224'

③. Slave_IO_Running: No 的一种情况

一旦出现这种问题,最好要去查看 mysql 日志进行排查

  • 我操作过程中遇到一种情况
    因为,我使用是虚拟机直接克隆而来,
    就会有 "server-uuid" 相同而导致无法操作主从分离配置
    网友有的建议直接更改一下
    但是我测试是不可以的,
    还是直接卸载重装了一下 MySQL ,一路顺利 YES !

④. 有时需要关闭 slave 线程

实际操作过程中,有时会有如下提示信息:

"ERROR 3021 (HY000): This operation cannot be performed with a running slave io thread; run STOP SLAVE IO_THREAD FOR CHANNEL '' first."

  • 这说明当前正在运行着一个 Slave I/O 线程,最直接的办法就是先关闭 :stop slave;

参考文章