华为云 RDS 数据库服务:MySQL/PostgreSQL 高可用配置指南

托管数据库把运维动作变成了控制台按钮,但没有把判断一并托管。主备切换的那几十秒里应用在干什么,才是"高可用"真正要回答的问题。

技术文章约 13 分钟6 次阅读

托管数据库把安装、备份、版本升级、主从复制这些动作变成了控制台里的按钮和开关——这是它最舒服的一面。最危险的一面在于,这些按钮容易让人误以为判断也被一并托管了。

主备切换是个典型例子:控制台显示"切换已完成,耗时 32 秒",但这 32 秒里应用在做什么、连接池变成了什么状态、有没有请求被静默地算错,都不会出现在那条提示里。本文先从底层机制讲清楚华为云 RDS 高可用的各个组成部分——主备复制、只读副本、备份恢复、参数组、连接与安全组、监控告警、迁移上云,再给出可复现的验证与实施命令。

#一、从自建到托管:RDS 解决了什么,又留下了什么

自建数据库时,从安装引擎、初始化数据目录,到配置复制、调度备份、打补丁、升版本,全部由自己完成。数据库进程本身只是其中一环,围绕它的存储、网络、监控和故障处理才是日常成本的大头。

RDS(Relational Database Service,关系型数据库服务)接管的是"运行数据库"这一层的工程责任:计算资源、存储卷、网络、备份调度、主从复制和版本升级由平台统一管理。但有三件事平台不会替你决定:

  • Schema 与 SQL 质量:表结构、索引、查询写法决定了数据库的真实负载,托管不会改变它们。
  • 参数取舍:平台只开放一部分参数旋钮,其余按规格预设;选什么值仍然取决于业务负载。
  • 连接与容量规划:连接数、并发、数据增长是否超出规格,需要业务侧持续观察。

换句话说,托管改变的是运行环境和运维职责,不是数据库本身:SQL 语义、事务行为、复制机制与自建版本一致,判断和取舍的责任仍然在用户侧。

#二、主备高可用:复制、切换与真实 RTO

#复制与切换的底层机制

主备架构是 RDS 高可用的基础。主库承担读写,备库通过复制持续接收变更:

  • MySQL:备库拉取主库的 binlog(二进制日志)并回放,与自建主从复制同源。
  • PostgreSQL:通过流复制(Streaming Replication)把 WAL(Write-Ahead Log,预写日志)持续传输到备库。

复制模式决定数据一致性上限。半同步复制(semi-sync)要求主库在提交事务前收到备库确认,正常运行时 RPO(Recovery Point Objective,恢复点目标)约为 0;异步复制下,主库故障时可能丢失尚未传到备库的最近事务。选择哪种模式需要在写性能与数据安全之间权衡,实例的默认值与可选范围以官方文档对应版本为准。

故障切换的完整链路是:监控探活发现主库异常 → 选出一个备库并提升为主库 → VIP(虚拟 IP)或 DNS 漂移指向新主库 → 应用侧重新建连。数据库侧完成的只是第一段,用户感知的恢复还包含后面的全过程。

#RTO 是应用的属性,不是数据库的属性

数据库给出的"切换时间"只覆盖它自己那一段耗时,用户感知的恢复时间是从应用开始报错到应用恢复正常的全过程:

数据库侧 RTO:故障检测 + 选主 + 切换
应用侧 RTO:  数据库侧 RTO
              + 连接池发现旧连接已死
              + 重试与退避
              + 缓存/队列积压的消化
              + 可能的会话状态丢失

这个分解解释了为什么很多组织的真实恢复时间远长于数据库侧的数字,瓶颈往往在第二行和第四行:

  • 连接池:连接池里握着的都是指向旧主库的连接,切换后集中失效,所有线程同时开始重连,形成重连风暴(reconnect storm)。特征很鲜明:数据库切换本身很快,但随后连接数瞬间飙升。
  • 积压:如果应用在切换期间把请求堆在队列里而不是快速失败,恢复后会有一波集中冲击,把刚起来的新主库再压一轮。

