- MySQL主从同步配置
主从同步是在数据库服务器层面配置的,不是在应用代码中实现:
步骤1:docker-compose配置
services:
mysql-master:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: masterpass
MYSQL_REPLICATION_USER: repl_user
MYSQL_REPLICATION_PASSWORD: repl_pass
volumes:
-
./mysql/master:/var/lib/mysql
-
./mysql/master.cnf:/etc/mysql/conf.d/master.cnf
ports:
- "3306:3306"
mysql-slave1:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: slavepass
MYSQL_REPLICATION_USER: repl_user
MYSQL_REPLICATION_PASSWORD: repl_pass
volumes:
-
./mysql/slave1:/var/lib/mysql
-
./mysql/slave1.cnf:/etc/mysql/conf.d/slave.cnf
depends_on:
- mysql-master
步骤2:主库配置文件 (master.cnf)
mysqld
server-id = 1
log-bin = mysql-bin
binlog_format = ROW
binlog_do_db = chatdb # 指定要同步的数据库
sync_binlog = 1
步骤3:从库配置文件 (slave.cnf)
mysqld
server-id = 2 # 每个从库需要唯一ID
relay-log = mysql-relay-bin
read_only = 1 # 确保从库只读
步骤4:初始化主从同步
在主库创建复制用户
docker exec -it mysql-master mysql -uroot -pmasterpass -e \
"CREATE USER 'repl_user'@'%' IDENTIFIED BY 'repl_pass'; \
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%'; \
FLUSH PRIVILEGES;"
查看主库状态
docker exec -it mysql-master mysql -uroot -pmasterpass -e "SHOW MASTER STATUS;"
在从库配置主库信息
docker exec -it mysql-slave1 mysql -uroot -pslavepass -e \
"CHANGE MASTER TO \
MASTER_HOST='mysql-master', \
MASTER_USER='repl_user', \
MASTER_PASSWORD='repl_pass', \
MASTER_LOG_FILE='mysql-bin.000003', \ # 来自SHOW MASTER STATUS
MASTER_LOG_POS=107; \
START SLAVE;"
- 解决主从同步延迟问题
针对主从同步延迟导致的数据不一致,我们采用"缓存屏障"策略:
// user_service.cpp
void updateUserStatus(int userId, string status) {
// 1. 更新主库
mysql_query(MasterDB, "UPDATE users SET status = ...");
// 2. 立即更新缓存
redisClient.set("user_status:" + to_string(userId), status);
// 3. 设置缓存过期时间(略长于主从同步最大延迟)
redisClient.expire("user_status:" + to_string(userId), 5);
}
string getUserStatus(int userId) {
// 1. 先尝试从缓存读取
string cachedStatus = redisClient.get("user_status:" + to_string(userId));
if (!cachedStatus.empty()) {
return cachedStatus;
}
// 2. 缓存不存在,查询数据库
// 注意:这里可能路由到从库,但此时数据应该已经同步
string dbStatus = queryStatusFromDB(userId);
// 3. 将结果写入缓存
redisClient.setex("user_status:" + to_string(userId), 300, dbStatus);
return dbStatus;
}
关键策略:
- 写后立即更新缓存:
-
写操作完成后立即更新缓存
-
确保后续读取可以直接从缓存获取最新数据
- 缓存过期时间:
-
设置略大于主从同步最大延迟时间(如5秒)
-
保证在过期前主从同步完成
- 重要数据强制读主:
string getCriticalData(int id) {
// 金融类数据直接读主库
return queryFromMasterDB("SELECT * FROM critical_data WHERE id = ...");
}
- Binlog监听更新缓存:
使用Canal等工具监听主库Binlog,实时更新缓存:
// Canal客户端伪代码
void updateCacheFromBinlog() {
while (true) {
Message message = canalConnector.get();
for (Entry entry : message.getEntries()) {
if (entry.getEntryType() == ROWDATA) {
redisClient.set(entry.getKey(), entry.getValue());
}
}
}
}
MySQL主从同步配置详解
您提供的配置是一个典型的基于Docker的MySQL主从同步配置。下面我将详细解释每个步骤的原理和作用,帮助您全面理解MySQL主从同步的配置过程。
一、主从同步的基本原理
MySQL主从同步是基于**二进制日志(binlog)**实现的:
-
主库(Master):
- 执行数据变更操作(INSERT/UPDATE/DELETE)
- 将操作记录到二进制日志(binlog)
- 二进制日志记录了所有对数据库的修改
-
从库(Slave):
- 通过IO线程连接主库,请求binlog
- 将binlog写入中继日志(relay-log)
- 通过SQL线程执行中继日志中的操作
- 实现与主库的数据同步
二、详细配置解析
步骤1:docker-compose配置
yaml
编辑
services:
mysql-master:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: masterpass
MYSQL_REPLICATION_USER: repl_user
MYSQL_REPLICATION_PASSWORD: repl_pass
volumes:
- ./mysql/master:/var/lib/mysql
- ./mysql/master.cnf:/etc/mysql/conf.d/master.cnf
ports:
- "3306:3306"
mysql-slave1:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: slavepass
MYSQL_REPLICATION_USER: repl_user
MYSQL_REPLICATION_PASSWORD: repl_pass
volumes:
- ./mysql/slave1:/var/lib/mysql
- ./mysql/slave1.cnf:/etc/mysql/conf.d/slave.cnf
depends_on:
- mysql-master
关键点解释:
- Docker容器化:将MySQL服务运行在容器中,便于隔离和管理
- 数据持久化 :
volumes将容器内的MySQL数据目录挂载到宿主机,确保容器重启后数据不丢失 - 配置文件挂载:将自定义的配置文件挂载到容器内,实现主从配置
- 依赖关系 :
depends_on确保主库容器先启动,从库容器再启动
步骤2:主库配置文件 (master.cnf)
ini
编辑
[mysqld]
server-id = 1
log-bin = mysql-bin
binlog_format = ROW
binlog_do_db = chatdb # 指定要同步的数据库
sync_binlog = 1
关键参数详解:
-
server-id = 1:
- 主库的唯一标识,必须与从库不同
- 用于区分多个MySQL实例(在集群中必须唯一)
- 知识库[3]和[7]提到:"server_id 用于区分服务,范围1~2^32-1"
-
log-bin = mysql-bin:
- 启用二进制日志功能
- 日志文件名前缀为
mysql-bin,实际文件会是mysql-bin.000001等 - 知识库[3]指出:"主数据库master进行增删改操作后,相应操作记录的语句会记录到binlog日志文件中"
-
binlog_format = ROW:
- 二进制日志格式,有三种模式:
- STATEMENT:记录SQL语句(可能导致主从不一致)
- ROW:记录每一行的变更(更安全,推荐)
- MIXED:混合模式
- 知识库[5]提到:"STATEMENT模式可能因为函数导致主从数据不一致"
- 二进制日志格式,有三种模式:
-
binlog_do_db = chatdb:
- 指定要同步的数据库
- 仅同步
chatdb数据库,避免不必要的数据传输 - 知识库[6]提到:"binlog-do-db= db1 #需要同步的数据库名称"
-
sync_binlog = 1:
- 控制binlog刷新到磁盘的频率
1表示每次事务提交都刷新到磁盘,提高数据安全性- 知识库[6]提到:"sync_binlog=1,MySQL在每写1次二进制日志时,会将日志同步到磁盘"
步骤3:从库配置文件 (slave.cnf)
ini
编辑
[mysqld]
server-id = 2 # 每个从库需要唯一ID
relay-log = mysql-relay-bin
read_only = 1 # 确保从库只读
关键参数详解:
-
server-id = 2:
- 从库的唯一标识
- 必须与主库和其他从库不同
- 知识库[7]指出:"server_id = 88 #集群唯一标识,主库从库不能重复"
-
relay-log = mysql-relay-bin:
- 从库的中继日志文件名前缀
- 用于存储从主库获取的binlog
- 知识库[8]提到:"中继日志(Relay Log):从库上的一个日志文件,用于存储从主库读取的二进制日志"
-
read_only = 1:
- 设置从库为只读模式
- 防止从库被直接写入,保证数据一致性
- 知识库[9]提到:"从库的只读属性是主从同步的重要保障"
步骤4:初始化主从同步
1. 创建复制用户
bash
编辑
docker exec -it mysql-master mysql -uroot -pmasterpass -e \
"CREATE USER 'repl_user'@'%' IDENTIFIED BY 'repl_pass'; \
GRANT REPLICATION SLAVE ON *.* TO 'repl_user'@'%'; \
FLUSH PRIVILEGES;"
关键点:
- 创建专门用于复制的用户
repl_user - 授予
REPLICATION SLAVE权限,这是主从同步必需的 GRANT REPLICATION SLAVE ON *.*:授予所有数据库的复制权限- 知识库[6]提到:"grant replication slave on . to 'repl'@'%' identified by 'repl';"
2. 查看主库状态
bash
编辑
docker exec -it mysql-master mysql -uroot -pmasterpass -e "SHOW MASTER STATUS;"
输出示例:
text
编辑
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 | 107 | chatdb | |
+------------------+----------+--------------+------------------+
关键信息:
File:当前binlog文件名(mysql-bin.000003)Position:当前binlog位置(107)Binlog_Do_DB:要同步的数据库(chatdb)
3. 在从库配置主库信息
bash
编辑
docker exec -it mysql-slave1 mysql -uroot -pslavepass -e \
"CHANGE MASTER TO \
MASTER_HOST='mysql-master', \
MASTER_USER='repl_user', \
MASTER_PASSWORD='repl_pass', \
MASTER_LOG_FILE='mysql-bin.000003', \
MASTER_LOG_POS=107; \
START SLAVE;"
关键点:
CHANGE MASTER TO:配置从库连接主库的参数MASTER_HOST='mysql-master':主库容器名(Docker网络中可解析)MASTER_LOG_FILE和MASTER_LOG_POS:从SHOW MASTER STATUS获取的值START SLAVE:启动从库的复制线程
三、主从同步工作流程
-
主库写入数据:
- 执行INSERT/UPDATE/DELETE操作
- 将操作记录到binlog(
mysql-bin.000003) - 操作在主库完成
-
从库获取数据:
- IO线程连接主库,请求binlog
- 从主库获取binlog内容
- 将binlog写入中继日志(
mysql-relay-bin)
-
从库应用数据:
- SQL线程读取中继日志
- 执行binlog中的操作
- 数据同步完成
四、主从同步状态检查
bash
编辑
docker exec -it mysql-slave1 mysql -uroot -pslavepass -e "SHOW SLAVE STATUS\G"
关键状态字段:
Slave_IO_Running:IO线程状态(Yes表示正常)Slave_SQL_Running:SQL线程状态(Yes表示正常)Seconds_Behind_Master:从库落后主库的时间(0表示同步完成)
五、主从同步的同步方式
根据知识库[1],MySQL主从同步主要有两种方式:
-
异步方式:
- 主库立即响应应用,同时异步复制数据
- 特点:高性能,但主库不可用会影响数据一致性
- 您的配置默认使用的是异步方式
-
半同步方式:
- 主库等待从库确认收到日志才返回响应
- 特点:数据安全性高,但性能稍低
- 知识库[1]提到:"半同步方式下,当备实例不可用...主实例会自动切换为异步方式"
六、为什么需要这些配置?
- server-id:确保主从库能正确识别彼此,避免循环复制
- binlog:主从同步的基础,没有binlog就无法实现同步
- binlog_format=ROW:避免STATEMENT模式可能导致的数据不一致
- binlog_do_db:只同步必要数据,减少网络传输和存储开销
- sync_binlog=1:确保数据安全,避免主库崩溃导致数据丢失
- read_only=1:防止从库被直接写入,保证数据一致性
七、常见问题与解决方案
-
主从同步失败:
- 检查网络连接:确保主从库之间网络连通
- 检查复制用户权限:确保
repl_user有REPLICATION SLAVE权限 - 检查binlog位置:确保
MASTER_LOG_FILE和MASTER_LOG_POS正确
-
数据不一致:
- 检查binlog_format:建议使用ROW模式
- 检查主从数据库版本:确保主从版本一致
- 使用
pt-table-checksum工具检查数据一致性
-
性能问题:
- 适当调整sync_binlog:设置为0可能提高性能,但降低数据安全性
- 使用半同步复制:在MySQL 5.7及以上版本支持
八、与知识库的联系
- 您的配置与知识库[3]、[6]和[7]中的配置方法一致
- 详细解释了
server-id、log-bin等关键参数 - 使用了ROW模式的binlog格式,避免了知识库[5]提到的STATEMENT模式问题
- 通过
read_only=1确保从库的只读特性,符合知识库[9]的建议
总结
您提供的配置是一个标准的MySQL主从同步配置,基于Docker实现,使用异步复制方式。这种配置方式:
- 简单易用,适合开发和测试环境
- 通过Docker实现环境隔离
- 使用ROW模式的binlog确保数据一致性
- 通过
read_only设置防止从库被直接写入
主从同步是实现高可用、读写分离和数据备份的基础,正确配置主从同步对构建可靠的应用系统至关重要。