前置知识:
[1] CentOS7安装MySQL

主从架构的作用


主从架构是保证 MySQL 高可用的重要手段。主节点会将数据同步到从节点,如果主节点宕机了,切换到从节点继续提供服务。

很多时候,系统的读的业务远远多于写的业务。这时候,可以通过主从架构来实现读写分离,从而提高系统的并发能力

主从复制基本原理


搭建了主从架构后,从库上有一个 IO 线程,这个线程负责和主库建立一个 TCP 连接,然后请求主库传输 binlog 日志给从库,这时候主库上有一个 IO dump 线程,负责通过这个 TCP 连接把 binlog 日志传输给从库的 IO 线程。

接着从库的 IO 线程就会将获取到的 biglog 日志数据写入到本地的 relay 日志文件中去,然后从库上另外有一个 SQL 线程会读取 relay 日志里的内容,进行日志重做,把所有在主库执行过的增删改操作在从库上做一遍,进行数据还原。

主从复制的搭建


主从架构大致可以分为 3 种架构,一主多从,链式主从,多主多从。当前搭建的是一主多从架构,而且是异步复制。

1. 配置 server-id,server-uuid 和 开启 bin log

首先要保证主库和从库的 server-id,server-uuid 是不一样的,并且主库打开了 binlog功能。
查看 server-id,server-uuid 和 查看 bin log 是否开启的 SQL 如下:

  1. show variables like '%server_id%'; # 查看server-id
  2. show variables like '%server_uuid%'; # 查看server-uuid
  3. SHOW VARIABLES LIKE 'log_bin'; # 查看bin log 开关,off 表示关闭

修改 server-id 需要在配置文件里面进行修改,找到配置文件 my.cnf 。一般默认在 /etc/ 目录下。
找不到的话可以执行这个命令来找,可以得到 mysql 的配置文件的默认加载顺序:

mysql --help | grep 'Default options' -A 1

输出如下:


[root@localhost ~]# mysql --help | grep 'Default options' -A 1
Default options are read from the following files in the given order:
/etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf 
[root@localhost ~]#

在 [mysqld] 下加上如下配置:

[mysqld]
server-id=2003306  #配置 server-id 
log-bin=mysql-bin  # 开启 bin log

关于 server-id 的配置可以根据自身的情况来定,我这里使用的是 ip 的最后 3 位 + 端口号。
这个配置就是最简单的配置好 server-id 和开启 bin log 。但是,bin log 的开启,一般需要增加多几个配置才比较完善,完整配置如下:

[mysqld]
server-id=2003306  #配置 server-id 
log-bin=mysql-bin  # 开启 bin log 
binlog_format = mixed   #日志的格式
expire_logs_days = 7    #过期时间

日志的格式, mixed 是性能比较好,又不容易出错的选择。具体的日志格式的选择,可以看 参考[1]。

修改 server-uuid 是需要修改数据目录下的 auto.cnf 文件。这个文件在数据目录下,数据目录可以使用这条 SQL 查询出来:show variables like ‘%datadir%’; 。
我的数据目录是 /var/lib/mysql/。所以编辑命令如下: vim /var/lib/mysql/aotu.cnf 。这个文件只有 1 行,就是 server-uuid ,只需要保证主从的 server-uuid 不一致就可以了。

[auto]
server-uuid=fd01bfe8-6329-11ec-b97c-000c2959e7a8

这里我的主库的 server-uuid 是 fd01bfe8-6329-11ec-b97c-000c2959e7a8 , 从库的 server-uuid 是 fd01bfe8-6329-11ec-b97c-000c2959e7a9。

如果没有保证 server-uuid 不一致的话,从库开启 slave 模式后,然后 show slave status ; 就会看到有报错在 Last_IO_Error 字段上。

2.在主库上创建一个用于主从复制的账号

执行下面 SQL 进行创建账号,分配权限和刷新权限。注意:这些 SQL 需要在 MySQL 服务器上执行,不推荐在 Navicat 等 SQL 工具上执行,可能会出错或者有权限问题。

CREATE USER 'backup_user'@'192.168.0.%' IDENTIFIED BY 'backup_123';
GRANT replication SLAVE on *.* to 'backup_user'@'192.168.0.%' ;
FLUSH privileges;

3. 在从库上开启从库模式

在从库上执行以下 SQL ,就开启从库模式了。