因此高可用的验证不能只测数据库切换,要测从应用视角看的端到端恢复时间。

#连接池该怎么设

连接池配置与故障恢复直接相关,三条最有价值:

参数在故障中的作用常见错误
maxLifetime / 最大存活时间让连接定期更换,故障时不会有大量"老连接"同时失效设为无限(继承数据库的 wait_timeout),故障时集中失效
连接校验(test-on-borrow)拿连接前先验活,避免把死连接交给业务关闭以求性能,结果错误以"随机的 SQL 异常"形式出现
connectionTimeout决定"等不到连接"多快失败设得过长,把线程全部堵在等待上

最便宜的一招是让连接的最大存活时间短于数据库侧的空闲超时,连接会自然轮换,故障时不会整批同时过期。这一条几乎不花成本,但能显著削弱重连风暴。

#故障切换演练

实例创建并接入应用后,至少做一次受控的主备切换演练。在控制台发起手动主备切换(具体入口以官方文档对应版本为准),同时用下面的脚本持续探测,记录应用视角的不可用窗口:

# 演练期间每 1 秒探测一次数据库连通性,记录端到端不可用窗口
# 建议先执行:export MYSQL_PWD='<password>',避免密码出现在命令行历史
for i in $(seq 1 120); do
  if mysql -h <endpoint> -P <port> -u <user> -e "SELECT 1" >/dev/null 2>&1; then
    echo "$(date +%H:%M:%S) ok"
  else
    echo "$(date +%H:%M:%S) fail"
  fi
  sleep 1
done

同时观察应用日志:重连是否按预期退避、队列积压是否被消化、是否有会话状态丢失。演练结论应落成两个数字:数据库侧切换耗时、应用侧端到端不可用时长。两者之间的差距,就是接下来要优化的部分。

#三、只读副本与读写分离:同步机制与一致性语义

只读副本的同步机制与主备复制同源:只读实例从主库拉取 binlog/WAL 并回放。延迟来自网络往返、只读实例规格与业务写入模式——IO 能力不足会拖慢回放,大事务、长事务、频繁 DDL 都会放大延迟。因此只读实例的规格不能拍脑袋选,要按"回放吞吐"而不是"查询吞吐"评估。

复制延迟会以非常具体的方式暴露给用户:提交表单 → 主库写入成功 → 页面跳转 → 从只读副本读 → 读不到刚才那条记录。监控上延迟是 200ms,用户观感是"我明明提交了"。这不是配置问题,是一致性语义问题。按代价从低到高有三种处理:

  1. 写后读主:刚写入的会话在一段时间内强制走主库。实现简单,但要小心会话粘滞带来的主库压力。
  2. 业务上容忍:识别出"必须立刻看到"的路径走主库,其余路径走副本,需要业务配合。
  3. 强一致读:牺牲扩展性换语义简单,多数互联网业务不需要走到这一步。

判断口径:别把复制延迟当成性能指标,它是正确性指标——它决定用户能不能看到自己刚写下的东西。在控制台的只读实例监控里观察"复制延迟",超过业务可容忍的写后读窗口时,优先排查只读实例规格与慢 DDL,而不是先改 SQL。部分版本允许在只读实例上直接查看复制链路状态:

-- 在只读实例上查看复制状态(可见性以官方文档对应版本为准)
SHOW SLAVE STATUS\G
-- 重点看 Seconds_Behind_Master(延迟秒数)与 Last_SQL_Errno(回放错误码)

#四、备份恢复与时间点恢复(PITR)

托管服务的自动备份解决"有没有"备份的问题,没解决"恢复得对不对"的问题。先说机制:RDS 备份由两部分构成——周期性的全量快照与持续归档的事务日志(MySQL 的 binlog / PostgreSQL 的 WAL)。时间点恢复(Point-in-Time Recovery,PITR)就是把全量快照恢复到某个时刻,再沿日志回放到指定时间点,所以 PITR 能回到多久之前,取决于日志的保留时长,而非快照数量。

