# AWS RDS + EC2 Redis 到外部备用服务器 Runbook

目标：让 `104.238.220.230` 持续作为 AWS 主生产环境的异地备用节点，承接：

- MySQL 外部只读从库
- Redis 外部从库
- 故障时的快速提升与业务切换

本文档以 `2026-05-13` 的真实现网状态为准，覆盖：

- 当前已经落地的主从架构
- 日常验收命令
- 主从故障排查
- 全量重建从库
- “新建规范 RDS 再切换”的生产级收敛路线
- 故障切换与回滚

## 1. 当前已确认资源

### 1.1 AWS 主生产

- Region: `ap-east-1`
- AWS app EC2:
  - Name: `hifast-hk-app-01`
  - Public IP: `18.163.33.75`
  - Private IP: `10.0.1.201`
- AWS MySQL:
  - Type: `RDS MySQL`
  - Instance: `hifast-mysql-prod-v2`
  - Endpoint: `hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com`
  - Version: `8.4.8`
  - DB Name: `hifast`
  - Admin user: `admin`
  - Admin password: keep it in a secret store, do not write plaintext into repo docs
  - Replication user: `repl`
  - Replication password: keep it in a secret store, do not write plaintext into repo docs
- AWS Redis:
  - Location: `hifast-hk-app-01`
  - Deployment: `Docker`
  - Container: `hifast-redis`
  - Version: `redis:8.2.1`
  - Listen: `0.0.0.0:6379`
  - Password: keep it in a secret store, do not write plaintext into repo docs

### 1.2 外部备用服务器

- Host: `104.238.220.230`
- OS: `Ubuntu 24.04 LTS`
- SSH user: `root`
- MySQL version: `8.4.9`
- Redis version: `8.6.3`
- 当前角色：
  - MySQL external replica
  - Redis replica
  - 备用应用节点

### 1.3 当前应用真实运行方式

AWS 应用机上的 `ppanel-server` 当前不是 systemd 托管，而是 Docker Compose 服务：

- Compose file: `/opt/ppanel/docker-compose.cloud.yml`
- Config file: `/opt/ppanel/configs/ppanel.yaml`
- Container name: `ppanel-server`
- Current MySQL target: `hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com:3306`
- Current Redis target: `127.0.0.1:6379`

也就是说，后续所有应用侧切换步骤，都应该以修改：

- `/opt/ppanel/configs/ppanel.yaml`

并执行：

```bash
cd /opt/ppanel
docker compose -f docker-compose.cloud.yml up -d ppanel-server
```

作为准。

## 2. 当前健康基线

截至 `2026-05-13`，已确认以下状态成立：

- `104` MySQL:
  - `Source_Host = hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com`
  - `Replica_IO_Running: Yes`
  - `Replica_SQL_Running: Yes`
  - `Seconds_Behind_Source: 0`
  - `read_only = ON`
  - `super_read_only = ON`
- AWS Redis 主库:
  - `role:master`
  - `connected_slaves:1`
- `104` Redis:
  - `role:slave`
  - `master_link_status:up`
- AWS 应用:
  - `curl http://127.0.0.1:8080/v1/common/heartbeat` 返回 `code=200`

这说明当前状态已经达到：

- 主生产可用
- 外部备用持续同步
- Redis 已回到真实本机链路

## 3. 当前网络前提

### 3.1 安全组

当前实际生效的安全组如下：

- `hifast-hk-app-core-sg`
  - `22/tcp <- 0.0.0.0/0`
  - `6379/tcp <- 104.238.220.230/32`
  - `8080/tcp <- hifast-hk-web-sg`
- `hifast-hk-rds-core-sg`
  - `3306/tcp <- 104.238.220.230/32`
  - `3306/tcp <- hifast-hk-app-core-sg`
- `hifast-hk-web-sg`
  - `22/80/443 <- 0.0.0.0/0`

### 3.2 当前结构性限制

当前 `104 -> RDS` 公网复制链路虽然可用，但依赖的是：

- `hifast-mysql-prod-v2` 为 `Publicly accessible = Yes`
- RDS ENI 仍位于 `hifast-hk-private-1b`
- `private-1b` 被临时挂到了公网路由表

这不是最终规范的生产形态。

当前这条路线已经完成，后续更推荐的动作是：