-- 指定主库地址和账号密码
CHANGE MASTER TO MASTER_HOST = '192.168.0.200',
MASTER_USER = 'backup_user',MASTER_PASSWORD='backup_123';

-- 开启从库模式
START SLAVE;

-- 停止从库模式
STOP SLAVE;

-- 查看主从复制状态
SHOW SLAVE STATUS;

查看主从注释状态,主要看的是 Slave_IO_Running 和 Slave_SQL_Running ,如果都是 Yes 证明启动成功。如果不是的话,可以查看 Last_Error 列,有对应的错误说明,再根据对应的错误说明去调整。

注意:以上主从同步的过程,适合什么都没有的数据库进行主从同步;或者是可以进行停机,然后将主库的数据导到从库上去,然后开启主从同步后,再开启主库。

一般来说,数据库是不能停机的,这个问题怎么处理呢? 但是数据库一般都是有备份的,如果备份是 dump 出来的,那么可以在 dump 命令里面加上 — master-data=2 参数,输出当前备份的 bin log 文件和位置。

mysqldump  -p'password'  -uroot -h192.168.0.200 
--skip-extended-insert --master-data=2 thirty_sec |gzip >
/home/back.sql.gz

打开 SQL 文件后,就可以看到类似 ‘ CHANGE MASTER TO MASTER_LOG_FILE=’mysql-bin.001145’, MASTER_LOG_POS=346920; ‘ 的字样了。

然后就可以在从库里面回复数据的时候,加上这两个参数,那么从库回复后,就会从bin log 对应的位置开始进行同步。

CHANGE MASTER TO MASTER_HOST = '192.168.0.200',
MASTER_USER = 'backup_user',MASTER_PASSWORD='backup_123',
MASTER_LOG_FILE='mysql-bin.001145',MASTER_LOG_POS=346920;

至此以上的搭建方式都是数据库的异步复制的方式。如果数据在写入主库后,还没来得及复制到从库就宕机了,这时候进行主备切换,数据就会丢失了。

半同步的方式搭建


同步发方式是指,数据写入到主库后,保证对应的 bing log 同步到从库后,主库的事务才算是提交成功。这样就保证了主从同步的数据不会丢失。

半同步的搭建方式有 2 种。

  1. 采用插件的方式

首先在 master 安装插件,并开启。

INSTALL PLUGIN rpl_semi_sync_master soname 'semisync_master.so'; 
SET global rpl_semi_sync_master_enabled = on;

然后在 slave 安装插件并开启。

INSTALL PLUGIN rpl_semi_sync_slave soname 'semisync_slave.so';
SET global rpl_semi_sync_slave_enabled = on;

可以使用 SHOW PLUGINS; 来查看插件的状态。

最后重启一下从库的 IO 线程就完成了。

STOP slave io_thread;
START slave io_thread;

可以在主库上使用 SHOW GLOBAL STATUS LIKE ‘%semi%’; 查看Rpl_semi_sync_master_status 如果是 ON 就证明已经开启了半复制状态。

  1. MySQL 5.6.5 提供的 GTID 方式

暂时看参考2, 后续补充总结。
有些问题, bin log 一定要开启 row 格式吗?

主从架构同步延迟


进行主从异步复制的时候,会产生一定的延迟。主要是因为主库是多线程写入,从库是单线程拉取 bin log 日志。主库的写入速度就会比从库的写入速度快。

可以使用 precona-toolkit 工具集里面的 pt-heartbeat 工具进行同步延迟的监控。大致原理是在主库上维护一个 heartbeat 表,有一个线程会定时去更新这个表里面的时间戳,从库也会有一个线程来监控和对比,主库的时间戳和从库的时间戳,就可以知道延迟了多久。

可以设置从库也使用多线程来进行同步,减少主从同步的延时。在从库里面设置 slave_parallel_workers > 0 并且将 slave_parellel_type 设置为 LOGICAL_CLOCK 就可以了。

如果需要强制一定要读取到立刻写入的数据的话,只能通过强制读写都从主库进行。

比较建议的方案是,使用半同步的方式来进行同步。可以保证主库宕机主从切换的情况下,数据不会丢失。再打开多线程复制来加快复制的性能。

主从架构同步异常


参考:
[1] MySQL 如何开启 binlog?binlog 三种模式的分析
[2] 基于 Gtid 的 MySQL 主从同步实践
[3] MYSQL 主从同步异常解决方案