值得先做且常被忽略的检查有三条:

  • 恢复演练:至少恢复一次到临时实例,确认数据可用、账号权限正确、连接串能通。
  • PITR 窗口:窗口是 7 天还是 30 天,直接决定你能容忍"多久之后才发现数据被改坏"。一个常见事故形态是三天前的一次错误发布污染了数据,而日志/备份窗口只有 24 小时——这时候快照再多也救不回来。
  • 逻辑备份的独立性:快照类备份与实例同源,删除实例可能连带影响;真正需要长期留存的,要另用逻辑导出存一份到对象存储。

备份保留天数、日志保留时长与 PITR 的可用区间,都在控制台的备份设置中配置,具体取值范围以官方文档对应版本为准。

恢复演练的完整命令链(以 MySQL 为例,先建临时实例再导入):

# 1) 逻辑导出:--single-transaction 在 InnoDB 下取得一致性快照,不锁业务表;
#    --routines/--triggers/--events 保留存储过程、触发器与事件
mysqldump -h <endpoint> -P <port> -u <user> -p \
  --single-transaction --routines --triggers --events \
  <db-name> > backup_$(date +%F).sql

# 2) 导入到恢复演练用的临时实例
mysql -h <restore-endpoint> -P <port> -u <user> -p <db-name> < backup_$(date +%F).sql

# 3) 抽样核对:两侧对同一张业务表计数,确认行数一致
mysql -h <restore-endpoint> -P <port> -u <user> -p \
  -e "SELECT COUNT(*) FROM <db-name>.<table-name>;"

PostgreSQL 使用 pg_dump 与 pg_restore,自定义格式还支持并行恢复以缩短时间:

# PostgreSQL 逻辑备份(自定义格式)与恢复
pg_dump -h <endpoint> -p <port> -U <user> -d <db-name> -Fc -f backup_$(date +%F).dump
pg_restore -h <restore-endpoint> -p <port> -U <user> -d <db-name> -j 4 backup_$(date +%F).dump
# -j 4 表示并行恢复线程数,按恢复实例规格调整

演练结束后删除临时实例,并把"多久恢复一次、恢复到哪"写进运维清单。

#五、参数组:托管只给了一部分旋钮

RDS 的参数通过参数组(参数模板)管理:把一组参数命名保存、绑定到一个或多个实例,既便于批量变更,也便于回退。平台默认值按通用负载设计,通常把内存类参数(如 innodb_buffer_pool_size)按规格预设,用户可在参数组中调整连接数、超时、事务隔离级别等。需注意两点:其一,可改与不可改的清单以官方文档对应版本为准;其二,参数修改有的立即生效、有的需要重启实例,批量变更前先看生效方式。

不同业务用同一个实例模板,参数需求可能完全不同:

负载类型关注点说明
OLTP(短事务、高并发)连接数上限、事务隔离、锁等待连接数上限比 CPU 更常成为瓶颈
分析查询(大表扫描)内存与临时空间一个慢查询就能拖垮同实例的其它业务
混合负载隔离最危险:分析查询的 IO 会挤占在线事务

混合负载是托管数据库最常见的性能事故来源。如果一定要混,至少把分析查询放到只读副本上跑——这也解释了为什么只读副本在运维上经常不是"读扩展",而是"负载隔离"手段。

绑定参数组后,进入实例核对实际生效值:

-- 核对关键参数是否与参数组配置一致
SHOW VARIABLES LIKE 'max_connections';
SHOW VARIABLES LIKE 'wait_timeout';
SHOW VARIABLES LIKE 'transaction_isolation';

#六、连接与安全组

RDS 实例默认位于 VPC 内网,通过安全组控制访问。安全组是最小授权的第一道闸门:只放行应用服务器的私网网段,数据库端口不应暴露到 0.0.0.0/0。以 MySQL 为例:

