主从复制的原理
随着业务量越来越大,单机架构无法满足I/O访问需求,为了提升数据库性能,我们会将数据库操作进行读写分离,写操作在主库(Master)完成,读操作在从库(Slave)完成。
如上图所示,主从复制的大致流程为:
- 主库(Master)的更新操作被写到 binlog;
- 从库(Slave)执行
start slave命令启动 I/O Thread 和 SQL Thread进程; - 从库(Slave)的 I/O Thread 会与主库(Master)建立长连接,主库会有一个线程专门维护连接,便于将增量 binlog 发送给从库;
- 从库(Slave)读取主库(Master)传过来的 binlog 内容,并写入到 Relay Log(中转日志);
- 从库(Slave)的 SQL Thread 会读取 Relay Log,将更新内容写到数据库中。
主从数据库搭建
docker-composer.yml 如下:
version: '3'
services:
mysql-master:
image: mysql:5.7
container_name: mysql-master
command: --server_id=1 --log-bin=mysql-bin --gtid_mode=ON --enforce_gtid_consistency=ON
environment:
- MYSQL_ROOT_PASSWORD=root
volumes:
- ~/data/mysql-master:/var/lib/mysql
ports:
- "33061:3306"
mysql-slave:
image: mysql:5.7
container_name: mysql-slave
command: --server_id=2 --log-bin=mysql-bin --gtid_mode=ON --enforce_gtid_consistency=ON
environment:
- MYSQL_ROOT_PASSWORD=root
volumes:
- ~/data/mysql-slave:/var/lib/mysql
ports:
- "33062:3306"
networks:
default:
driver: bridge
这里简单配置了一主一从,主从数据库要求 id 不一致,这里把主库 id 设置为1,从库 id 设置为2,运行 docker-compose up -d 命令,启动两个数据库服务。
注:一定要开启 binlog,主从复制的实现依赖于 binlog 日志。
配置主从同步
这里基于 GTID 协议配置主从关系,MySQL 5.6起推荐采用这种方式。
-
进入
mysql-master数据库,运行以下命令,创建一个用于主从复制的用户。CREATE USER 'slave'@'%' IDENTIFIED BY '123456'; GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%'; -
进入
mysql-slave数据库,运行change master命令配置要同步的主库信息。CHANGE MASTER TO MASTER_HOST='mysql-master', MASTER_USER='slave', MASTER_PASSWORD='123456', MASTER_AUTO_POSITION=1; -
运行
show slave status\G;查看从库状态。 -
运行
start slave;命令,启动I/O线程和SQL线程。 -
通过 ROOT 用户登录到
mysql-slave,运行set global read_only=ON;将从库设置为只读模式。
主备关系的建立
主备关系和主从关系的建立是一样的,同时也在主库上运行 change master 命令,我们把这种主库和备库互为主备关系的架构叫做双 M 架构。需要注意的是:主/备库上需要将 log_slave_updates 配置项设置为 ON ,这样在备库同步数据之后也能生成对应的 binlog,为切换为主库做准备,保证集群的高可用性。
验证主从数据同步
在主库中新建一个 test 数据库和 一个 test 数据表,并插入几条数据:
进入从库,查看刚刚数据是否已经同步过来:
数据已经都同步到从库当中,主从复制架构搭建完成。
主从延迟优化
从库同步主库的数据需要经过几个步骤:主库将更新写入 binlog、从库写入中转日志、从库SQL线程读取中转日志执行更新,这几个步骤都有延迟,延迟是不可避免的,只能优化,影响延迟的因素主要是以下几方面:
- 主库、从库服务器配置不一样,配置越差,延迟时间越长;
- 业务读操作较多,导致从库压力大;
- 有大事务执行操作,事务耗时较长,从库同步时也需要耗费较长时间;
- 主从之间网络延迟大,或者从库根据 binlog 日志进行数据同步时间长。
相应的优化方案如下:
- 对服务器进行升级,控制延迟到合理范围;
- 增加从库数量;
- 大事务操作尽量安排在业务低峰期执行;
- 对于实时性要求高的场景,可以将读写操作强制走主库;实时性要求不高的场景,可以通过 Ajax 或 JavaScript 在前端 UI 交互上倒计时若干秒后跳转,或者让用户主动点击按钮进行跳转,变相延迟读取从库的时间点。