1. 持续确认应用主库目标保持在 `hifast-mysql-prod-v2`
2. 持续确认 `104` 复制目标保持在 `hifast-mysql-prod-v2`
3. 根据回收窗口安排旧 RDS 下线
4. 按网络收敛计划处理 `private-1b` 路由语义

## 4. 日常验收命令

### 4.1 验收 MySQL 主从

在 `104` 执行：

```bash
mysql -e "SHOW REPLICA STATUS\G"
```

重点看：

- `Source_Host`
- `Replica_IO_Running`
- `Replica_SQL_Running`
- `Seconds_Behind_Source`
- `Last_IO_Error`
- `Last_SQL_Error`

成功标准：

- `Replica_IO_Running: Yes`
- `Replica_SQL_Running: Yes`
- `Seconds_Behind_Source: 0` 或较小

### 4.2 验收 Redis 主从

在 AWS app EC2 执行：

```bash
docker exec hifast-redis redis-cli -a '0BVz9XOHf7KUfEuoFJRK-dURdKUGFiZ8QeaHpysHnKeKhLskZb55HPK121lFsKtr' INFO replication
```

重点看：

- `role:master`
- `connected_slaves:1`

在 `104` 执行：

```bash
redis-cli INFO replication
```

重点看：

- `role:slave`
- `master_host:18.163.33.75`
- `master_port:6379`
- `master_link_status:up`

### 4.3 验收应用

在 AWS app EC2 执行：

```bash
curl -sf http://127.0.0.1:8080/v1/common/heartbeat
```

期望返回：

- `{"code":200,...}`

查看容器：

```bash
cd /opt/ppanel
docker compose -f docker-compose.cloud.yml ps
```

期望：

- `ppanel-server` 为 `Up`
- `hifast-redis` 为 `Up`

## 5. MySQL 复制故障排查

### 5.1 先看复制状态

```bash
mysql -e "SHOW REPLICA STATUS\G"
```

重点判断：

- `Replica_IO_Running = No`
- `Replica_SQL_Running = No`
- `Last_IO_Error`
- `Last_SQL_Error`

### 5.2 常见场景

#### 场景 A：网络或白名单断开

表现：

- `Replica_IO_Running: No`
- `Last_IO_Error` 出现连接失败、超时、拒绝访问

排查：

```bash
mysql -h hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com -u repl -p -e "SELECT 1;"
```

处理：

- 检查 RDS SG 是否仍保留 `104.238.220.230/32 -> 3306`
- 检查 RDS 是否仍为 `Publicly accessible = Yes`
- 如果后续已迁到新规范 RDS，则检查新实例的 SG 和公网可达性

#### 场景 B：主库 binlog 位点丢失

表现：

- `Last_IO_Error` 或 `Last_SQL_Error` 指向缺失 binlog

处理：

- 不要硬跳过
- 直接执行全量重建从库

#### 场景 C：SQL 执行报错

表现：

- `Replica_SQL_Running: No`
- `Last_SQL_Error` 有实际 SQL 冲突信息

处理建议：

- 如果只是临时演练环境，可重建从库
- 如果已经进入生产切换阶段，不建议盲目 `sql_slave_skip_counter`
- 优先保守做法仍是重新全量初始化

## 6. Redis 复制故障排查

### 6.1 看 `104` 从库状态

```bash
redis-cli INFO replication
```

重点：

- `role`
- `master_host`
- `master_link_status`

### 6.2 看 AWS 主库状态

```bash
docker exec hifast-redis redis-cli -a '0BVz9XOHf7KUfEuoFJRK-dURdKUGFiZ8QeaHpysHnKeKhLskZb55HPK121lFsKtr' INFO replication
```

重点：

- `role:master`
- `connected_slaves`

### 6.3 常见问题

#### 场景 A：安全组断开

表现：

- `master_link_status:down`

处理：

- 确认 `hifast-hk-app-core-sg` 仍保留：
  - `6379/tcp <- 104.238.220.230/32`

#### 场景 B：主库密码漂移

表现：

- 从库重连失败
- 日志出现 `NOAUTH`

处理：

- 统一更新 `/etc/redis/redis.conf` 中的：
  - `masterauth`
- 然后：

```bash
systemctl restart redis-server
redis-cli INFO replication
```