安全组规则(最小授权原则):
  方向:入方向
  协议:TCP
  端口:3306(MySQL)/ 5432(PostgreSQL)
  源地址:仅应用服务器的私网网段,如 10.0.0.0/24

连接前先做连通性探测,再做一次真实登录,两个命令能区分"网络不通"与"认证失败":

# 端口连通性探测(-w 为超时秒数)
nc -vz -w 3 <endpoint> <port>

# MySQL 真实登录测试
mysql -h <endpoint> -P <port> -u <user> -p --connect-timeout=5 -e "SELECT 1;"

# PostgreSQL 真实登录测试(生产建议启用 SSL,sslmode=require)
psql "host=<endpoint> port=5432 dbname=<db-name> user=<user> sslmode=require" -c "SELECT version();"

公网访问只在确有必要时开启,并配合白名单收紧来源 IP;应用与数据库同 VPC 时应优先走内网,省去公网带宽与额外延迟。

#七、监控与告警

托管平台的监控告警(华为云为云监控 Cloud Eye)覆盖 CPU、内存、磁盘使用率、连接数、QPS/TPS、只读副本复制延迟等指标。阈值设置建议按"先告警后出事"的原则:

  • 磁盘使用率:告警阈值建议明显低于实例上限(如 80%)。磁盘满会导致写入失败,是数据库最典型的"慢启动"故障——从告警到失败之间通常还有清理或扩容的窗口。
  • 连接数:接近 max_connections 即告警。连接耗尽表现为 "too many connections",应用侧是大量连接超时。
  • 复制延迟:阈值取业务可容忍的写后读窗口,如 30 秒或 60 秒。
  • 主备切换事件:任何一次切换都应告警,哪怕控制台显示切换成功——它意味着一次真实的中断。

告警要落到人:绑定通知通道,并明确"收到告警后谁看、看什么、下一步动作"。

#八、迁移上云

迁移路径取决于可接受的停机时间。在线迁移由数据复制服务(DRS)完成:全量拷贝加增量同步,切换前可反复校验,适合对停机敏感的生产库,具体任务流程以官方文档对应版本为准。停机窗口内可完全用命令完成的离线迁移步骤如下:

# 1) 源库导出(一致性快照;若应用可接受短暂停写则最稳妥)
mysqldump -h <source-endpoint> -P 3306 -u <user> -p \
  --single-transaction --routines --triggers --events \
  <db-name> > full_dump.sql

# 2) 目标 RDS 导入
mysql -h <rds-endpoint> -P <port> -u <user> -p <db-name> < full_dump.sql

# 3) 迁移后抽样核对:行数、最新一条记录时间、关键外键
mysql -h <rds-endpoint> -P <port> -u <user> -p \
  -e "SELECT COUNT(*) FROM <db-name>.<table-name>;"

迁移完成的判定不是"导入成功",而是应用切流后的观察:连接串已切换、慢查询体感一致、日志无认证或权限报错。

#九、边界与建议

本文没有覆盖的内容同样重要,避免误用:

  • 具体控制台步骤与参数名:各版本界面差异大,请以官方文档对应版本为准。
  • SQL 调优与索引设计:那是应用侧的功夫,与是否托管无关,值得单独成文。
  • 分布式数据库(分库分表、NewSQL):那是单实例高可用之后的另一个阶段,混在一起会模糊掉边界。
  • 版本/规格选型:取决于负载画像与兼容性要求,没有脱离场景的答案。

一句话收束:托管服务把动作托管了,没有把判断托管。上线前值得问一句:切换发生的那几十秒里,我的应用会做什么?如果答不上来,这套高可用还只是纸面上的。

相关阅读

Related

留言讨论

0 条

还没有留言,来说点什么吧。

华为云 RDS 数据库服务:MySQL/PostgreSQL 高可用配置指南 · LXH·BLOG