掌握容器之力:MySQL主从复制
前言:
在业务场景中,使用MySQL主从复制(Master-Slave Replication)有许多重要的原因和优势:
- 负载均衡:主从复制可以将读操作分发到多个从服务器,从而减轻主服务器的负载。这有助于提高系统的性能和可扩展性,特别是在高流量的业务场景下。
- 高可用性:如果主服务器发生故障,从服务器可以快速接管,维护系统的可用性。这种故障切换可以通过监控工具和自动化脚本来实现,以降低系统宕机的风险。
- 数据备份:从服务器可以用于备份数据库。你可以在从服务器上执行备份操作,而不会影响主服务器的性能。这使得备份过程更加灵活和可控。
- 数据分析:从服务器可以用于执行复杂的数据分析和报告生成操作,而不会干扰主服务器上的事务处理。这可以改善业务智能和数据挖掘方面的工作流程。
- 读写分离:主从复制使得可以将读操作路由到从服务器,而将写操作发送到主服务器。这对于具有读写分离需求的应用程序非常有用,因为它可以提高读取性能,同时保持数据的一致性。
- 灾难恢复:如果主服务器发生严重故障或数据损坏,可以使用从服务器来进行灾难恢复。这可以帮助企业在灾难发生时快速恢复正常运营。
- 数据分发:主从复制还可以用于将数据复制到不同的地理位置或数据中心,以提高数据的可用性和地理分布。
使用Docker搭建MySQL主从复制具有以下一些优势:
- 环境隔离:Docker容器提供了隔离的运行环境,这意味着你可以在同一物理主机上运行多个MySQL实例,每个实例都具有独立的文件系统、网络和资源。这有助于防止不同MySQL实例之间的干扰和冲突。
- 快速部署:Docker容器可以快速创建和销毁,因此你可以轻松地部署MySQL主从复制环境,而无需复杂的安装和配置步骤。这对于开发、测试和部署过程非常有用。
- 可移植性:Docker容器可以在不同的环境中轻松迁移,因为它们包含了应用程序及其依赖的所有内容。这使得在开发、测试和生产环境之间进行无缝切换变得更加容易。
- 版本控制:你可以使用Docker映像标签来管理不同版本的MySQL容器。这使得可以轻松地在不同版本之间切换,以适应应用程序的需求。
- 资源管理:Docker容器可以限制使用的CPU、内存和其他资源,因此你可以更好地控制MySQL实例的资源消耗。这对于避免资源冲突和提高性能很有帮助。
- 易于升级和维护:更新和维护Docker容器非常方便。你可以通过构建新的容器映像,然后将它们替换掉旧的容器来进行MySQL版本升级或配置更改。
- 生态系统支持:Docker拥有庞大的生态系统,有许多现成的Docker映像和容器编排工具,如Docker Compose和Kubernetes,可以帮助你更轻松地管理和扩展MySQL主从复制环境。
一 Mysql主从复制原理
- 1、master服务器将数据的改变都记录到二进制binlog日志中,
只要master上的数据发生改变,则将其改变写入二进制日志
; - 2、salve服务器会在一定时间间隔内对master二进制日志进行探测其是否发生改变,如果发生改变,则
开始一个I/O Thread请求master二进制事件
- 3、同时
主节点为每个I/O线程启动一个dump线程
,用于向其发送二进制事件,并保存至从节点本地的中继日志中
- 4、从节点将启动SQL线程从中继日志中读取二进制日志,在本地重放,使得其数据和主节点的保持一致
- 5、最后I/O Thread和SQL Thread将进入睡眠状态,等待下一次被唤醒。
- 需要理解:
- 1)从库会生成两个线程,一个I/O线程,一个SQL线程;
- 2)I/O线程会去请求主库的binlog,并将得到的binlog写到本地的relay-log(中继日志)文件中;
- 3)主库会生成一个log dump线程,用来给从库I/O线程传binlog;
- 4)SQL线程,会读取relay log文件中的日志,并解析成sql语句逐一执行;
二 Mysql复制流程图
1、master将操作语句记录到binlog日志中
2、salve服务器会在一定时间间隔内对master二进制日志进行探测其是否发生改变,如果发生改变
3、
salave开启两个线程
:IO线程和SQL线程- 1)
IO线程
:负责读取master的binlog内容到中继日志relay log里; - 2)
SQL线程
:负责从relay log日志里读出binlog内容,并更新到slave的数据库里(保证数据一致)
- 1)
三 MySQL同步延迟
- 1、造成mysql同步延迟常见原因
- 1)网络:如主机或者从机的带宽打满、主从之间网络延迟很大,导致主上的binlog没有全量传输到从机,造成延迟。
- 2)机器性能:从机使用了烂机器?比如主机使用SSD而从机还是使用的SATA。
- 3)从机高负载:有很多业务会在从机上做统计,把从机服务器搞成高负载,从而造成从机延迟很大的情况
- 4)大事务:比如在RBR模式下,执行带有大量的delete操作,这种通过查看processlist相关信息以及使用mysqlbinlog查看binlog中的SQL就能快速进行确认
- 5)锁: 锁冲突问题也可能导致从机的SQL线程执行慢,比如从机上有一些select …. for update的SQL,或者使用了MyISAM引擎等。
- 2、硬件方面(优化)
- 1.采用好服务器,比如4u比2u性能明显好,2u比1u性能明显好。
- 2.存储用ssd或者盘阵或者san,提升随机写的性能。
- 3.主从间保证处在同一个交换机下面,并且是万兆环境。
- 总结:硬件强劲,延迟自然会变小。一句话,缩小延迟的解决方案就是花钱和花时间。
四 实机操作
1.拉取MySQL的镜像
这里拉取的mysql镜像的版本是8.0.34
docker pull mysql:8.0.34
2.新建MySQL主服务器的容器实例,端口为3307
创建目录
mkdir -p {mysql-master,mysql-slave}/{log,data,conf,mysql-files}
启动容器
docker run -p 3307:3306 --name mysql-master \
-v $MyFilePath/Docker/mysql/mysql-master/log:/var/log/mysql \
-v $MyFilePath/Docker/mysql/mysql-master/data:/var/lib/mysql \
-v $MyFilePath/Docker/mysql/mysql-master/conf/conf.d:/etc/mysql/conf.d \
-v $MyFilePath/Docker/mysql/mysql-master/mysql-files:/var/lib/mysql-files \
-e MYSQL_ROOT_PASSWORD=123456 \
-d mysql:8.0.34
这里$MyFilePath为我自己的环境变量
命令解读:
docker run :创建并运行一个容器
- –name : 给容器起一个名字,比如叫做abc
- -p :将宿主机端口与容器端口映射,冒号左侧是宿主机端口,右侧是容器端口
- -d:后台运行容器
- -e:环境变量,如密码什么的
- -v:挂载一个数据卷到某个容器内目录,上面分别配置了日志、数据、配置的数据卷
docker使用mysql8镜像时加载指定的外部配置文件和存储目录时,也需要指定 /var/lib/mysql-files的外部目录,不然会报如下的错:
mysqld: Error on realpath() on '/var/lib/mysql-files' (Error 2 - No such file or directory)
所以在启动容器时 需要加上-v /mydata/mysql/mysql-files:/var/lib/mysql-files/
如果启动失败可以查看docker日志
docker logs -f [name]
3.进入$MyFilePath/Docker/mysql/mysql-master/conf/conf.d
目录下新建my.cnf
cd $MyFilePath/Docker/mysql/mysql-master/conf/conf.d
vim my.cnf
里面编写如下的配置(建议复制):
[mysqld]
## 设置server_id,同一局域网中需要唯一
server_id=101
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能
log-bin=mall-mysql-bin
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
## 二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
4.修改完配置后重启master实例
docker restart mysql-master
5.进入mysql-master容器
docker exec -it mysql-master /bin/bash
mysql -uroot -p123456
6.在mysql-master容器实例内创建数据数据同步用户
新建一个数据同步用户:
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
给这个用户授予权限:
GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO 'slave'@'%';
考虑到我的MySQL8 ,密码密码必须修改为mysql_native_password的plugin才能被连接,不然无法连接。
ALTER USER 'slave'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
到这一步结束后,主机3307就告一段落了。
7.新建从服务器从服务器实例3308
docker run -p 3308:3306 --name mysql-slave \
-v $MyFilePath/Docker/mysql/mysql-slave/log:/var/log/mysql \
-v $MyFilePath/Docker/mysql/mysql-slave/data:/var/lib/mysql \
-v $MyFilePath/Docker/mysql/mysql-slave/conf/conf.d:/etc/mysql/conf.d \
-v $MyFilePath/Docker/mysql/mysql-slave/mysql-files:/var/lib/mysql-files \
-e MYSQL_ROOT_PASSWORD=123456 \
-d mysql:8.0.34
8.进入$MyFilePath/Docker/mysql/mysql-slave/conf/conf.d
目录下新建my.cnf
cd $MyFilePath/Docker/mysql/mysql-master/conf/conf.d
vim my.cnf
编写如下的配置:
[mysqld]
## 设置server_id,同一局域网中需要唯一
server_id=102
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能,以备Slave作为其它数据库实例的Master时使用
log-bin=mall-mysql-slave1-bin
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
## 二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
## relay_log配置中继日志
relay_log=mall-mysql-relay-bin
## log_slave_updates表示slave将复制事件写进自己的二进制日志
log_slave_updates=1
## slave设置为只读(具有super权限的用户除外)
read_only=1
9.修改完配置后重启slave实例
docker restart mysql-slave
10.在主数据库中查看主从同步状态
docker exec -it mysql-master /bin/bash
mysql -uroot -p123456
查看主从状态
show master status;
11.进入mysql-slave容器
docker exec -it mysql-slave /bin/bash
mysql -uroot -p123456
12.在从数据库里面配置主从复制
change master to master_host='宿主机ip', master_user='slave', master_password='123456', master_port=3307, master_log_file='mall-mysql-bin.000001', master_log_pos=156, master_connect_retry=30;
主从复制命令参数说明:
- master_host: 主数据库的IP地址;
- master_port:主数据库的运行端口;
- master_user:在主数据库创建的用于同步数据的用户账号;
- master_password:在主数据库创建的用于同步数据的用户密码;
- master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取File参数;
- master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取Position参数;
- master_connect_retry:连接失败重试的时间间隔,单位为秒。
在从数据库中查看主从同步状态:
show slave status \G
12.在从数据库中开启主从同步
start slave;
查看从数据库状态是否开启同步:
show slave status \G
13.主从复制测试
主机新建数据库,然后新建数据表,插入数据,然后在从数据库里面查看是否同步。
本案例主数据库可以读写数据,从数据库可以同步读取主数据库的数据,从数据库写的数据只存在从数据库中,不会进行同步。
- Post link: https://yanxiang.wang/%E6%8E%8C%E6%8F%A1%E5%AE%B9%E5%99%A8%E4%B9%8B%E5%8A%9B%EF%BC%9AMySQL%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.