## 7. 全量重建 MySQL 从库

适用场景：

- 主从中断且无法安全追平
- `6666@qq.com` 这类写入在主库存在、从库未同步
- binlog 不连续
- 需要回到最稳妥状态

### 7.1 在主库导出

在一台可连 RDS 的机器上执行：

```bash
mysqldump \
  -h hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com \
  -u admin \
  -p \
  --single-transaction \
  --routines \
  --triggers \
  --events \
  --set-gtid-purged=OFF \
  hifast > hifast-full.sql
```

如果需要同步账号权限，也可以额外单独导出授权对象；但当前业务库恢复重点是 `hifast` 数据库本身。

### 7.2 清理 `104` 当前复制

在 `104` 执行：

```sql
STOP REPLICA;
RESET REPLICA ALL;
```

### 7.3 重新导入业务库

在 `104` 执行：

```bash
mysql -e "DROP DATABASE IF EXISTS hifast; CREATE DATABASE hifast CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;"
mysql hifast < hifast-full.sql
```

### 7.4 重新挂复制

当前现网是非 GTID 自动定位，使用 file/position 模式。

先在主库取位点：

```sql
SHOW MASTER STATUS;
```

然后在 `104` 执行：

```sql
CHANGE REPLICATION SOURCE TO
  SOURCE_HOST='hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com',
  SOURCE_PORT=3306,
  SOURCE_USER='repl',
  SOURCE_PASSWORD='<REPL_PASSWORD>',
  SOURCE_LOG_FILE='<MASTER_LOG_FILE>',
  SOURCE_LOG_POS=<MASTER_LOG_POS>,
  SOURCE_SSL=1;
START REPLICA;
SHOW REPLICA STATUS\G
```

### 7.5 验收

确认：

- `Replica_IO_Running: Yes`
- `Replica_SQL_Running: Yes`
- `Seconds_Behind_Source: 0`
- `read_only = ON`
- `super_read_only = ON`

## 8. 重新配置 Redis 从库

当前 `104` Redis 为原生安装，不使用 Docker。

### 8.1 临时切回从库

```bash
redis-cli CONFIG SET masterauth '0BVz9XOHf7KUfEuoFJRK-dURdKUGFiZ8QeaHpysHnKeKhLskZb55HPK121lFsKtr'
redis-cli REPLICAOF 18.163.33.75 6379
redis-cli CONFIG SET replica-read-only yes
redis-cli INFO replication
```

### 8.2 持久化配置

检查 `/etc/redis/redis.conf` 至少包含：

```conf
replicaof 18.163.33.75 6379
masterauth 0BVz9XOHf7KUfEuoFJRK-dURdKUGFiZ8QeaHpysHnKeKhLskZb55HPK121lFsKtr
replica-read-only yes
```

然后：

```bash
systemctl restart redis-server
redis-cli INFO replication
```

## 9. 生产级收敛路线：新建规范 RDS 再切换

这条路线已经完成，当前现网主库已经切到 `hifast-mysql-prod-v2`。下面内容保留为迁移归档参考，不再表示待执行。

### 9.1 目标

把当前临时方案：

- `private-1b` 挂公网路由

收敛成：

- RDS 使用纯公网 DB subnet group
- 安全组仍只对白名单和应用组开放

### 9.2 已准备好的资源

- 已建 DB subnet group:
  - `hifast-hk-rds-public-only-sgprep`
- 子网：
  - `hifast-hk-public-1a`
  - `hifast-hk-public-1b`

### 9.3 新 RDS 建议参数

新实例建议名：

- `hifast-mysql-prod-v2`

建议保持与旧主库一致：

- Engine: `mysql`
- Version: `8.4.8`
- Class: `db.r7g.xlarge`
- Storage: `gp3`
- Size: `200 GB`
- IOPS: `3000`
- Throughput: `125`
- Publicly accessible: `Yes`
- Multi-AZ: `No` 或按预算单独评估
- Deletion protection: `On`
- Performance Insights: `On`
- Backup retention: `7`
- DB subnet group: `hifast-hk-rds-public-only-sgprep`
- VPC SG: `hifast-hk-rds-core-sg`

### 9.4 迁移步骤

