Oracle RAC、Data Guard与双机热备:故障域与选型边界
数据库这行干久了,总有人跑来问同一类问题:我们这套系统要上高可用,到底该选 Oracle RAC 还是双机热备?Data Guard 是不是也算高可用?三个词经常被混着用,甚至有人以为 DG 就是 RAC 的简化版。实际情况完全不是这么回事——双机热备(HA)、Oracle RAC、Data Guard,它们解决的是三个不同层面的问题,一个保服务、一个保实例、一个保数据。你要是没搞清楚它们各自的故障域在哪儿,花了大价钱搭出来的架构,真出事那天可能一点用都没有。
这篇内容我按自己的理解把三者拆开讲透:每种方案在保什么、不保什么,切换时间到底花在哪些环节,私网带宽和 SRL 大小这些参数怎么算,以及什么情况下必须组合使用。面向的是正在做架构选型的 DBA、运维负责人,还有刚接触 Oracle 高可用体系、想搞清楚这几个概念边界的同学。文中会给到可直接参考的配置片段和检查清单,也会把我在实际项目里踩过的坑摊开说。
1. 三个词经常被混着用,先把它们摆到同一张桌子上
在架构评审会上听到“我们上了 RAC 所以不怕宕机”这种说法,我一般会追问一句:机房断电呢?存储阵列挂了怎么办?RAC 挡不住的东西太多了。把三个概念混为一谈,最容易导致的结果就是容灾演练那天发现切换不了,或者切换过去数据少了半小时。
所以先做一件事:给每个方案划一条清晰的“责任边界”。这条边界不看厂商宣传页,只看故障发生时,它到底能不能把业务接住。
1.1 双机热备(HA):保的是“服务别断太久”
双机热备的本质非常简单:两台服务器,一份数据,同一时刻只有一台在对外提供服务,另一台待命。数据放在共享存储上,或者用软件做块级镜像。对外暴露一个虚拟 IP,谁提供服务这个 IP 就挂在谁身上。
它的价值在于把单台服务器的硬件故障、操作系统崩溃、数据库实例意外退出这些“局部故障”兜住。检测到故障,集群软件把资源(IP、存储挂载、数据库实例、监听)在另一台机器上拉起来,业务方重新连接就能用。
关键点在于“重新连接”这四个字。HA 方案下,故障切换期间连接是断的,已经在跑的事务是回滚的,客户端必须自己实现重连逻辑。至于断开多久,取决于你的实例启动速度和崩溃恢复时间,快的一两分钟,慢的七八分钟都有。这是它和 RAC 最本质的差别,很多人做选型时恰恰忽略了这一点。
1.2 Oracle RAC:保的是“实例别全挂”
RAC 的模型是:一个数据库,多个实例,共享同一份存储。每个节点跑一个实例,实例之间通过私有网络交换数据块,这个机制叫 Cache Fusion。任何一个节点挂了,挂在它上面的会话会被其他节点接管(配合 TAF 或应用连续性),数据库本身还在,不需要重新启库。
这就意味着 RAC 的切换是“秒级到分钟级”的,而且不需要经历完整的实例启动和介质恢复流程——存活节点直接把挂掉节点的 undo 回滚掉就行,会话在别的节点重新执行。
RAC 顺带还给了横向扩展能力:读多写少的场景下,加节点确实能分担连接数和部分查询压力。但要注意,RAC 不是“写扩展”方案,写压力大、热点集中的系统上 RAC,加节点可能反而让争用更严重。这一点后面单独说。
RAC 挡不住的:共享存储整体故障、机房断电、人为误删数据、存储链路双断。所以它再强,也只是“本地高可用”。
1.3 Data Guard:保的是“数据别丢”
DG 走的是完全不同的路子——日志复制。主库产生的 redo,通过网络传到备库,备库重演。备库是一份独立的、完整的数据库副本,有自己的存储、自己的实例。
它天然解决的是“机房级”问题:主库所在机房整体不可用,备库可以切过去。同时也解决人为误操作——主库被误删表,备库因为有延迟应用,还能捞回来。
但 DG 的短板也很明确:备库通常是 mount 状态(除非开 Active Data Guard 做只读),它不承担业务流量,也不能像 RAC 那样做实例级快速接管。主库实例崩了,DG 不会自动帮你把业务接到备库上——除非你额外配了 Fast-Start Failover 加 Observer。很多人以为配了 DG 就万事大吉,结果主库实例挂掉,业务停了四十分钟,因为没人手动执行切换。
1.4 一张表看清楚三者的边界
| 维度 | 双机热备(HA) | Oracle RAC | Data Guard |
|---|---|---|---|
| 冗余层级 | 服务器 / 实例 | 实例 + 节点 | 数据库 / 存储 |
| 共享一份数据 | 是(共享存储或镜像) | 是(共享存储) | 否(独立副本) |
| 故障切换粒度 | 整机接管 | 会话级接管 | 数据库级切换 |
| 典型切换时间 | 2~10 分钟 | 30 秒~2 分钟 | 30 秒~数分钟(FSFO)/ 手动更久 |
| 连接是否中断 | 中断,需重连 | 部分中断,TAF 可重连 | 切换时中断 |
| 能否防机房级故障 | 否(同机房内) | 否 | 是 |
| 能否防误删数据 | 否 | 否 | 是(延迟应用) |
| 能否横向扩展读 | 否 | 是 | 是(ADG 只读分流) |
| 运维复杂度 | 低 | 高 | 中 |
| 典型成本 | 低 | 高(授权 + 硬件 + 人力) | 中(需独立存储和授权) |
这张表建议直接存下来,下次评审会用得上。看表就能发现,三者根本不在一个维度上打架,硬要比“谁更好”是没有意义的。
2. 双机热备:最便宜,也最容易被想当然
我见过太多项目把双机热备用成了“心理安慰”——装上了,测试过一次手动切换成功,然后就再也没碰过。真出事那天,脚本报错、共享存储挂载失败、VIP 漂移到了错误的网卡,各种问题一起冒出来。
HA 方案本身不复杂,但它的可靠性高度依赖细节:备机的状态、切换判定的逻辑、资源的依赖顺序、失败后的回退路径。这些地方任何一处没处理干净,整套方案就是纸糊的。
2.1 冷备、温备、热备,差的不只是启动速度
按备机的“热度”分三档,实际项目里选哪档,直接决定了故障恢复时间。
冷备:备机平时关机或者只装好系统,数据库软件都没起。主库挂了,人去开机、挂存储、启实例。这种模式恢复时间以小时计,现在基本只用于非核心系统或者预算极度受限的场景。
温备:备机操作系统在跑,集群软件在跑,但数据库实例没启动。切换时集群软件负责把实例拉起来。恢复时间主要消耗在实例启动和崩溃恢复上,通常 3~8 分钟。这是最常见的形态。
热备:备机数据库实例已经启动,处于 mount 或 recovery 状态,redo 持续应用。切换时省掉了实例启动这一大段,只需要做最后的恢复和 open,时间可以压到 1~2 分钟。代价是备机要常驻内存和 CPU,且需要一个机制保证备库的 redo 来源(通常是共享存储上同一份归档)。
从成本收益看,绝大多数业务系统用温备就够了。要求恢复时间进 2 分钟以内的,其实该考虑 RAC 或者 DG 的 FSFO,而不是硬把 HA 做成热备——因为热备的复杂度已经接近 RAC 了,但收益差得远。
2.2 共享存储、数据镜像和虚拟 IP 的组合方式
HA 的数据层有三种常见做法,选哪种影响很大。
共享存储:两台机器挂同一个 LUN,靠集群软件的 fencing 机制保证同一时刻只有一台能挂载。这是最主流的方式,可靠、性能好。前提是存储本身别是单点——现实中很多项目存储只有一台,那 HA 只解决了服务器故障,存储故障照样全挂。
块级镜像:两台机器各自本地盘,用 DRBD 这类工具做实时块同步。省掉了共享存储的钱,但同步链路的延迟会直接打在写性能上,而且脑裂风险比共享存储更高(因为没有第三方仲裁)。适合预算紧、写入量不大的系统。
存储双活:两台存储阵列做双活,服务器多路径访问。这是最高级的形态,成本也最高,一般只在核心系统上用。
虚拟 IP 是另一个必谈的点。业务方连的必须是 VIP,不能是物理机 IP,否则切换后客户端改配置得改到天亮。VIP 的漂移由集群软件控制,要保证漂移后 ARP 能及时刷新,否则会出现“IP 已经在新机器上,但客户端还往旧机器发包”的尴尬情况。这个问题在老式交换机和某些虚拟化环境下特别容易碰到。
注意:VIP 一定要和应用的连接串绑定,同时把
SQLNET.EXPIRE_TIME配上(一般 10 分钟),让死连接能被及时清理,否则切换后连接池里全是僵死会话。
2.3 脑裂是这套方案的头号杀手
脑裂指的是:两台机器之间的心跳断了,但双方都还活着,都认为自己应该是主,于是同时去挂载共享存储、同时启动数据库。结果就是存储上的数据被两个实例同时写,轻则文件系统损坏,重则整个数据库报废。
防止脑裂靠三样东西:
第一是仲裁机制。心跳走多条路径(网线直连 + 交换机),任何一条通就不算失联。再加一个仲裁盘或者仲裁节点,投票决定谁是主。
第二是fencing(隔离)。这是最关键的一环。判定对方失联后,必须先想办法把对方“弄死”或者把它的存储访问切断,再接管资源。常见手段有 SCSI reservation(通过存储命令锁住 LUN)、STONITH(电源管理口强制断电)、SAN fence。没有 fencing 的 HA 方案,本质上是不安全的。
第三是资源启动前的二次确认。接管脚本里加一步:检查共享存储上有没有锁文件、检查数据库是否有其他实例在跑,确认无冲突再启动。
我见过一个项目为了省事,把 fencing 关掉了,理由是“我们两台机器心跳很稳”。后来机房整改,误拔了一根网线,两台机器同时挂载存储,恢复花了整整两天。
2.4 切换时间到底花在哪儿:一次实测拆解
拿一个典型的温备环境举例,配置是两台 16 核 64G 的机器、共享存储、数据库实例约 500GB、日常 redo 生成量约 8GB/小时。手动触发切换,秒表记录各个环节:
| 环节 | 耗时 | 说明 |
|---|---|---|
| 故障检测 | 10~30 秒 | 心跳超时判定,取决于advert_int和dead_ratio |
| fencing 执行 | 3~10 秒 | 切断对端存储访问或强制关机 |
| 释放旧资源 | 5~15 秒 | 卸载文件系统、清理锁、停监听 |
| 挂载存储 | 5~20 秒 | 取决于 LUN 数量和文件系统检查 |
| 启动实例 | 20~40 秒 | 参数文件加载到 nomount → mount |
| 崩溃恢复 | 60~180 秒 | 回滚未提交事务,取决于 redo 量和检查点间隔 |
| 打开数据库 | 5~15 秒 | open 阶段 |
| VIP 漂移 + ARP 刷新 | 3~10 秒 | 交换机 MAC 表更新 |
| 应用重连 | 不定 | 取决于连接池配置和重试策略 |
加起来,2 到 5 分钟是常态。崩溃恢复这一项波动最大,如果主库刚做完大批量 DML 就挂了,redo 里有大量未提交事务要回滚,时间会明显拉长。
这也是为什么我建议把fast_start_mt_target设一个合理值(比如 300 秒),让检查点更积极一些,把崩溃恢复时间控制在可预期范围内。代价是正常运行时的写放大,需要在两者之间找平衡。
2.5 实操:一个能跑起来的 VIP 漂移配置
用 Keepalived 做 VIP 管理是最轻量的做法,配合自定义脚本拉起数据库资源。下面是一个可以直接参考的骨架,网段和密码自行替换:
vrrp_instance VI_DB { state BACKUP interface eth0 virtual_router_id 51 priority 100 advert_int 1 nopreempt authentication { auth_type PASS auth_pass ReplaceMe } virtual_ipaddress { 192.168.10.100/24 dev eth0 } notify_master "/opt/ha/scripts/to_master.sh" notify_backup "/opt/ha/scripts/to_backup.sh" notify_fault "/opt/ha/scripts/to_fault.sh" }几个要点解释一下。
state两边都写BACKUP,配合nopreempt,是为了避免原主库恢复后抢占 VIP 导致二次切换。优先级高的只是“更愿意当主”,但恢复后不主动抢,业务稳定性更好。
advert_int 1是心跳间隔 1 秒,配合默认的dead_ratio,故障检测大约在 3~4 秒内完成。这个值不要调太小,网络抖动会造成误切换。
to_master.sh里做的事要按依赖顺序来:先确认存储可挂载(检查锁文件),再挂载文件系统,再启动数据库实例,最后确认监听正常。任何一步失败都要立即退出并告警,不能继续往下走。
#!/bin/bash # to_master.sh 简化示例 LOCK_FILE=/shared_ha/ha.lock if [ -f "$LOCK_FILE" ] && [ "$(cat $LOCK_FILE)" != "$(hostname)" ]; then logger "HA: 检测到锁文件属于其他节点,放弃接管" exit 1 fi echo "$(hostname)" > "$LOCK_FILE" mount /dev/mapper/dbdata /u01/app/oracle/oradata || exit 1 su - oracle -c "srvctl start database -d ORCL" || exit 1 su - oracle -c "lsnrctl start" || exit 1 logger "HA: 接管完成"切换前一定要演练,而且不是演练一次。我一般建议每季度跑一次真切换,把应用方也拉进来,验证连接池能不能自动恢复。演练的价值远大于任何文档。
3. Oracle RAC:横向扩展和高可用被绑在了一起
RAC 是这三者里最容易被神化的方案。销售说它“永不宕机”,实际上 RAC 只是把单实例的故障域从“一台机器”缩小到了“一个实例”,共享存储、集群网络、OCR 投票盘这些环节任何一个出问题,整个集群都得停。
但 RAC 确实有它的不可替代性:会话级接管、秒级响应、读扩展。这些优势在交易类、高并发连接的场景下非常值钱,关键是要搞清楚它的成本结构。
3.1 架构拆开看:四层各管什么
RAC 的架构可以拆成四层,从上往下理解会清楚很多。
客户端层:应用通过 SCAN VIP 连接,SCAN 监听把连接分发给各个节点的 VIP。节点故障时,VIP 会漂到存活节点,SCAN 重新把连接引导过去。这是 RAC 对外“看起来像一个数据库”的关键。
集群层(Grid Infrastructure):负责节点成员管理、心跳、资源管理、VIP 管理、ASM 管理。核心组件包括 OHASD、CSSD(集群同步服务)、CRSD(资源管理)、EVM(事件管理)。CSSD 负责心跳和节点驱逐,是 RAC 里最敏感的进程,它出问题整个节点会被踢出集群。
实例层:每个节点一个实例。实例之间通过私有网络做 Cache Fusion,共享 SGA 里的数据块。这一层是 RAC 的技术核心,也是绝大部分性能问题的来源。
存储层:ASM 管理共享磁盘,做条带化和镜像。所有节点的数据文件、redo、控制文件都在 ASM 上,物理上只有一份。ASM 的冗余模式(NORMAL 双副本、HIGH 三副本)决定了能容忍几块盘坏掉。
这四层里,存储层是真正的单点——如果存储阵列整体挂了,ASM 再强也没用。所以核心系统上 RAC,存储必须做冗余(双控制器 + 双链路 + 双活或远程复制),不能只靠 ASM 的盘级冗余。
3.2 Cache Fusion 决定了私网比存储还金贵
理解 RAC 性能瓶颈,抓住一个概念就够了:任何数据块的访问,都要经过“当前持有者”。
节点 A 修改了数据块,这个块在 A 的 SGA 里标记为脏。节点 B 要读这个块,不能直接从磁盘读(那样会读到旧数据),必须通过私网向 A 请求,A 把这个块的当前版本传过来。这个传输过程就是 Cache Fusion。
带来的结果是:节点间交互量直接决定了 RAC 的性能天花板。典型等待事件里,gc cr block 2-way、gc current block 2-way、gc buffer busy acquire这几个都是 Cache Fusion 相关的。如果私网延迟高、带宽不够,这些等待会迅速堆积,表现就是“明明是两台机器,性能还不如单机”。
设计 RAC 私网有两条硬性建议:
- 物理上至少两条独立链路,走不同交换机,做绑定(bonding),避免单点。
- 私网不要和公网混跑,也不要用虚拟化环境下的共享虚拟交换机,延迟不可控。
还有一个容易忽略的点:节点间时钟必须同步。RAC 依赖 CTSS(集群时间同步服务)保证各节点时间一致,如果时钟漂移过大,事务顺序会乱,严重的会导致数据不一致。CTSS 自身会做同步,但要确保它的告警被接住。
3.3 私网带宽和延迟的实际算法
很多人做容量规划时直接拍一个“万兆就够了”,其实有个简单的估算方法。
先算峰值数据块交互速率。假设业务峰值 IOPS 是 20000,平均块大小 8KB,其中需要跨节点传输的比例假设 30%(这个比例取决于业务的数据分布,两个节点跑完全不同的业务模块可以接近 0,跑同一套业务的能到 50% 以上):
20000 IOPS × 8KB × 30% = 48000 KB/s ≈ 48 MB/s ≈ 384 Mbps再乘一个峰值系数(业务尖峰的瞬时并发往往是均值的 3 倍左右):
384 Mbps × 3 = 1152 Mbps ≈ 1.2 Gbps所以万兆私网在大多数场景下是够的,双万兆绑定更稳妥。但如果你的跨节点请求比例超过 60%,或者单块交互非常频繁(比如大量全表扫描走了错误的执行计划),私网很容易被打满。
延迟方面,要求比带宽更严格。同机房内网延迟应该控制在 0.5ms 以内,超过 1ms 就会明显影响 Cache Fusion 效率。这也解释了为什么跨机房 RAC(所谓的“延伸集群”)只在极少数场景下被接受——光纤延迟加上网络设备处理,很容易突破 1ms。
验证方法很直接,在节点间跑 ping 和网络带宽测试,看 P99 延迟而不是平均值:
ping -c 100 -i 0.2 node2-priv # 关注 max 和 stddev,平均值没意义3.4 一个节点宕机后,剩下的节点做了什么
这个流程值得完整走一遍,因为它直接决定了 RAC 的切换时间。
第 1 阶段,心跳超时:存活节点在设定时间内(默认约 30 秒,取决于misscount)没有收到故障节点的心跳,判定其失联。
第 2 阶段,节点驱逐:集群层通过 fencing 机制(I/O fencing 或 reboot)确保故障节点不会继续写共享存储。这一步必须成功,否则有数据损坏风险。
第 3 阶段,资源重配:故障节点的 VIP 漂移到存活节点,SCAN 重新注册。ASM 实例重新计算磁盘归属。
第 4 阶段,事务恢复:存活节点读取故障节点的 undo 段,回滚它未提交的事务。这一阶段叫 instance recovery,是耗时最长的一环,取决于故障节点在挂之前产生了多少脏块。
第 5 阶段,客户端重连:配置了 TAF 的会话会被自动重连到存活节点;没配的只能应用自己重试。
整个流程下来,VIP 漂移通常在 30~90 秒内完成,但事务恢复可能要几分钟。这期间业务上是“部分可用”的状态——已经连到存活节点的会话不受影响,挂在故障节点上的会话要等恢复。
所以 RAC 的“秒级切换”要打个引号:网络层和连接层确实很快,但数据层恢复不是瞬时的。宣传资料里说的“零中断”只在配置了 Application Continuity 的特定场景下才成立。
3.5 RAC 带来的新麻烦:争用
上了 RAC 之后,原本在单机上跑得好好的系统可能出现性能下降。这不是玄学,原因是原来不存在的争用被引入进来了。
序列争用:SELECT seq.NEXTVAL在单机上只是内存操作,在 RAC 上要跨节点同步,默认缓存 20 个值根本不够。解决办法是加大 cache(比如CACHE 1000 NOORDER),或者用可扩展序列。
索引块争用:单调递增的索引(比如用序列做主键),所有插入都打在最右侧的叶子块上。单机上是“热点块”,RAC 上就变成“跨节点热点块争用”,表现为gc buffer busy acquire飙高。解决办法是反向键索引、hash 分区索引,或者干脆用 UUID 主键。
全表扫描的 Cache Fusion:一个节点做全表扫描,把大量块加载到自己的 SGA,另一个节点再扫同样的表时,可能要从对方那里拉,或者触发 remastering。大表扫描最好做分区,让不同节点访问不同分区。
节点亲和性:如果两个节点跑同一套业务,块在节点间来回传递的次数会非常多。更好的做法是按业务模块划分节点,让数据和访问尽量“本地化”。这个要靠服务(Service)配置来实现,把不同的应用连到不同的服务名上。
提示:上线前一定要跑一遍 AWR 的全局视图,重点看
gv$cr_block_server、gv$gc_element和gv$active_session_history里的 gc 类等待,别只看单实例的本地视图。
3.6 实操:部署前必须逐项打勾的检查清单
RAC 部署失败大多数不是技术问题,是准备不充分。下面这份清单是我按实际项目整理的,建议逐项打勾。
| 检查项 | 具体要求 | 常见失误 |
|---|---|---|
| 操作系统版本 | 在认证矩阵内,所有节点完全一致 | 混用不同小版本内核 |
| 主机名与 IP | 禁止使用保留字符,SCAN 独立解析 | 用了_导致监听起不来 |
| 时钟同步 | 所有节点指向同一时间源 | 有一台漏配,CTSS 报警 |
| 共享存储 | 多路径配置正确,权限一致 | 权限差异导致 ASM 起不来 |
| 私网 | 独立网段,双向可达,延迟 < 1ms | 和公网混在一块网卡上 |
| 内核参数 | shmmax、shmall、sem等按内存计算 | 直接抄文档没按实际内存算 |
| 用户与组 | UID/GID 所有节点必须一致 | 一台 54321 另一台 54322 |
| 防火墙 | 集群端口全部放行 | 开了防火墙没加规则 |
| 磁盘预留 | 预留盘给 OCR 和投票盘 | 和 DATA 盘混用 |
部署完成后跑一遍验证:
crsctl check crs crsctl stat res -t olsnodes -n -s oifcfg getif srvctl status database -d ORCL cluvfy stage -post crsinst -n node1,node2 -verbosecluvfy的输出不要走马观花看“passed”,要逐个看 warning 项。很多问题当时不影响启动,但在高负载或者故障切换时才会暴露出来。
4. Data Guard:护数据,不护服务
很多人对 DG 的期待是错的。以为配了 DG,主库挂了业务自动切过去。实际上默认配置下 DG 什么都不会做,它只是安静地在那边应用日志,等你发指令。
DG 的价值要放在正确的位置上看:它是数据级容灾,是最后一道防线。当 RAC 挡不住(存储整体故障)、双机热备挡不住(机房级故障)、人为误操作挡不住(误删误改)的时候,DG 是唯一能兜住的。
4.1 三种保护模式,本质是在可用性和数据零丢失之间做选择
DG 有三种保护模式,选择哪一种,等于在“数据丢多少”和“主库能不能继续写”之间做一个权衡。
最大保护(Max Protection):主库的每次提交,必须等到至少一个备库确认 redo 已写入 standby redo log,才返回成功。数据零丢失,但代价是备库一旦不可达,主库直接停止写入。这个模式在生产环境用得很少,因为网络抖动就会导致业务停摆。
最大可用(Max Availability):同样是同步传输,但备库不可达时自动降级为异步,主库继续跑,等备库恢复后再追平。这是折中方案,核心交易系统比较常用。降级期间如果主库再出问题,会丢数据,这个风险要业务方明确接受。
最大性能(Max Performance):默认模式,异步传输,主库提交不等备库。性能最好,但主库崩溃时可能丢最近一段时间的 redo。同城场景下丢秒级,异地场景下可能丢分钟级。
选择逻辑其实很清楚:能接受丢多久的数据,就选对应的模式。不要因为“听说最大保护最安全”就上最大保护,那是对业务的不负责。
4.2 物理备库、逻辑备库、快照备库怎么挑
物理备库是绝对主流,块级复制,备库和主库完全一致,应用日志就是介质恢复。性能开销小,可靠性高,几乎所有容灾场景都用这个。
逻辑备库通过 SQL Apply 重演,备库可以和主库有不同结构(比如少几个索引、多几个物化视图)。它的独特价值是支持滚动升级——先升备库,再 switchover,主库停机时间可以压缩到几分钟。代价是维护复杂,对数据类型有限制(不支持某些类型),且性能开销大。
快照备库是物理备库的一个特殊状态,可以临时打开读写用于测试,测试完丢弃变更,再回到备库状态。做版本验证、报表压测时很方便,但要严格控制使用流程,一旦有人忘了回退,备库就废了。
选型建议:容灾一律物理备库;有滚动升级需求再加一个逻辑备库;测试环境用快照备库,但必须走审批。
4.3 redo 从主库到备库的完整链路
理解这条链路,DG 的问题排查就有章法了。链路上任何一个环节断了,备库就会落后,落后到一定程度就叫“归档缺口”(gap)。
第 1 环,主库生成 redo:LGWR 把 redo buffer 写到 online redo log。
第 2 环,传输进程读取:LNSn 进程(或 ARCH 进程)读取 online redo log,通过log_archive_dest_2配置的服务名发往备库。用 LGWR 传还是 ARCH 传,差别很大——LGWR 传是实时的,ARCH 传要等日志切换,延迟可能到几十分钟。
第 3 环,备库接收:备库的 RFS 进程接收 redo,写入 standby redo log(SRL)。
第 4 环,应用进程重演:MRP 进程(Managed Recovery Process)从 SRL 或归档日志里读 redo,做介质恢复。
链路上四个环节,任何一环出问题都表现为“备库延迟”。排查顺序应该是:先看主库的v$archive_dest_status,再看备库的v$managed_standby,最后看告警日志。这个顺序是从源头往后找,效率最高。
4.4 SRL 大小和传输带宽的估算过程
SRL 的作用是在备库接收 redo 时有个缓冲,防止网络抖动导致日志直接落到归档目录。它的大小直接决定了备库能容忍多长时间的传输中断。
估算公式:
SRL 总大小 ≥ 峰值 redo 生成速率 × 可容忍中断时长 × 冗余系数举例:某系统峰值 redo 生成速率 20 MB/s,希望容忍 30 分钟的网络中断,冗余系数取 1.2:
20 MB/s × 1800 s × 1.2 = 43200 MB ≈ 42 GBOracle 建议 SRL 至少和最大 online redo log 一样大,一般配置 4~8 组。按 42GB 分摊,每组 8GB、配 6 组,一共 48GB,比较合适。
再看传输带宽。峰值 redo 20 MB/s 对应 160 Mbps,考虑重传和协议开销,同城专线至少配 500 Mbps,异地按 2~3 倍冗余配。注意这是持续带宽,不是突发带宽——专线买小了,redo 会一直积压,延迟越来越大。
同城场景还要关注延迟。同步模式下,主库每次提交都要等备库确认,备库往返延迟直接加在主库的事务响应时间上。要求控制在 5ms 以内,最好 2ms 以内。超过 10ms,业务方会明显感觉到提交变慢。
4.5 实操:主备库的关键参数落地
下面这一段是主库上的核心配置,备库对应调整角色参数。库名、服务名按实际替换:
-- 主库:配置向备库传输 ALTER SYSTEM SET log_archive_dest_2 = 'SERVICE=std lgwr SYNC AFFIRM VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=std' SCOPE=BOTH; ALTER SYSTEM SET log_archive_dest_state_2 = 'ENABLE' SCOPE=BOTH; ALTER SYSTEM SET standby_file_management = 'AUTO' SCOPE=BOTH; ALTER SYSTEM SET fal_server = 'std' SCOPE=BOTH; ALTER SYSTEM SET fal_client = 'prim' SCOPE=BOTH; ALTER SYSTEM SET db_unique_name = 'prim' SCOPE=BOTH;几个参数的用意说明一下。
lgwr SYNC AFFIRM表示用 LGWR 进程同步传输并等待确认,这是最大可用模式的基础。如果改成ARCH,就退化成最大性能模式了。
VALID_FOR限定只在主库角色下生效,切换后不会误用。
FAL_SERVER和FAL_CLIENT是 gap 自动修复的关键。备库发现日志缺失时,会向FAL_SERVER请求补齐。这两个参数配错,gap 就永远修不上,只能手工拷贝日志文件——非常痛苦。
standby_file_management设为 AUTO,主库加数据文件时备库会自动创建,不然每次加表空间都要手动处理。
如果要配自动切换(Fast-Start Failover),还需要在备库上配置:
ALTER DATABASE SET FastStartFailoverThreshold = 30; ALTER DATABASE SET FastStartFailoverTarget = 'std'; ALTER DATABASE SET FastStartFailoverPingInterval = 10; ALTER DATABASE SET FastStartFailoverLagLimit = 30; ALTER DATABASE SET FastStartFailoverAutoReinstate = TRUE;FastStartFailoverThreshold = 30是 Observer 连续 30 秒联系不上主库才触发切换。这个值不能太小,否则网络抖动就会误切;也不能太大,否则业务停太久。30 秒是个比较常用的起点。
FastStartFailoverLagLimit = 30表示备库延迟超过 30 秒就不允许自动切换,避免切过去丢太多数据。这个值要和业务方对齐。
4.6 Switchover 和 Failover 不是一回事
这两个词经常被混用,实际差别很大,做演练时必须区分。
Switchover是有计划的角色互换,主备都健康,先让主库变成备库角色,再让备库变成主库。全程不丢数据,可以反复做。这是演练和升级时的标准动作。
Failover是主库不可用时的强制切换,有数据丢失风险。执行之后,原来的主库必须通过闪回或者重建才能回到集群。
演练的时候只做 Switchover 是没用的,因为真实故障走的是 Failover 路径,两者涉及的操作和风险完全不同。我建议每年至少做一次真正的 Failover 演练,在隔离环境里跑,把流程完全走通一遍,包括后续如何把原主库重新接回来。
注意:Failover 之后如果原主库还能启动(比如只是实例崩溃),千万不要直接把它加回配置。必须先做闪回(
FLASHBACK DATABASE TO BEFORE RESETLOGS)或者用 RMAN 重建,否则会出现双主,数据直接废掉。
5. 别把 RAC 和 DG 当竞品:它们解决的是两个维度的问题
讨论到这儿,答案其实已经出来了:RAC 和 DG 从来不是二选一的关系。RAC 解决的是“本地实例级故障”和“读扩展”,DG 解决的是“站点级故障”和“数据保护”。真实的生产架构里,两者是叠加使用的。
而双机热备,是 RAC 的低成本替代品——预算不够上 RAC,又需要本地高可用时,HA 是合理选择,代价是切换时间和连接中断。
5.1 故障域决定了你必须组合使用
把常见故障按影响范围列一下,就能看出为什么单一方案不够。
| 故障类型 | 双机热备 | RAC | DG |
|---|---|---|---|
| 单台服务器硬件故障 | 能兜住 | 能兜住 | 不接管服务 |
| 数据库实例崩溃 | 能兜住 | 能兜住 | 不接管服务 |
| 单块磁盘损坏 | 存储层冗余 | ASM 冗余 | 无关 |
| 共享存储整体故障 | 全挂 | 全挂 | 能接管(切换到备库) |
| 机房断电/网络中断 | 全挂 | 全挂 | 能接管 |
| 人为误删数据 | 无能为力 | 无能为力 | 延迟应用可恢复 |
| 勒索软件加密数据 | 无能为力 | 无能为力 | 备库可保留干净副本 |
| 大版本升级 | 停机时间长 | 可滚动升级 | 可先升备库再切换 |
看最后三行就知道,DG 的价值不在“快”,在“稳”和“能回退”。这也是为什么金融、电信这类行业的核心系统,哪怕已经上了 RAC,也一定会配 DG。
5.2 一个典型的同城加异地拓扑
大部分核心系统的落点是:生产中心 RAC + DG 到同城灾备 + DG 到异地灾备。
生产中心两个节点跑 RAC,本地高可用交给 ASM 和集群层。数据通过 DG 同步到同城灾备(最大可用模式),网络延迟控制在 2ms 以内,主库提交等确认,数据零丢失。同时再异步传一份到异地(最大性能模式),防止城市级灾难。
这套架构的切换路径要提前定义清楚:
- 单节点故障:RAC 自动接管,不需要人工介入。
- 生产存储故障:整个 RAC 集群不可用,切换到同城备库,RTO 目标 10~30 分钟。
- 同城整体灾难:切换到异地备库,RTO 目标 1~4 小时,RPO 目标分钟级。
每条路径都要有对应的操作手册,写清楚谁决策、谁执行、怎么验证、怎么回切。手册要定期更新,因为人员会流动,环境会变化。
5.3 选型决策表:按业务要求倒推架构
与其纠结哪个方案先进,不如从业务要求倒推。下面这张表可以直接拿去用:
| 业务要求 | 推荐架构 |
|---|---|
| RTO > 30 分钟,RPO > 1 小时,预算有限 | 双机热备 + 定期备份 |
| RTO 5~30 分钟,数据不能丢 | 双机热备 + DG(同步) |
| RTO < 5 分钟,连接不能大范围中断 | RAC + DG |
| 需要读扩展,且写入量中等 | RAC(配合服务划分) |
| 写入量极大,热点集中 | 单实例 + 高性能存储 + DG,慎上 RAC |
| 有严格监管要求,必须有多份异地副本 | RAC + 同城 DG + 异地 DG |
| 开发测试环境需要快速回滚 | 快照备库或存储快照 |
最后一行特别提醒一下:写入量极大的 OLTP 系统,上 RAC 之前一定要做压测和 Cache Fusion 评估。我见过一个订单系统,单实例跑得很稳,迁到 RAC 后 TPS 反而降了 20%,原因就是自增主键导致的索引块争用。这种情况不如老老实实单实例加更强的硬件,容灾交给 DG。
5.4 成本这笔账要算清楚
技术选型绕不开成本,这里把大头列一下。
RAC 的成本:RAC 本身在标准版里是包含的,但如果用企业版,RAC 和 ASM 都是额外收费选项,按处理器核心数计费。再算上至少两台高性能服务器、共享存储、双万兆交换机、私网链路,硬件成本大概是单实例方案的 2.5~3 倍。还有一块隐形成本:RAC 的运维门槛高,出问题排查链条长,需要专职 DBA 或者团队支撑。
DG 的成本:需要一套独立的存储和服务器(备库可以配置降低,但存储空间要和主库相当)。企业版里 Active Data Guard 是额外选项,但基础 DG 功能是包含的。主要成本是硬件和专线。
双机热备的成本:最低。两台服务器 + 共享存储(或者本地盘做镜像),加上集群软件的授权(也有开源方案免费)。运维相对简单。
账算完会发现,钱主要花在“能不能扛住机房级故障”上,而不是“切换快不快”。这也是为什么很多项目最终选了“HA + DG”而不是“RAC + DG”——业务能接受几分钟的切换,但接受不了丢数据。
6. 常见问题和排查实录
架构方案写得再漂亮,落地时都会遇到各种问题。这一节按方案分类,把高频问题整理成速查表,再补充几个我印象比较深的实例。
6.1 问题速查表
| 现象 | 可能原因 | 排查方向 |
|---|---|---|
| HA 切换后 VIP 不通 | ARP 缓存未刷新 | 检查交换机 MAC 表,缩短 ARP 老化时间 |
| HA 两边同时挂载存储 | fencing 未配置或失效 | 检查集群软件日志,确认隔离动作是否执行 |
| RAC 节点频繁被驱逐 | 私网心跳不稳或负载过高 | 查cssd日志、私网丢包率、CPU 是否被打满 |
| RAC 性能不如单机 | Cache Fusion 争用 | 查 gc 类等待事件,评估服务划分 |
| RAC 节点时间漂移 | CTSS 异常 | 检查crsctl stat res -t里 CTSS 状态 |
| DG 备库延迟持续增长 | 传输链路带宽不足或应用跟不上 | 分别查v$archive_dest_status和v$managed_standby |
| DG 出现归档缺口 | FAL 参数配置错误或日志已删除 | 查看告警日志里的 gap 提示,确认 FAL_SERVER |
| DG 切换后备库起不来 | 控制文件或参数文件角色未切换 | 检查v$database的database_role |
| DG 双主 | Failover 后原主库未闪回 | 立即隔离原主库,禁止挂载共享存储 |
6.2 RAC 侧的典型故障
节点被反复踢出集群,是 RAC 里最常见也最让人头疼的问题。日志里会看到node evicted或者reboot advisory。
排查顺序:先看 CSSD 日志,确认驱逐原因(心跳丢失、磁盘 I/O 超时、进程挂起都有可能)。然后检查私网链路质量——ping -f -c 1000打大包看丢包率。最后看系统负载,如果 CPU 长期跑满,CSSD 进程抢不到时间片,也会被误判为挂起。
有个容易忽略的点:虚拟化环境下,宿主机资源争抢会导致虚拟机“假死”,RAC 以为是节点故障就把自己踢了。这种情况要么给虚拟机留足资源余量,要么把misscount适当调大(但不要超过 60 秒,否则故障检测太慢)。
私网打满,表现是 gc 类等待飙升,但 CPU 和存储都不忙。用ifstat或者sar -n DEV看私网网卡的吞吐,如果接近线速,说明 Cache Fusion 流量超预期。短期靠加网卡绑定缓解,长期要查执行计划,看看是不是有本该走本地的大表扫描被跨节点访问了。
ASM 磁盘组空间告警,RAC 上有个坑:某个节点上的归档删除策略没生效,其他节点的归档空间持续增长。ASM 是共享的,一个节点写满,所有节点都受影响。解决办法是把归档清理做在 ASM 层(用asmcmd的rm结合日期),而不是依赖单节点的脚本。
6.3 DG 侧的典型故障
备库延迟突然拉大,先分清是哪一环的问题。
查主库:
SELECT dest_id, status, error, gap_status, applied_seq# FROM v$archive_dest_status WHERE dest_id = 2;如果status是VALID但gap_status显示有缺口,说明是传输问题。查备库:
SELECT process, status, sequence#, thread# FROM v$managed_standby WHERE process IN ('RFS','MRP0');MRP0的sequence#是应用进度,RFS的sequence#是接收进度。两者差距大,说明是应用慢(备库硬件不够、并行度设置不合理)。两者都落后于主库当前序列,说明传输有问题(网络、带宽、归档删除太快)。
归档日志被提前删除导致 gap,这是人为事故的高发区。主库上如果配了频繁的归档清理,备库还没收到日志就被删了,gap 就永远修不上。缓解办法:主库的归档保留策略要考虑备库的接收速度,保留时间至少是“备库最长可能延迟时间”的 2 倍。同时把LOG_ARCHIVE_DEST_2加上REOPEN参数,网络恢复后自动重连。
同步模式下主库变慢,用最大可用模式时,如果备库所在网络抖动,主库的提交响应会被拖慢。诊断方法是看主库的log file sync等待事件——如果这个等待突然变长,而备库日志里显示有大量传输重试,基本可以确定是网络问题。这时候要么优化网络,要么临时降级为异步模式(改log_archive_dest_2去掉SYNC AFFIRM),保证业务先跑起来。
6.4 HA 侧的典型故障
切换判定过于灵敏,网络轻微抖动就触发切换,一天切好几次,业务方根本受不了。调整方向:增大advert_int,或者给 VRRP 加认证和单播模式(unicast_peer),减少广播干扰。
切换后应用连不上,最常见的原因是连接池里全是旧连接的僵死会话。解决办法有两层:数据库侧配SQLNET.EXPIRE_TIME,应用侧配连接有效性检测(比如 Druid 的testWhileIdle),再加上合理的重试策略。
共享存储挂载失败,切换脚本里没做重试,一次挂载失败就退出,整个接管流程中断。存储设备的识别、多路径的收敛都需要时间,脚本里要加重试和等待逻辑(比如挂载前先multipath -ll确认路径状态,最多重试 3 次,间隔 10 秒)。
回切失败,原主库修好后想切回去,发现存储上的锁文件还在,或者文件系统有残留。回切一定要在业务低峰做,而且要先把原主库完全清理干净(卸载存储、清锁文件、确认实例彻底停止),再让它以备机身份加入。
6.5 我自己踩过的几个坑
第一个坑,进度条式的检查清单靠不住。早年做 RAC 部署,拿着文档逐项打勾,全都通过了,结果压测时私网被打满。原因是文档里只写了“配置私网”,没写“带宽要按业务量估算”。从那以后我每次做方案都会先算一遍峰值交互量,宁可硬件多买点,也不在私网上省。
第二个坑,DG 的 FAL 参数配错,gap 修了三天。当时备库落后了几百个归档,手工拷贝了一天日志文件还是追不上。后来发现是FAL_CLIENT写成了主库的实例名,应该配备库自己的服务名。这种细节文档里一句话带过,但配错了就是灾难。现在我做 DG 一定会在部署完成后立刻模拟一次网络中断,验证 gap 能不能自动修复。
第三个坑,双机热备没做 fencing,差点毁掉数据。那次是机房网络改造,心跳线被误拔,两台机器同时挂载存储。好在当时是低峰期,监控告警来得快,及时人工干预。事后复盘,最大的问题是当初为了“简化配置”把 STONITH 关了。这种简化,代价可能是整个数据库。
第四个坑,把 RAC 当成容灾方案卖给业务方。有个项目业务方明确要求“机房停电不能停业务”,架构图上却只画了 RAC。后来沟通才发现,业务方以为 RAC 就是双活容灾。这种认知偏差在跨团队协作里非常常见,一定要在方案评审阶段把故障域讲清楚,白纸黑字写下来——RAC 挡不住机房级故障,必须配 DG。
第五个坑,演练只做 Switchover,不做 Failover。有一年演练很顺利,二十多分钟完成切换,领导很满意。结果半年后真实故障走的是 Failover,值班同事拿着 Switchover 的手册操作,多花了四十分钟才把库起起来。从那以后我的做法是:两套手册分开写,Failover 手册每季度在隔离环境完整走一遍。
最后分享一个我一直在用的习惯——给每个高可用架构画一张“故障域地图”。把从服务器、交换机、存储、机房、网络链路,一直到应用连接池,每一层可能出什么问题、由谁兜住、兜不住时怎么办,全部标在一张图上。这张图比任何架构文档都直白,评审的时候往投影上一放,谁都能一眼看出漏洞在哪儿。很多方案看着完备,真画出来才发现某个关键环节其实是裸奔的。