1. Docker环境下的MySQL主从复制实战
在分布式系统中,数据库的高可用性是保障业务连续性的关键。MySQL主从复制作为经典的高可用方案,通过Docker容器化部署能够快速搭建测试环境。下面我将分享在Docker中配置MySQL 5.7主从复制的完整过程。
1.1 主从复制核心原理
MySQL主从复制的本质是基于二进制日志(binlog)的数据同步机制。当主库数据发生变化时,这些变更会被记录到binlog中,从库通过I/O线程读取主库的binlog并写入本地的中继日志(relay log),最后由SQL线程重放这些变更。
这种架构带来三个主要优势:
- 读写分离:主库处理写请求,从库承担读负载
- 数据备份:从库相当于实时备份
- 故障转移:主库宕机时可快速提升从库为主库
生产环境中建议至少配置2个从库,避免单点故障。根据业务压力,从库数量可以水平扩展。
1.2 主库容器配置实操
首先创建主库容器实例(端口映射3307):
bash复制docker run -p 3307:3306 --name mysql-master \
-v /mydata/mysql-master/log:/var/log/mysql \
-v /mydata/mysql-master/data:/var/lib/mysql \
-v /mydata/mysql-master/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
关键配置说明:
-v参数将容器内的日志、数据和配置目录挂载到宿主机,避免容器销毁时数据丢失- 建议使用固定密码而非默认的随机密码,方便后续维护
- MySQL 5.7相比8.0版本对Docker兼容性更好,适合学习环境
主库的核心配置文件my.cnf需要特别关注以下参数:
ini复制[mysqld]
server_id=101 # 集群内唯一ID
log-bin=mall-mysql-bin # 二进制日志文件名
binlog_format=mixed # 推荐使用混合模式
binlog-ignore-db=mysql # 不同步系统库
expire_logs_days=7 # 日志保留周期
配置完成后需要重启容器使配置生效:
bash复制docker restart mysql-master
1.3 从库容器配置要点
从库的创建命令与主库类似,主要区别在于:
- 使用不同的端口映射(如3308)
- 数据目录需要独立挂载
- server_id必须与主库不同
从库的my.cnf配置需要额外注意:
ini复制[mysqld]
relay_log=mall-mysql-relay-bin # 中继日志配置
log_slave_updates=1 # 级联复制时需要
read_only=1 # 从库只读模式
特别提醒:如果遇到/etc/mysql/conf.d目录缺失错误,需要先在宿主机创建对应目录结构。
1.4 主从链路建立过程
在主库创建复制专用账号:
sql复制CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
在从库执行连接主库的命令:
sql复制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=617;
关键参数说明:
MASTER_LOG_FILE和MASTER_LOG_POS需要通过SHOW MASTER STATUS在主库查询- 网络连通性测试建议使用
telnet 主库IP 3307验证 - 企业级环境建议配置SSL加密复制通道
启动复制后,可以通过SHOW SLAVE STATUS\G查看复制状态,确认Slave_IO_Running和Slave_SQL_Running都为Yes。
1.5 主从复制问题排查
常见问题及解决方案:
- 复制中断:检查
Last_Error字段,常见原因是主从数据不一致 - 延迟严重:监控
Seconds_Behind_Master,可能是从库性能不足 - 连接失败:检查防火墙设置和网络连通性
建议定期检查复制状态,可以设置监控告警。对于重要业务,建议配置延迟从库作为灾备。
2. Redis集群部署与分区算法详解
2.1 分布式存储方案对比
当数据量达到亿级时,单机Redis无法满足需求,必须采用分布式方案。主流的分区算法有三种:
2.1.1 哈希取余分区
最简单的分布式方案,计算公式:hash(key) % 节点数
优点:
- 实现简单
- 数据分布均匀(节点数固定时)
缺点:
- 扩容/缩容时数据迁移量大
- 节点变化会导致缓存雪崩
适合节点固定的测试环境,不推荐生产使用。
2.1.2 一致性哈希算法
通过虚拟环状结构减少节点变化的影响范围。
改进点:
- 节点增减只影响相邻节点
- 数据迁移量减少约1/N(N为节点数)
现存问题:
- 节点分布不均时会出现数据倾斜
- 新增节点只能分担相邻节点的负载
2.1.3 哈希槽分区(Redis Cluster方案)
Redis官方集群方案,采用16384个固定槽位。
核心优势:
- 解耦数据和节点的直接映射关系
- 槽位可以批量迁移,运维更方便
- 支持自动故障转移
数据定位流程:
- 对key计算CRC16值
- 对16384取模得到槽位号
- 根据槽位映射表找到对应节点
2.2 Redis集群搭建实战
2.2.1 集群节点初始化
创建6个Redis节点(3主3从):
bash复制for port in $(seq 6381 6386); do
docker run -d --name redis-node-${port} \
--net host --privileged=true \
-v /data/redis/share/redis-node-${port}:/data \
redis:6.0.8 \
--cluster-enabled yes \
--appendonly yes \
--port ${port}
done
关键参数说明:
--net host使用主机网络模式,避免端口映射复杂化--cluster-enabled yes启用集群模式- Redis 6.0相比旧版本提供了更好的集群管理功能
# 1. 题目
93. 复原 IP 地址
难度中等890
有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。
- 例如:
"0.1.2.201"和"192.168.1.1"是 有效 IP 地址,但是"0.011.255.245"、"192.168.1.312"和"192.168@1.1"是 无效 IP 地址。
给定一个只包含数字的字符串 s ,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s 中插入 '.' 来形成。你 不能 重新排序或删除 s 中的任何数字。你可以按 任何 顺序返回答案。
示例 1:
code复制输入:s = "25525511135"
输出:["255.255.11.135","255.255.111.35"]
示例 2:
code复制输入:s = "0000"
输出:["0.0.0.0"]
示例 3:
code复制输入:s = "101023"
输出:["1.0.10.23","1.0.102.3","10.1.0.23","10.10.2.3","101.0.2.3"]
提示:
1 <= s.length <= 20s仅由数字组成
2. 题解
3. code
c++复制class Solution {
public:
vector<string> ans;
bool isValid(const string& s, int start, int end) {
if (start > end) {
return false;
}
if (s[start] == '0' && start != end) {
return false;
}
int num = 0;
for (int i = start; i <= end; i++) {
if (s[i] > '9' || s[i] < '0') {
return false;
}
num = num * 10 + (s[i] - '0');
if (num > 255) {
return false;
}
}
return true;
}
void backtracking(string s, int startIdx, int pointNum) {
if (pointNum == 3) {
if (isValid(s, startIdx, s.size() - 1)) {
ans.push_back(s);
}
return;
}
for (int i = startIdx; i < s.size(); i++) {
if (isValid(s, startIdx, i)) {
s.insert(s.begin() + i + 1, '.');
pointNum++;
backtracking(s, i + 2, pointNum);
pointNum--;
s.erase(s.begin() + i + 1);
} else {
break;
}
}
return;
}
vector<string> restoreIpAddresses(string s) {
if (s.size() < 4 || s.size() > 12) return ans;
backtracking(s, 0, 0);
return ans;
}
};
4. 心得
回溯法,注意终止条件,以及插入和删除的位置。