1. 已创建新 RDS `hifast-mysql-prod-v2`
2. 在旧主库导出 `hifast`
3. 导入新库
4. 在新库创建 `repl` 用户并配置 binlog retention
5. 修改 AWS app EC2 上 `/opt/ppanel/configs/ppanel.yaml` 的 `MySQL.Addr`
6. 重启 `ppanel-server` 容器
7. 在 `104` 上 `STOP REPLICA; RESET REPLICA ALL;`
8. 指向新 RDS endpoint 重新挂复制
9. 验收应用与主从
10. 验收通过后，安排旧 RDS 下线，并推进 `private-1b` 恢复私网路由

### 9.5 应用切换命令

在 AWS app EC2：

1. 备份配置

```bash
cp /opt/ppanel/configs/ppanel.yaml /opt/ppanel/configs/ppanel.yaml.bak.$(date +%Y%m%d%H%M%S)
```

2. 编辑：

- `/opt/ppanel/configs/ppanel.yaml`

把：

```yaml
MySQL:
  Addr: hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com:3306
```

改成：

```yaml
MySQL:
  Addr: hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com:3306
```

3. 重启应用容器：

```bash
cd /opt/ppanel
docker compose -f docker-compose.cloud.yml up -d ppanel-server
```

4. 验证：

```bash
curl -sf http://127.0.0.1:8080/v1/common/heartbeat
docker compose -f docker-compose.cloud.yml logs --tail=100 ppanel-server
```

### 9.6 `104` 改挂新 RDS

```sql
STOP REPLICA;
RESET REPLICA ALL;
CHANGE REPLICATION SOURCE TO
  SOURCE_HOST='<NEW_RDS_ENDPOINT>',
  SOURCE_PORT=3306,
  SOURCE_USER='repl',
  SOURCE_PASSWORD='<REPL_PASSWORD>',
  SOURCE_LOG_FILE='<MASTER_LOG_FILE>',
  SOURCE_LOG_POS=<MASTER_LOG_POS>,
  SOURCE_SSL=1;
START REPLICA;
SHOW REPLICA STATUS\G
```

### 9.7 切换验收

至少确认：

- AWS 应用心跳正常
- 新 RDS 可正常读写
- `104` 复制恢复为 `Yes/Yes`
- `Seconds_Behind_Source` 追到 `0`
- Navicat 可从允许的白名单来源连接新 RDS

### 9.8 回滚

如果新 RDS 切换后应用异常：

1. 立即把 `/opt/ppanel/configs/ppanel.yaml` 中 `MySQL.Addr` 改回旧 endpoint
2. 重启 `ppanel-server`
3. 暂不处理 `104`，先恢复主生产
4. 复盘新库数据、权限、参数、网络

## 10. AWS 故障时的备用接管

### 10.1 Redis 提升为主库

在 `104`：

```bash
redis-cli REPLICAOF NO ONE
redis-cli INFO replication
```

期望：

- `role:master`

### 10.2 MySQL 提升为可写主库

在 `104`：

```sql
STOP REPLICA;
RESET REPLICA ALL;
SET GLOBAL super_read_only=OFF;
SET GLOBAL read_only=OFF;
```

再确认：

```sql
SHOW VARIABLES LIKE 'read_only';
SHOW VARIABLES LIKE 'super_read_only';
```

期望：

- `OFF`
- `OFF`

### 10.3 应用切到 `104` 本机数据层

如果 `104` 上也部署同样的 PPanel 服务，则应用配置应改为：

- MySQL 指向 `127.0.0.1:3306` 或本机 socket
- Redis 指向 `127.0.0.1:6379`

### 10.4 最后切入口

数据层和应用层都确认可写后，再做：

- DNS 切换
- 或 Nginx / 上游切流量

原则：

- 先数据接管
- 再应用确认
- 最后入口切换

## 11. 日常巡检建议

建议至少每天巡检一次：

1. `104` MySQL `SHOW REPLICA STATUS\G`
2. `104` Redis `INFO replication`
3. AWS Redis 主库 `INFO replication`
4. AWS app 心跳 `/v1/common/heartbeat`
5. `docker compose -f /opt/ppanel/docker-compose.cloud.yml ps`

如果后续要做真正的生产级自动化，再补：

- MySQL 复制延迟告警
- Redis 主从断链告警
- 应用心跳失败告警
- RDS 连接失败告警
- 定期灾备切换演练
