背景

现有网上很多教程都是修改了源MySQL镜像,因此会存在安全隐患,也不容易提升版本。此处给出不修改源镜像的主从复制配置方案。

现状

现有一台生产上运行的MySQL5.7服务器,由docker镜像提供支持

原docker-compose文件

version: '3.7'
services:

  mysql57:
    image: mysql:5.7
    restart: always
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    ports:
      - 3306:3306
    networks:
      - prod
    volumes:
      - ./mysql57/data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: root
networks:
  prod:

改造过程

配置主服务器

新增同步用户并授权

##创建slave1用户
CREATE USER 'slave1'@'%' IDENTIFIED BY 'slavepass';

##为slave1赋予REPLICATION SLAVE权限。
GRANT REPLICATION SLAVE ON *.* TO 'slave1'@'%';

开启binlog日志

由于原主服务器没有开启binlog日志,故需要挂载配置文件并开启binlog日志

新增配置文件custom-master.cnf

[mysqld]
log-bin         = mysql-bin
log-bin-index   = mysql-bin.index
binlog_format   = mixed
server-id       = 1
sync-binlog     = 1
character-set-server = utf8

修改docker-compose文件为

version: '3.7'
services:

  mysql57:
    image: mysql:5.7.29
    restart: always
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    ports:
      - 3306:3306
    networks:
      - prod
    volumes:
      - ./mysql57/data:/var/lib/mysql
      - ./mysql57/custom-master.cnf:/etc/mysql/conf.d/custom.cnf
      - ./mysql57/log:/var/log/mysql
    environment:
      MYSQL_ROOT_PASSWORD: root
networks:
  prod:

更新服务(会短暂停机)

$ docker-compose up -d

配置内容解释

log-bin:设置二进制日志文件的基本名;
log-bin-index:设置二进制日志索引文件名;
binlog_format:控制二进制日志格式,进而控制了复制类型,三个可选值
    -STATEMENT:语句复制
    -ROW:行复制
    -MIXED:混和复制,默认选项
server-id:服务器设置唯一ID,默认为1,推荐取IP最后部分;
sync-binlog:默认为0,为保证不会丢失数据,需设置为1,用于强制每次提交事务时,同步二进制日志到磁盘上。

备份主数据库数据

该步骤可以等到两台从服务器的docker环境都配置完毕后操作,以减少停机时间

  1. 获取一个一致性的快照,需对所有表设置读锁:
flush tables with read lock;
  1. 获取二进制日志的坐标:
show master status;
FilePositionBinlog_Do_DBBinlog_Ignore_DBExecuted_Gtid_Set
mysql-bin.0000036165
  1. 备份数据
# 针对事务性引擎
mysqldump -u root -p --all-databases -e --single-transaction --flush-logs --max_allowed_packet=1048576 --net_buffer_length=16384 > /var/log/mysql/all_db.sql
# 针对 MyISAM 引擎,或多引擎混合的数据库
mysqldump -uroot --all-databases -e -l --flush-logs --max_allowed_packet=1048576 --net_buffer_length=16384 > /var/log/mysql/all_db.sql

由于挂载了日志目录,故在容器外部可以看到该备份的数据文件

配置从服务器

  1. 新增两台CentOS 7服务器,并安装docker和docker-compose服务
  2. 由于主从复制要求所有机器版本号包括小版本号都必须一致,故此处拉取mysql:5.7.29镜像
  3. 从主库拷贝数据文件all_db.sql到两台从库上
$ scp /root/mysql/log/all_db.sql root@192.168.1.33:/root/mysql/log/
  1. 新增配置文件custom-slave1.cnf
[mysqld]
log-bin             = mysql-bin
binlog_format       = mixed
log-slave-updates   = 0
server-id           = 2
relay-log           = mysql-relay-bin
relay-log-index     = mysql-relay-bin.index
read-only           = 1
slave_net_timeout   = 10
  1. 新增docker-compose文件
version: '3'
services:

  mysql57-master:
    image: mysql:5.7.29
    restart: always
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    ports:
      - 3306:3306
    networks:
      - mysql-net
    volumes:
      - ./data:/var/lib/mysql
      - ./custom-slave1.cnf:/etc/mysql/conf.d/custom.cnf
      - ./log:/var/log/mysql
    environment:
      MYSQL_ROOT_PASSWORD: root

networks:
  mysql-net:
  1. 由于也挂载了log目录,启动后容器内就已经有从主库同步过来的数据文件
  2. 数据恢复
mysql -u root -p < /var/log/mysql/all_db.sql
  1. 使用工具连接数据库,配置主从连接
CHANGE MASTER TO
MASTER_HOST='10.168.1.30',
MASTER_USER='slave1',
MASTER_PASSWORD='slavepass',
MASTER_LOG_FILE='mysql-bin.000003',
MASTER_LOG_POS=6165;
  1. 启动slave同步进程
start slave;
  1. 关闭主服务器全局读锁
UNLOCK TABLES;
  1. 查看从服务器同步状态,主要是Slave_IO_Running Slave_SQL_Running状态必须为Yes
Slave_IO_StateMaster_HostMaster_UserMaster_PortConnect_RetryMaster_Log_FileRead_Master_Log_PosRelay_Log_FileRelay_Log_PosRelay_Master_Log_FileSlave_IO_RunningSlave_SQL_RunningReplicate_Do_DBReplicate_Ignore_DBReplicate_Do_TableReplicate_Ignore_TableReplicate_Wild_Do_TableReplicate_Wild_Ignore_TableLast_ErrnoLast_ErrorSkip_CounterExec_Master_Log_PosRelay_Log_SpaceUntil_ConditionUntil_Log_FileUntil_Log_PosMaster_SSL_AllowedMaster_SSL_CA_FileMaster_SSL_CA_PathMaster_SSL_CertMaster_SSL_CipherMaster_SSL_KeySeconds_Behind_MasterMaster_SSL_Verify_Server_CertLast_IO_ErrnoLast_IO_ErrorLast_SQL_ErrnoLast_SQL_ErrorReplicate_Ignore_Server_IdsMaster_Server_IdMaster_UUIDMaster_Info_FileSQL_DelaySQL_Remaining_DelaySlave_SQL_Running_StateMaster_Retry_CountMaster_BindLast_IO_Error_TimestampLast_SQL_Error_TimestampMaster_SSL_CrlMaster_SSL_CrlpathRetrieved_Gtid_SetExecuted_Gtid_SetAuto_PositionReplicate_Rewrite_DBChannel_NameMaster_TLS_Version
Waiting for master to send event192.168.1.30slave1330660mysql-bin.0000033722724mysql-relay-bin.0000023717604mysql-bin.000003YesYes 0 037227243717811None 0No 0No0 0 14c99130f-e664-11e9-987b-0242ac120003/var/lib/mysql/master.info0 Slave has read all relay log; waiting for more updates86400 0

可能出现的问题

死锁——waiting for global read lock

原因在于flush tables with read lock语句和事务执行的过程都涉及到连个锁,而且不是原子的,再加上并行复制以及设置了从库binlog的顺序提交,最终导致多个线程形成死锁

解决方法:

  • 重启主数据库
  • 查看所有连接线程,分析死锁的原因,杀掉执行flush tables with read lock的线程

参考资料:

Last modification:April 17th, 2020 at 03:37 pm
如果觉得我的文章对你有用,请随意赞赏