在互联网业务中,数据库是核心基础设施,单点数据库一旦故障会直接导致服务中断、数据丢失,造成巨大损失。数据库高可用的核心目标是消除单点故障、保障数据不丢失、服务持续可用。本文聚焦两大主流数据库------关系型数据库MySQL(主从复制架构)和非关系型数据库Redis(集群架构),详解从环境搭建、配置部署到故障切换的完整流程,全程实战导向,新手也能按步骤落地。
一、数据库高可用核心认知
1.1 为什么需要高可用?
单点数据库存在三大致命问题:
- 硬件故障(硬盘损坏、服务器宕机)导致服务直接中断;
- 数据库压力突增(高并发查询/写入)时,单点性能瓶颈无法突破;
- 数据备份不及时或恢复困难,可能造成永久性数据丢失。
高可用架构通过"多节点冗余"解决上述问题,核心实现思路:
- 数据多副本存储(避免单点数据丢失);
- 服务多节点部署(故障时自动/手动切换);
- 读写分离(分摊单点压力,提升并发能力)。
1.2 本文覆盖架构
- MySQL高可用:一主多从复制架构(1主2从),支持读写分离、故障手动切换(生产环境可搭配MGR或Keepalived实现自动切换);
- Redis高可用:3主3从Cluster集群架构,支持数据分片存储、自动故障转移、负载均衡。
1.3 前置准备
- 服务器配置:至少4台CentOS 7.x服务器(MySQL主1台+从2台,Redis集群3台,可复用服务器但推荐独立部署);
- 基础环境:所有服务器关闭SELinux、配置防火墙规则、同步系统时间;
- 软件版本:MySQL 8.0(稳定版)、Redis 6.2(支持Cluster集群)。
二、MySQL高可用:主从复制架构部署
MySQL主从复制是关系型数据库高可用的基础方案,通过binlog(二进制日志)实现主库数据向从库同步,支持读写分离(主库写、从库读),大幅提升并发处理能力。
2.1 主从复制原理
- 主库开启binlog日志,记录所有数据修改操作(增删改);
- 从库通过IO线程连接主库,获取主库的binlog日志并写入本地relay log(中继日志);
- 从库通过SQL线程读取relay log,解析日志并执行相同操作,实现与主库数据一致。
2.2 环境规划
| 角色 | 服务器IP | 核心配置 | 用途 |
|---|---|---|---|
| MySQL主库 | 192.168.1.30 | 4核8G,500G硬盘 | 处理写入请求、同步数据 |
| MySQL从库1 | 192.168.1.31 | 4核8G,500G硬盘 | 处理查询请求、备份 |
| MySQL从库2 | 192.168.1.32 | 4核8G,500G硬盘 | 冗余备份、故障切换 |
2.3 主库(192.168.1.30)配置步骤
2.3.1 安装MySQL 8.0
bash
# 安装MySQL YUM源
wget https://dev.mysql.com/get/mysql80-community-release-el7-7.noarch.rpm
rpm -ivh mysql80-community-release-el7-7.noarch.rpm
# 安装MySQL服务器
yum install -y mysql-community-server --nogpgcheck
# 启动MySQL并设置开机自启
systemctl start mysqld
systemctl enable mysqld
# 获取初始密码
grep 'temporary password' /var/log/mysqld.log | awk '{print $NF}'
2.3.2 初始化MySQL(修改密码、授权)
bash
# 登录MySQL
mysql -u root -p
# 修改root密码(MySQL 8.0要求大小写+数字+特殊字符)
ALTER USER 'root'@'localhost' IDENTIFIED BY 'MySQL@123456';
# 创建主从复制专用用户(仅允许从库IP访问)
CREATE USER 'repl'@'192.168.1.%' IDENTIFIED BY 'Repl@123456';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.%';
FLUSH PRIVILEGES;
# 退出MySQL
exit
2.3.3 配置主库binlog与服务器ID
编辑MySQL配置文件/etc/my.cnf,添加以下配置:
ini
[mysqld]
# 服务器唯一ID(主库建议设为1,从库需不同)
server-id = 1
# 开启binlog日志,指定日志存储路径
log-bin = /var/lib/mysql/mysql-bin
# binlog日志格式(row格式支持所有场景,推荐)
binlog_format = row
# 同步的数据库(仅同步指定数据库,可选)
binlog-do-db = web_app
# 忽略同步的数据库(可选)
binlog-ignore-db = mysql
# 避免从库复制时主键冲突
log-slave-updates = 1
# 二进制日志过期时间(7天,避免日志过大)
expire_logs_days = 7
2.3.4 重启MySQL并查看主库状态
bash
# 重启MySQL
systemctl restart mysqld
# 登录MySQL,查看主库状态(记录binlog文件名和位置,后续从库配置用)
mysql -u root -pMySQL@123456
SHOW MASTER STATUS;
执行结果需记录File(如mysql-bin.000001)和Position(如156),后续从库配置需用到。
2.4 从库(192.168.1.31/32)配置步骤
两台从库配置完全一致,以下以192.168.1.31为例。
2.4.1 安装MySQL 8.0
同主库安装步骤,无需重复初始化密码(后续会同步主库数据)。
2.4.2 配置从库服务器ID与中继日志
编辑/etc/my.cnf,添加以下配置:
ini
[mysqld]
# 服务器唯一ID(从库1设为2,从库2设为3,必须与主库不同)
server-id = 2
# 开启中继日志
relay-log = /var/lib/mysql/relay-bin
# 中继日志索引文件
relay-log-index = /var/lib/mysql/relay-bin.index
# 从库只读(避免从库写入数据,导致主从不一致)
read_only = 1
# 允许超级用户临时写入(用于维护)
super_read_only = 1
# 同步的数据库
replicate-do-db = web_app
# 忽略同步的数据库
replicate-ignore-db = mysql
2.4.3 重启MySQL并配置主从同步
bash
# 重启MySQL
systemctl restart mysqld
# 登录从库MySQL
mysql -u root -p
# 重置从库同步状态(首次配置必执行)
STOP SLAVE;
RESET SLAVE;
# 配置主从连接(替换为实际主库信息、binlog文件名和位置)
CHANGE MASTER TO
MASTER_HOST='192.168.1.30',
MASTER_USER='repl',
MASTER_PASSWORD='Repl@123456',
MASTER_LOG_FILE='mysql-bin.000001', # 主库SHOW MASTER STATUS输出的File
MASTER_LOG_POS=156; # 主库SHOW MASTER STATUS输出的Position
# 启动从库同步线程
START SLAVE;
# 查看从库同步状态
SHOW SLAVE STATUS\G;
2.4.4 验证主从同步状态
执行SHOW SLAVE STATUS\G;后,重点查看两个参数:
Slave_IO_Running:YES(IO线程正常);Slave_SQL_Running:YES(SQL线程正常)。 两个参数均为YES,说明主从同步配置成功。
2.5 主从复制实战验证
2.5.1 数据同步验证
- 在主库创建
web_app数据库并插入测试数据:
mysql
CREATE DATABASE IF NOT EXISTS web_app;
USE web_app;
CREATE TABLE user (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50));
INSERT INTO user (name) VALUES ('测试用户1'), ('测试用户2');
- 在从库查询数据,验证是否同步成功:
mysql
USE web_app;
SELECT * FROM user;
若能查询到主库插入的数据,说明数据同步正常。
2.5.2 读写分离配置(可选)
通过应用层实现读写分离(主库写、从库读),以PHP为例:
php
// 主库(写操作)
$master_db = new mysqli('192.168.1.30', 'root', 'MySQL@123456', 'web_app');
// 从库(读操作)
$slave_db = new mysqli('192.168.1.31', 'root', 'MySQL@123456', 'web_app');
// 写操作(插入/更新/删除)用主库
$master_db->query("INSERT INTO user (name) VALUES ('读写分离测试')");
// 读操作(查询)用从库
$result = $slave_db->query("SELECT * FROM user");
2.6 主从复制常见问题与解决
2.6.1 Slave_IO_Running=No
- 原因:主从网络不通、复制用户密码错误、binlog文件名/位置错误;
- 解决:检查防火墙(开放3306端口)、验证复制用户权限、重新获取主库binlog状态。
2.6.2 Slave_SQL_Running=No
- 原因:从库数据与主库不一致、表结构冲突、主键重复;
- 解决:重新同步主库数据(用mysqldump备份主库,从库恢复),执行
STOP SLAVE; RESET SLAVE;后重新配置同步。
2.6.3 主从同步延迟
- 原因:从库性能不足、主库写入量过大、大事务导致;
- 解决:升级从库硬件、拆分大事务、开启从库并行复制(MySQL 8.0默认支持)。
2.7 故障切换实战(主库宕机)
当主库(192.168.1.30)宕机时,手动切换到从库(192.168.1.31):
- 确认主库宕机,登录从库停止同步:
mysql
STOP SLAVE;
- 解除从库只读限制:
mysql
SET GLOBAL read_only = 0;
SET GLOBAL super_read_only = 0;
-
应用层修改数据库连接地址,指向新主库(192.168.1.31);
-
原主库恢复后,可作为新从库,配置同步新主库数据。
三、Redis高可用:3主3从Cluster集群部署
Redis作为内存数据库,高并发场景下单点故障会导致缓存失效,进而引发数据库雪崩。Redis Cluster集群通过"分片存储+主从复制"实现高可用,支持自动故障转移,无需依赖第三方工具。
3.1 Redis Cluster核心原理
- 分片存储:将数据按哈希槽(共16384个)分配到不同主节点,每个主节点负责部分哈希槽;
- 主从复制:每个主节点对应至少1个从节点,主节点故障时,从节点自动升级为主节点;
- 自动故障转移:通过集群内节点心跳检测,发现主节点故障后,自动触发从节点选举和切换。
3.2 环境规划
| 服务器IP | 节点端口 | 角色 | 用途 |
|---|---|---|---|
| 192.168.1.40 | 7000、7003 | 主节点7000、从节点7003 | 哈希槽分配、数据备份 |
| 192.168.1.41 | 7001、7004 | 主节点7001、从节点7004 | 哈希槽分配、数据备份 |
| 192.168.1.42 | 7002、7005 | 主节点7002、从节点7005 | 哈希槽分配、数据备份 |
注:每台服务器部署2个Redis节点(1主1从),生产环境建议主从节点分布在不同服务器,避免单点故障。
3.3 集群部署步骤(所有节点通用)
3.3.1 安装Redis 6.2
bash
# 安装依赖
yum install -y gcc gcc-c++ make wget
# 下载Redis源码
wget https://download.redis.io/releases/redis-6.2.14.tar.gz
tar -zxvf redis-6.2.14.tar.gz
cd redis-6.2.14
# 编译安装
make MALLOC=libc
make install PREFIX=/usr/local/redis
# 创建Redis命令软链接
ln -s /usr/local/redis/bin/* /usr/bin/
3.3.2 创建节点目录与配置文件
以192.168.1.40为例,创建7000和7003节点目录:
bash
# 创建节点目录
mkdir -p /data/redis/{7000,7003}
# 编写7000节点配置文件(主节点)
cat > /data/redis/7000/redis.conf << EOF
port 7000
daemonize yes
pidfile /var/run/redis-7000.pid
logfile /data/redis/7000/redis.log
dir /data/redis/7000
bind 0.0.0.0
protected-mode no
requirepass Redis@123456
masterauth Redis@123456
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 5000
cluster-announce-ip 192.168.1.40
cluster-announce-port 7000
cluster-announce-bus-port 17000
maxmemory 4gb
maxmemory-policy allkeys-lru
EOF
# 编写7003节点配置文件(从节点,仅修改端口相关)
cat > /data/redis/7003/redis.conf << EOF
port 7003
daemonize yes
pidfile /var/run/redis-7003.pid
logfile /data/redis/7003/redis.log
dir /data/redis/7003
bind 0.0.0.0
protected-mode no
requirepass Redis@123456
masterauth Redis@123456
cluster-enabled yes
cluster-config-file nodes-7003.conf
cluster-node-timeout 5000
cluster-announce-ip 192.168.1.40
cluster-announce-port 7003
cluster-announce-bus-port 17003
maxmemory 4gb
maxmemory-policy allkeys-lru
EOF
其他两台服务器(192.168.1.41/42)按相同方式创建节点(端口7001/7004、7002/7005),仅修改cluster-announce-ip为对应服务器IP。
3.3.3 启动所有Redis节点
bash
# 192.168.1.40启动节点
redis-server /data/redis/7000/redis.conf
redis-server /data/redis/7003/redis.conf
# 192.168.1.41启动节点
redis-server /data/redis/7001/redis.conf
redis-server /data/redis/7004/redis.conf
# 192.168.1.42启动节点
redis-server /data/redis/7002/redis.conf
redis-server /data/redis/7005/redis.conf
# 验证节点启动状态
ps aux | grep redis-server
3.3.4 创建Redis Cluster集群
在任意一台服务器执行(推荐192.168.1.40):
bash
redis-cli -a Redis@123456 --cluster create \
192.168.1.40:7000 192.168.1.41:7001 192.168.1.42:7002 \
192.168.1.40:7003 192.168.1.41:7004 192.168.1.42:7005 \
--cluster-replicas 1
--cluster-replicas 1:指定每个主节点对应1个从节点;- 执行后会自动分配哈希槽,输入
yes确认即可。
3.4 集群验证与测试
3.4.1 查看集群状态
bash
# 登录任意节点
redis-cli -h 192.168.1.40 -p 7000 -a Redis@123456
# 查看集群信息
cluster info
# 查看节点列表(包含主从关系、哈希槽分配)
cluster nodes
输出中包含cluster_state:ok,说明集群状态正常。
3.4.2 数据读写测试
bash
# 插入数据(自动分配到对应主节点)
set product:1001 '{"name":"测试商品","price":199.9}'
# 查询数据(自动路由到数据所在节点)
get product:1001
# 查看数据所在节点
cluster keyslot product:1001
3.4.3 故障转移测试
手动停止主节点7000,验证从节点7003是否自动升级为主节点:
bash
# 停止主节点7000
redis-cli -h 192.168.1.40 -p 7000 -a Redis@123456 shutdown
# 5秒后查看节点状态
redis-cli -h 192.168.1.40 -p 7003 -a Redis@123456 cluster nodes
此时7003会显示为master,原主节点7000故障后,集群自动完成故障转移,服务不中断。
3.5 Redis集群优化与运维
3.5.1 持久化配置(避免数据丢失)
Redis集群默认开启RDB持久化,生产环境建议开启AOF持久化(日志追加模式),修改每个节点的redis.conf:
ini
appendonly yes
appendfsync everysec # 每秒同步日志到磁盘
修改后重启所有节点。
3.5.2 内存优化
- 合理设置
maxmemory(根据服务器内存,建议预留20%系统内存); - 选择合适的内存淘汰策略(
allkeys-lru:优先淘汰最近最少使用的key); - 定期清理过期key,避免无效数据占用内存。
3.5.3 集群监控
结合Prometheus+Grafana监控集群状态,核心监控指标:
- 集群状态(
cluster_state); - 每个节点的内存使用率、连接数;
- 哈希槽分配情况;
- 主从复制状态。
四、数据库高可用生产环境最佳实践
4.1 通用最佳实践
-
数据备份策略:
- MySQL:开启binlog,每天全量备份(mysqldump)+ 实时binlog备份;
- Redis:开启RDB+AOF混合持久化,定期备份RDB文件。
-
监控告警:
- 监控数据库服务状态(是否存活)、连接数、查询延迟;
- 监控数据同步状态(MySQL主从、Redis主从);
- 设置告警阈值(如MySQL连接数超过80%、Redis内存使用率超过90%),通过邮件/短信告警。
-
权限最小化:
- MySQL复制用户仅授予
REPLICATION SLAVE权限; - Redis集群设置密码,禁止外部直接访问。
- MySQL复制用户仅授予
4.2 MySQL主从复制优化
- 生产环境推荐"1主3从"架构,1个从库用于读写分离,1个用于备份,1个用于故障切换;
- 大表拆分,避免大事务导致同步延迟;
- 搭配MGR(MySQL Group Replication)实现自动故障切换,无需手动干预。
4.3 Redis集群优化
- 主从节点分布在不同服务器/机房,避免单点故障;
- 合理规划哈希槽,避免单个主节点负载过高;
- 禁止使用
KEYS、FLUSHDB等危险命令,避免影响集群性能。