news 2026/11/3 13:01:07

Oracle RAC、DG与双机热备:RTO/RPO高可用选型指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Oracle RAC、DG与双机热备:RTO/RPO高可用选型指南

把 RAC、Data Guard、双机热备这几个词摆在一张桌子上问“哪个更好”,是这些年被问得最频繁的一类问题,也是最容易问偏的一类问题。问的人通常已经知道几个关键词:Oracle RAC能做到多节点同时读写、DG能把数据同步到异地、双机热备(HA)便宜又简单,但一到真正选型就卡住——切换时间差多少、RPO 能不能做到零、预算差几倍、出了事谁兜底,这些具体问题没人给一个能落地的答案。

我先把结论性的定位摆出来:这三样东西压根不在同一个维度上。双机热备解决的是“服务器坏了”,RAC 解决的是“实例或节点坏了,同时还想让多台机器一起扛并发”,DG 解决的是“存储坏了、机房没了、数据被误删了”。拿它们互相比“谁更强”,就像拿备胎和四驱系统比谁更越野——不是不能比,是比出来没意义。真正需要的是把它们各自守住哪一段故障域搞清楚,然后按业务能接受的中断时长和数据丢失量做组合。

这篇内容面向的是正在做数据库高可用架构选型的人:可能是要上线一套核心库的 DBA,可能是被领导问“为什么不直接上 RAC”的运维,也可能是刚接手一套老旧双机热备环境、想搞清楚它到底靠不靠谱的工程师。下面从概念定位、原理拆解、参数配置、实操步骤一路讲到踩坑排查,凡是涉及取舍的地方我都会把“为什么这么选”讲透,涉及数字的地方都会说明这是经验值而非官方承诺。

1. 先把概念摆正:HA、双机热备、RAC、DG 根本不在一个维度

1.1 用 RTO 和 RPO 两把尺子量之前,先搞清楚谁在管哪一层

讨论高可用,绕不开两个硬指标。RTO(Recovery Time Objective,恢复时间目标)指的是从故障发生到业务恢复可用的时间,通俗说就是“能停多久”;RPO(Recovery Point Objective,恢复点目标)指的是故障发生时允许丢失多少数据,通俗说就是“能丢多少”。所有高可用方案的取舍,本质都是在这两个数字和预算之间找平衡点。

这里有个特别容易混淆的地方:HA(High Availability)本身是一个目标,不是一款产品。高可用意味着系统整体在可接受的时间内持续对外提供服务,而双机热备、RAC、DG 都只是达成这个目标的手段。厂商销售口中说的“我们的 HA 方案”,国内运维口语里说的“上双机热备”,指的都是“两台服务器主备接管”这一种具体实现;而 Oracle 官方文档里讲 HA 时,往往把 RAC、Data Guard、Oracle Restart 全都归到高可用技术体系下面。同一个词,两个语境,含义差着一整个数量级,这是很多人讨论跑偏的起点。

所以看到“RAC 和 HA 哪个好”这种问法,正确的反应是先反问:你说的 HA 是指操作系统层面的双机接管,还是泛指整个高可用体系?如果是前者,那它和 RAC 是同一层的两种实现方案,可以比;如果是后者,那 RAC 本身就在 HA 里面,不存在对比关系。

1.2 一张定位表把四个概念钉死

我把这几个名词的边界整理成一张表,日常做方案评审时直接拿这张表对照,能省掉大量来回解释。

名称冗余的对象备节点平时是否承载业务典型故障域覆盖
双机热备(HA)服务器硬件、操作系统、实例进程否,纯待机单台服务器宕机、OS 崩溃、实例异常退出
Oracle RAC服务器节点 + 数据库实例是,所有节点同时读写单节点宕机、单实例崩溃,不覆盖存储故障
Data Guard(DG)数据本身(独立副本)物理备库可只读打开(需相应授权)存储损坏、机房级故障、数据误删误改
Oracle Restart单机上的实例与监听进程不涉及实例崩溃、监听异常,不覆盖整机故障

看这张表能明白两件事。第一,双机热备和 RAC 的冗余对象重叠但方式不同:前者是“一台干活一台待命”,后者是“大家一起干活,谁倒下剩下的接着干”。第二,DG 是唯一能覆盖存储故障和数据逻辑错误的方案,因为它的本质是维护一份物理上独立的完整数据副本,而前面两者都只有一份数据。

现实中最常见的误解就是“上了 RAC 就高枕无忧了”。RAC 的所有节点共享同一套存储,这套存储一挂,所有节点同时失去数据文件,业务瞬间全停。我见过不止一套环境,RAC 做得漂漂亮亮,两个节点、万兆私网、SCAN 配置齐全,结果存储控制器的固件升级把阵列搞挂了,两个节点一起趴窝,恢复全靠三天前的全备。这种场景里,RAC 的高可用性等于零。

还有一个容易被忽略的小角色:Oracle Restart。它是 Grid Infrastructure 里的一个组件,作用是在单机上监控实例和监听,进程挂了自动拉起来。很多单实例环境配置了它,就以为“我这也算高可用了”,但它只能解决进程级别的崩溃,服务器一关机它什么也做不了。把它当成 HA 方案,是把保险丝当成发电厂。

1.3 一个类比把三者的关系讲明白

用一个物流仓库的例子来理解会轻松很多。假设你有一个仓库在对外发货:

双机热备相当于准备了两间库房,但平时只用其中一间,另一间空着、门锁着。主库房着火了,赶紧把货物清单和钥匙搬到备用库房,重新开门营业。这中间要花的时间就是 RTO,而备用库房里有没有货取决于你有没有提前把货搬过去——如果两间库房共用同一个货架(共享存储),那货一直都在,RPO 为零;如果只是定期把货复制一份过去,那最近一批货就丢了。

RAC相当于同一间大库房开了两个出货口,两个班组同时在里面拣货,共用同一批货架。一个出货口的卷帘门坏了,另一个口照常发货,业务几乎无感。但如果货架本身塌了(存储故障),两个口一起停摆。而且两个班组要拿同一件货的时候,得先打电话协调(Cache Fusion),这个协调动作是有成本的,人多的时候电话打得太频繁反而拖慢速度。

DG相当于在另一个城市建了一个完整的备份仓库,所有的出入库记录实时同步过去。本地仓库烧了,异地仓库直接接管发货,但送货地址变了、客户要重新引导。这个方案的强项不是“快”,而是“远”和“有底”——本地仓库的货被搬错了、账记错了,异地那份还能还原回来。

这三段东西组合起来才是一套完整的容灾体系,任何单一方案都有明确的覆盖盲区。

2. RAC 到底在解决什么问题:多实例共享一份数据的横向扩展

2.1 Cache Fusion 是灵魂,也是性能成本的主要来源

RAC 的架构核心不复杂:多台服务器,每台上跑一个独立的数据库实例,每个实例有自己的 SGA 和后台进程,但所有实例共享同一份数据文件。数据文件放在共享存储上,通常用 ASM 管理,OCR 和 Voting Disk 也在这套共享存储里。客户端通过 SCAN 地址连进来,由集群做负载分发。

第一个要理解的关键点是:数据只有一份,但缓存有多份。每个实例的 Buffer Cache 里都缓存着自己读过的数据块。这就带来一个问题——如果节点 A 要修改的数据块,正好在节点 B 的缓存里是脏的(已修改未写盘),A 不能直接从磁盘读旧版本,也不能让 B 先把块写盘再读,那样太慢。于是引入了Cache Fusion:A 通过私有网络向 B 发起请求,B 把块的最新版本直接通过网络传给 A,同时通过 GCS(Global Cache Service)和 GES(Global Enqueue Service)协调锁的归属,确保同一时刻只有一个实例能修改这个块。

这个过程听起来很优雅,代价却相当真实。每一次跨实例的块传输都要占用私有网络带宽,都会引入网络延迟。本地内存访问是纳秒级,跨网络传输是微秒级,差着三个数量级。所以 RAC 的性能好坏,很大程度上取决于业务访问模式跟 Cache Fusion 相处得好不好。

举个典型的反面例子:一张单调递增主键的表,所有节点都在往里面插数据。因为主键递增,新插入的记录都落在索引的同一个叶子块上。节点 A 插入时持有这个块的锁,节点 B 要插入得先向 A 申请,A 把块传过去,B 改完再传回来。两个节点就这样为一个块来回“打乒乓”,术语叫block ping。并发越高,ping 得越凶,性能可能还不如单实例。序列(Sequence)如果不设置合适的缓存和noorder属性,也会造成类似的争用,全靠一个全局的 enqueue 排队。

提示:RAC 扩展的是并发处理能力,不是单条 SQL 的执行速度。指望“上了 RAC 单条慢查询就变快”,方向从一开始就错了。

2.2 RAC 的高可用边界:它防不住存储和人为误操作

RAC 的高可用机制是这样工作的:集群里的每个节点通过私有网络互相发送心跳,同时向 Voting Disk 写心跳信息。当某个节点在一段时间内没有心跳响应(Linux 上由misscount参数控制,默认 60 秒),集群会认为该节点失联,把它从集群中踢出去(node eviction),这个节点上的实例被强制终止。剩下的节点检测到有实例异常退出,开始做instance recovery:读取redo 日志,前滚恢复已提交但未写盘的事务,回滚未提交的事务,然后重新分布资源,业务恢复。

整个过程从故障发生到业务真正可用,经验值通常在30 秒到 2 分钟之间,取决于节点数量、事务量和恢复时需要处理的脏块数量。这个时间比很多人想象的要长——它不是“瞬间切换”。

更关键的是边界问题。RAC 的冗余单位是“服务器 + 实例”,共享存储是唯一的一份,没有任何冗余。存储在物理层面当然可以自己做 RAID 保护,但逻辑损坏、控制器故障、误删表空间、误 truncate 表,这些 RAC 全都防不住,因为它们作用在唯一的那份数据上。

所以生产环境里,RAC 从来不单独出现。要么配 DG 做异地副本,要么配存储级复制。只上 RAC 不配 DG 的架构,我一般会在评审时直接标红——不是它不能跑,是风险敞口太大。

2.3 私网与存储规划:三个最容易返工的地方

RAC 实施里最容易出问题、返工成本最高的部分,全在基础设施层,跟数据库参数关系不大。

第一是私有网络(Interconnect)。这块网卡专门承载 Cache Fusion 的块传输和集群心跳,绝不能和业务网卡混用,也不要和业务网卡做成同一个 bond。带宽上,两个节点用万兆是起步配置,节点数往上加就得考虑多链路绑定或更高带宽。交换机要独立,避免业务流量突发时把心跳挤掉——心跳一旦超时,节点就被踢了,而踢节点本身又是一次业务中断。

开启 Jumbo Frame(MTU 设成 9000)能明显降低大块传输的 CPU 开销,但要注意链路上所有设备(网卡、交换机端口、对端)必须全部一致,中间有一个设备还是 1500,就会出各种诡异的分片和丢包问题,排查起来非常痛苦。我的建议是新环境直接上,老环境如果链路设备型号混杂,先别动。

第二是心跳超时参数。Linux 平台上用crsctl get css misscount查看,默认 60 秒。有人觉得 60 秒太长,想调小到 10 秒让故障检测更快。这个操作要非常谨慎:调小之后,只要私网出现一次瞬时拥塞或交换机重启,节点就会被误判失联而踢出。我见过一个环境为了追求“快速切换”把 misscount 调到 15 秒,结果每次交换机做配置变更都会触发一次节点驱逐,业务侧的感受比真正故障还频繁。

第三是共享存储的冗余配置。ASM 磁盘组的冗余级别要选对:外部冗余(EXTERNAL)意味着一份数据,磁盘阵列负责保护;正常冗余(NORMAL)是双份,需要至少两块故障组;高冗余(HIGH)是三份。OCR 和 Voting Disk 至少要有三份副本,分别放在不同的存储设备或 LUN 上,否则这套“集群的大脑”本身就有一个单点。

注意:部署完成后务必验证一遍网卡命名、Multipath 配置、udev 绑定规则在所有节点上完全一致。节点之间设备名对不上,会导致 ASM 磁盘识别混乱,这个问题在扩容时最容易暴露。

2.4 集群状态巡检的常用命令

日常运维 RAC,有几个命令是每天都要敲的,我把它们整理在一起,方便直接抄。

# 查看集群所有资源的状态(最常用,一眼看全局) crsctl stat res -t # 查看集群节点列表和编号 olsnodes -n # 查看私有网络和公共网络的接口配置 oifcfg getif # 查看数据库实例在各节点的运行状态 srvctl status database -d ORCL # 查看某个实例的详细配置 srvctl config database -d ORCL # OCR 手动备份(重要!升级、改配置前必做) ocrconfig -manualbackup # 查看 OCR 备份列表 ocrconfig -showbackup

crsctl stat res -t输出里的 State 列要看仔细:ONLINE是正常,INTERMEDIATE表示正在启动或停止,卡在这个状态超过几分钟基本就是有问题了,得去看对应的日志。日志位置在 Grid Infrastructure 的log目录下,cssd、crsd、ohasd这几个组件的日志是排查节点驱逐问题的必看项。

3. Data Guard 的逻辑:用日志搬运换一份独立的数据副本

3.1 redo 从主库到备库的完整链路

DG 的原理说穿了很朴素:主库把自己产生的 redo 日志,通过网络传给备库,备库把这些日志在本地重放一遍,最终得到一份和主库一致的数据副本。数据文件、控制文件、参数文件都是物理上独立的,不共享任何存储。这一份独立性,就是 DG 能覆盖存储故障和机房故障的根本原因。

链路里有几个关键角色。主库这边,LGWR 进程在写在线日志的同时,把 redo 通过 LNSn 进程(Log Writer Network Server)实时传到备库;或者由归档进程 ARCn 在日志切换归档完成后再传。备库这边,RFS 进程(Remote File Server)负责接收 redo,写进备库的 standby redo log,然后由MRP 进程(Managed Recovery Process)在物理备库上做 Redo Apply,把日志变更应用到底层数据文件。如果备库是逻辑备库,则由 SQL Apply 把 redo 解析成 SQL 语句在备库上重新执行。

传输方式的选择直接决定了 RPO 和主库性能:

传输方式主库是否等待备库确认RPO对主库性能影响
ARCH不等待,归档后才传可能丢一个日志切换周期几乎无影响
LGWR SYNC提交前等待备库写入 standby redo log 确认零丢失每个事务多一次网络往返
LGWR ASYNC不等待确认秒级,通常几秒影响很小

这里的关键取舍是:要零丢失就必须同步等待,同步等待就必然增加提交延迟。物理距离越远,这个延迟越明显。同城机房之间通常在 1 毫秒以内,影响可以接受;跨省跨地域的距离,一个事务多出几十毫秒,高并发交易库根本扛不住。这就是为什么后来要引入Far Sync这种中间层——在离主库很近(低延迟)的位置放一个只接收日志不应用日志的实例,主库向它同步传输,它再异步转发到远端备库,既保证了主库零丢失,又不让主库承受远距离传输的延迟代价。

3.2 三种保护模式怎么选,以及 standby redo log 的配置规则

DG 官方定义了三种保护模式,实际选型时几乎只在两种之间纠结。

最大保护模式(Maximum Protection)要求至少一个备库以 SYNC 方式确认接收,否则主库直接停止写入。它的语义非常强硬:宁可不给业务写,也绝不丢一笔数据。这个模式在生产环境里很少用,因为一旦所有备库都不可达,主库会卡死,业务侧的感受是“主库挂了”。除非是法规要求极严格的场景,否则不建议。

最高可用模式(Maximum Availability)同样是 SYNC 传输,但做了一个聪明的降级处理:当备库不可达时,主库自动切换成异步传输继续运行,不会中断业务;等备库恢复后自动升回同步模式。这是绝大多数生产环境的选择,兼顾了零丢失和可用性。

最高性能模式(Maximum Performance)是默认模式,采用异步传输,主库性能几乎不受影响,代价是故障切换时可能丢几秒的数据。对数据一致性要求不那么苛刻的业务,这个模式的性价比最高。

配置模式的前提是standby redo log 必须存在且配置正确。规则很简单:每个线程的 standby redo log 组数 = 该线程的在线日志组数 + 1,每个日志组里包含的成员数应该和在线日志组保持一致,大小不小于在线日志组中最大的那个。如果这个配错了,同步模式根本起不来,会报日志空间不足相关的错误。这条规则我见过太多人漏掉,搭建时只记得建备库,忘了在主库上先把 standby redo log 加好。

3.3 Switchover 和 Failover 完全是两件事

这两个词经常被混着说,但操作风险和后果差得很远。

Switchover 是计划内的角色互换。主库正常运行时,主动把主库角色交给备库,原主库变成新的备库。整个过程零数据丢失,业务中断时间通常在几十秒到一两分钟,可控可回退。硬件维护、存储升级、机房搬迁,全都用这个方式。做之前确认几件事:备库的 MRP 正在运行、两边参数文件里的LOG_ARCHIVE_DEST_2指向正确、密码文件同步、fal_server和fal_client配好。

Failover 是主库真的挂了之后的强制接管。备库直接提升为主库,业务在备库上继续跑。此时如果用的是异步模式,最近一段时间的数据就丢了;如果原主库的在线日志还有一部分没传到备库,那部分也丢了。更麻烦的是原主库归队——它不能直接变回备库,因为它的数据比新主库“旧”或者“新”得不一致,必须做 reinstate(重新同步)才能加入。

reinstate 的方式取决于有没有提前打开Flashback Database。如果开了,可以把原主库闪回到备库分叉的那个 SCN,然后自动追平,几分钟搞定;如果没开,就老老实实从新主库做一次全量恢复,数据量大的库光这一步就是好几个小时。我在任何 DG 环境里都会把 Flashback Database 打开,用一点空间换这一步的分钟级恢复能力,非常划算。

3.4 搭建 DG 的关键参数与核心步骤

假设主库orcl_pri、备库orcl_stby,走 LGWR SYNC 的最高可用模式,核心步骤和参数如下。

第一步,主库开启强制日志并开启归档(强制日志保证即使表上配了 NOLOGGING,redo 也会完整记录,否则备库会出现坏块)。

ALTER DATABASE FORCE LOGGING; ALTER DATABASE ARCHIVELOG;

第二步,在主库添加 standby redo log。假定在线日志有 4 组,那么每个实例的 standby redo log 建 5 组。

ALTER DATABASE ADD STANDBY LOGFILE GROUP 11 ('/u01/app/oradata/orcl/srl_11a.log') SIZE 512M; ALTER DATABASE ADD STANDBY LOGFILE GROUP 12 ('/u01/app/oradata/orcl/srl_12a.log') SIZE 512M; ALTER DATABASE ADD STANDBY LOGFILE GROUP 13 ('/u01/app/oradata/orcl/srl_13a.log') SIZE 512M; ALTER DATABASE ADD STANDBY LOGFILE GROUP 14 ('/u01/app/oradata/orcl/srl_14a.log') SIZE 512M; ALTER DATABASE ADD STANDBY LOGFILE GROUP 15 ('/u01/app/oradata/orcl/srl_15a.log') SIZE 512M;

第三步,配置主库的 DG 相关参数。

ALTER SYSTEM SET log_archive_config='DG_CONFIG=(orcl_pri,orcl_stby)' SCOPE=BOTH; ALTER SYSTEM SET log_archive_dest_1='LOCATION=/u01/arch VALID_FOR=(ALL_LOGFILES,ALL_ROLES) DB_UNIQUE_NAME=orcl_pri' SCOPE=BOTH; ALTER SYSTEM SET log_archive_dest_2='SERVICE=orcl_stby LGWR SYNC AFFIRM VALID_FOR=(ONLINE_LOGFILES,PRIMARY_ROLE) DB_UNIQUE_NAME=orcl_stby' SCOPE=BOTH; ALTER SYSTEM SET standby_file_management=AUTO SCOPE=BOTH; ALTER SYSTEM SET fal_server='orcl_stby' SCOPE=BOTH; ALTER SYSTEM SET fal_client='orcl_pri' SCOPE=BOTH;

standby_file_management=AUTO这个参数一定要设,否则主库新增数据文件时,备库不会自动跟着创建,MRP 会直接停掉,报文件找不到的错误。

第四步,用 RMAN 的 active duplicate 方式直接在线搭建备库,不需要提前做备份文件传输,省掉一整轮备份恢复的时间。

rman target sys/密码@orcl_pri auxiliary sys/密码@orcl_stby RMAN> duplicate target database for standby from active database nofilenamecheck;

第五步,备库启动到 mount 状态,开启日志应用。

ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT FROM SESSION;

这里USING CURRENT LOGFILE是关键,它表示用实时应用(实时读 standby redo log),而不是等到归档完成才应用。不加这个子句,备库的延迟会明显变大。

注意:搭建完成后一定要做一次真实的切换演练。很多环境搭好就一直放着,等到真出事才发现fal_server配错、密码文件不同步、切换脚本没测过。没演练过的容灾,等于没有容灾。

3.5 DG 最容易踩的三个坑

第一个坑是归档删除策略。主库上的归档日志什么时候能删?只有确认所有备库都已经应用完之后才能删。如果主库按时间策略无脑删归档,备库一旦断连一段时间再回来,就会发现需要的日志已经被删了,追不上,形成gap。正确做法是在主库上配置:

RMAN> CONFIGURE ARCHIVELOG DELETION POLICY TO APPLIED ON ALL STANDBY;

这个策略告诉 RMAN,只有当所有备库都应用过之后,对应的归档才允许删除。配合备库上的ARCHIVELOG DELETION POLICY一起使用效果更稳。

第二个坑是日志 gap 的排查。备库应用停了、或者日志接不上,第一件事是查 gap 在哪:

SQL> SELECT * FROM V$ARCHIVE_GAP;

结果会告诉你缺的日志序列号和线程号。如果这些日志在主库归档目录里还在,直接拷过去,在备库上注册一下:

ALTER DATABASE REGISTER LOGFILE '/tmp/arch_1_1023_xxxx.arc';

如果主库上也被删了,那就只能从备库当前 SCN 开始做增量恢复,或者重新搭建。

第三个坑是备库应用进程悄无声息地停了。MRP 进程退出不一定有告警,业务侧也感知不到,等到需要切换时才发现备库落后了几十个小时。我的做法是配一个定时巡检,每分钟查一次备库的V$MANAGED_STANDBY视图,确认 MRP0 的状态是APPLYING_LOG,如果不是就立刻告警。同时监控V$DATAGUARD_STATS里的apply lag和transport lag两个指标,正常应该都在秒级,超过阈值就说明链路出问题了。

4. 双机热备(HA):最容易被低估也最容易做错的一层

4.1 结构:浮动 IP、共享存储、资源接管脚本

双机热备的基本形态是两句话:两台服务器,一台跑数据库,另一台待机;故障时把浮动 IP 和存储接管过来,在备机上把实例拉起来。

三个组成部分缺一不可。浮动 IP(VIP)是客户端连接的入口,它平时绑在主节点的网卡上,故障时漂移到备节点,客户端不需要改连接串。共享存储是数据库文件存放的位置,必须两台机器都能访问,否则备机就算接管了 IP 也起不来实例——这一点是很多人搭建时最容易忽略的前提,如果两台机器各用本地盘,那就根本不叫双机热备,那叫“冷备加手动拷贝”。接管脚本负责在故障时执行一系列动作:检查主机是否真的不可用、挂载共享 LUN、启动数据库实例、启动监听、检查服务是否正常。

实现工具上,Linux 环境最常见的是Keepalived(负责 VIP 漂移和健康检查)配合自定义脚本,或者Pacemaker + Corosync(功能更完整,能做资源依赖和服务编排,学习曲线也更陡)。也有商业化的 HA 软件,原理大同小异,无非是把脚本和检测做成了产品。云上的话,通常用负载均衡加健康检查来替代 VIP 漂移,思路上是一样的。

这个方案的优势非常直接:成本低、结构简单、运维人员容易理解、出问题好排查。两台普通服务器加一套共享存储,就能防住单台服务器宕机。缺点也同样直接:备机长期闲置,资源利用率最多 50%;切换过程中业务一定有中断,因为实例要重新启动,这个过程是分钟级的;而且它只能防硬件和系统层面的故障,数据库内部的逻辑错误一点都防不住。

4.2 脑裂是这套方案最大的敌人

脑裂(split brain)是双机热备里最危险的情况,没有之一。它的成因是:两台机器之间的心跳网络断了,但两台机器都还活着,而且都能访问共享存储。这时候主节点认为自己还是主节点,备节点收不到心跳,认为主节点死了,于是也去挂载共享 LUN、启动数据库。

结果就是两个实例同时读写同一份数据文件。这不是“性能慢一点”的级别,这是数据文件块级别的互相覆盖,轻则数据库打不开,重则整库彻底损坏,只能从备份恢复——而且大概率恢复不到故障前那一刻。

解决脑裂的核心是引入第三方仲裁或者强制隔离(fencing)。常见的几种做法:

一种是仲裁盘。用一块小的共享 LUN 或者一个独立的物理设备作为仲裁,心跳断开时,两个节点都去抢仲裁盘上的锁,抢到的一方继续服务,没抢到的自动放弃。这是廉价且有效的方案。

另一种是STONITH(Shoot The Other Node In The Head,直译就是“打爆对方的头”)。这个词听着暴力,逻辑也确实暴力:检测到疑似脑裂时,直接用带外管理口或电源控制把对方节点强制断电或重启,确保只有一台机器在运行。Pacemaker 体系里这是标准配置,虽然听起来吓人,但在脑裂场景下,牺牲可用性保住数据一致性永远是正确选择。

还有一种是存储侧的强制保留。利用存储的 SCSI persistent reservation 或者 LUN masking,让同一时刻只有一个节点能挂载某个 LUN,从物理层面杜绝双写。

提示:如果预算实在紧张,至少也要配一块小容量的仲裁盘,或者用带外管理口做节点隔离。什么保护都不做的双机热备,本质上是在赌运气。

这里还有一个特别隐蔽的问题:心跳断了但主机实例还活着。这种情况下,主机的数据库其实还在正常服务,只是备机联系不上它了。如果接管脚本只是简单地“检测不到就启动实例”,那就会出现两个实例同时运行的灾难。所以接管脚本里必须有一步——在启动实例之前,先确认主节点的实例真的已经不在了。确认方式可以是查共享存储上的锁文件、通过带外管理口确认主机电源状态、或者通过存储层面解除主机的 LUN 映射。这一步做扎实了,脑裂的风险能降一个数量级。

4.3 一份可复现的 Keepalived 加 Oracle 单实例配置

这里给出一份可以直接参考的最小配置,两个节点都是一样的配置内容,靠优先级决定主备。

vrrp_instance VI_ORACLE { state BACKUP interface eth0 virtual_router_id 51 priority 100 advert_int 1 nopreempt authentication { auth_type PASS auth_pass OracleHA2024 } virtual_ipaddress { 192.168.10.100/24 } notify_master "/opt/ha/scripts/oracle_start.sh" notify_backup "/opt/ha/scripts/oracle_stop.sh" notify_fault "/opt/ha/scripts/oracle_stop.sh" }

两个细节值得单独说。state都写 BACKUP 而不是一个 MASTER 一个 BACKUP,配合nopreempt(不抢占),能避免主节点恢复后把 VIP 抢回去,减少不必要的二次切换。advert_int 1表示心跳间隔 1 秒,配合默认的 3 倍超时,大约 3 到 4 秒能判定对端失联,这个响应速度对大部分业务足够。

接管脚本的关键是幂等——重复执行不能产生副作用,也不能把已经在跑的实例再启动一次。

#!/bin/bash # oracle_start.sh 接管时执行 LOG=/opt/ha/logs/start_$(date +%Y%m%d%H%M%S).log echo "=== 接管开始 $(date) ===" >> $LOG # 1. 保险:确认主机的实例确实不在了,防止脑裂 if ssh -o ConnectTimeout=3 -o BatchMode=yes node1 "pgrep -f ora_pmon_orcl" 2>/dev/null; then echo "ERROR: 检测到 node1 上的实例仍在运行,放弃接管" >> $LOG exit 1 fi # 2. 挂载共享存储(先检查是否已挂载,保证幂等) if ! mountpoint -q /u01/app/oradata; then mount /dev/mapper/asmdata01 /u01/app/oradata >> $LOG 2>&1 fi # 3. 启动监听和实例 su - oracle -c "lsnrctl start" >> $LOG 2>&1 su - oracle -c "sqlplus -s / as sysdba <<EOF startup mount; ALTER DATABASE OPEN; EXIT; EOF" >> $LOG 2>&1 # 4. 健康检查,最多等 90 秒 for i in $(seq 1 9); do if su - oracle -c "sqlplus -s / as sysdba <<EOF" 2>/dev/null | grep -q "OPEN" set heading off feedback off SELECT status FROM v\$instance; EXIT; EOF then echo "数据库已 OPEN,接管完成" >> $LOG exit 0 fi sleep 10 done echo "ERROR: 90 秒内未完成 OPEN,请人工介入" >> $LOG exit 1

这段脚本里有三个地方是血泪教训堆出来的。第一步的 ssh 检查必须做,而且要在挂载共享存储之前做,否则等你挂上去才发现对面实例还活着,数据可能已经被两个实例同时操作了。挂载前的mountpoint -q判断必须做,因为 Keepalived 在某些边界情况下会重复调用 notify 脚本,不判断就会挂载两次,轻则报错重则搞乱目录。最后的健康检查循环必须做,因为startup命令返回成功不代表数据库真的打开了,如果启动过程中卡在某个环节,脚本已经退出,Keepalived 却以为接管成功了,VIP 挂在了一个死掉的实例上,业务会表现为“能连上但一直超时”,排查方向会完全跑偏。

5. 横向对比:把 RAC、DG、双机热备放进同一张表

5.1 RTO、RPO、成本、扩展性的真实对比

前面几节把每个方案的原理拆开了,这里集中做一次横向对照。表里的时间数字都是经验值,实际环境会因数据量、硬件配置、参数调优而浮动。

对比维度双机热备(HA)Oracle RACData Guard
故障切换 RTO1 到 5 分钟,取决于实例启动和恢复时间30 秒到 2 分钟,取决于实例恢复量计划内 Switchover 秒级到分钟级;故障 Failover 分钟级
数据丢失 RPO共享存储方式为 0;本地复制方式有损0,数据只有一份SYNC 模式为 0;ASYNC 模式秒级
覆盖的故障域服务器、OS、实例进程节点、实例进程存储、站点、误操作
是否覆盖存储故障否否是
是否覆盖误删数据否否是,延迟备库可直接恢复
横向扩展能力无,备机闲置有,多节点并发读写备库可做只读查询分流
硬件成本低,两台服务器加共享存储高,多节点、万兆私网、高端共享存储中,一套独立存储
软件授权成本无额外数据库授权需 RAC 选项授权,按核数计费视使用方式而定,只读打开需相应授权
运维复杂度低高,集群、ASM、私网、SCAN 全要懂中,主要是日志链路和保护模式
典型适用规模中小业务、非核心系统核心交易、高并发 OLTP有容灾要求的所有核心系统

从这张表能读出几个明确的结论。双机热备的性价比在中小业务里是无敌的,两台机器加一套存储就能防住最常见的服务器故障,运维门槛低到普通运维就能 hold 住。RAC 的成本不只是硬件,RAC 选项的授权按 CPU 核数收费,一个 64 核的服务器集群,授权费往往是硬件的好几倍,这是很多人做预算时漏算的大头。DG 是唯一能兜住误操作和存储故障的方案,这个特性在核心系统里是不可替代的。

还有一个数字经常被忽略:DG 的 Switchover 和 Failover 时间差。Switchover 因为两边都正常,只是角色互换,可以做到几十秒;Failover 需要额外做日志应用、角色提升、客户端重连,往往要几分钟。做容灾演练的 SLA 时,这两个数字要分别写,不能混用。

5.2 为什么生产环境的主流是 RAC 加 DG 的组合

RAC 和 DG 的关注点完全不重叠,所以它们天然是互补关系。

RAC 负责的是“局部故障不中断”。单台服务器硬件挂了、单个实例进程崩了、某台机器的操作系统需要打补丁重启,这些场景 RAC 都能平滑吸收,业务侧的感知只是连接短暂抖动。这是双机热备做不到的——双机热备遇到这些情况必须走一次完整的切换流程,中断时间以分钟计。

DG 负责的是“灾难有底”。存储阵列挂了、机房断电了、有人执行了DROP TABLE还提交了,这些场景 RAC 一个都扛不住,而 DG 的独立副本能兜住。尤其是延迟备库这个配置,让备库故意滞后主库一到两个小时应用日志,一旦主库发生误操作,可以在备库上把时间点恢复出来,这一招救过太多人的职业生涯。

组合起来的形态通常是:本地两个或三个节点做 RAC 承载业务,异地一个备库做 DG 容灾,保护模式选最高可用,本地同步传输保证零丢失,异地用 Far Sync 中转降低主库延迟。这套架构的 RTO 能压到分钟级,RPO 在本地故障场景下为零,异地故障场景下为秒级。

如果预算不允许上 RAC,退而求其次的方案是单实例加 DG,再加双机热备。双机热备管服务器故障,DG 管存储和误操作,两层叠加基本覆盖了 90% 的故障场景,成本只有 RAC 方案的三分之一左右。这套组合在中小型核心系统里非常常见,性价比很高。

5.3 按业务特征反推选型

脱离业务谈架构没有意义。我把常见的几类场景和推荐方案对应一下。

核心交易库,中断一分钟就是事故,预算相对充足:RAC 加 DG,本地 RAC 保证节点级容错,异地 DG 保证站点级容灾。别省 RAC 的授权费,一次严重故障的业务损失可能就超过授权成本。

中小业务系统,能接受几分钟中断,预算有限:单实例加双机热备。这套方案的运维门槛最低,出问题也最容易定位,对团队能力要求不高。

有异地容灾的硬性要求:DG 是绕不开的,或者用存储级复制。但存储级复制的粒度是整个 LUN,没法做延迟恢复,也没法单独校验某个表的数据,灵活性远不如 DG。

报表和查询压力大,需要横向扩展读能力:RAC 的读扩展能力可以用上,另一种思路是 Active Data Guard 把只读查询分流到备库,既利用了备库资源又不影响主库,这个方案在某些场景下比加 RAC 节点更划算。

有强误删恢复需求,比如财务、账务系统:DG 的延迟备库必须配。日志滞后一到两小时,配合归档日志的完整保留,任意时间点恢复都能做。

6. 常见问题与排查实录

6.1 RAC 侧的高频问题

节点被驱逐(node eviction)是 RAC 里最常见的故障。现象是某个节点突然从集群里消失,上面的实例被终止,业务连接报错。排查的顺序是:先看crsd和cssd的日志,找到驱逐发生的时间点;再往上翻私有网络的监控,看是不是有心跳超时、丢包、交换机端口闪断。十次驱逐有八次是私网问题,剩下两次是服务器本身负载过高导致心跳进程调度不上(比如内存耗尽触发 swap,或者 CPU 被某个进程吃满)。

全局缓存等待过高。业务反馈“上了 RAC 反而更慢了”,去查等待事件,如果看到gc buffer busy acquire、gc cr block 2-way、gc current block 2-way这类以gc开头的等待事件占了主要部分,说明 Cache Fusion 的跨实例传输成了瓶颈。这时候要分析对象级别的争用:

SELECT inst_id, sid, event, p1, p2, p3, wait_class FROM gv$session_wait WHERE event LIKE 'gc%' ORDER BY inst_id, sid; -- 按对象看跨实例争用 SELECT * FROM gv$gcspfmaster_info ORDER BY gc_master_flushed DESC;

治理思路有三条:一是调整业务访问模式,尽量让同一类数据固定由同一个节点服务(应用分区连接);二是增加序列缓存、使用NOORDER序列、把单调递增主键改成分区或者乱序生成;三是把热点小表的访问改成全局缓存表(GLOBAL CACHED),让每个实例本地保存一份只读副本。

SCAN 或者 VIP 连不上。先查 DNS 解析是否正常,SCAN 的三个地址要能解析到三个不同的 VIP;再查srvctl config scan确认配置;然后确认节点上的local_listener参数和 VIP 地址一致,不一致会导致实例注册到错误的监听地址上,客户端连上去就被重定向到连不通的地方。这类问题排查起来不难,但如果不熟悉,会浪费很多时间在“网络肯定是通的”这种假设上。

6.2 DG 侧的高频问题

MRP 进程停止。备库不再应用日志,apply lag一直涨。手动重启:

ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL; ALTER DATABASE RECOVER MANAGED STANDBY DATABASE USING CURRENT LOGFILE DISCONNECT FROM SESSION;

如果重启之后很快又停,去看备库的 alert 日志,最常见的两个原因:一是主库新增了数据文件但standby_file_management不是 AUTO,备库找不到文件;二是磁盘空间满了,standby redo log 写不进去。

日志 gap。前面已经提过,用V$ARCHIVE_GAP定位缺哪个序列,能补就补,补不了就只能做增量恢复。预防的关键就是把归档删除策略配成APPLIED ON ALL STANDBY,别用按时间删。

备库和主库数据不一致。这个最麻烦,通常表现为备库查询报块损坏。查V$DATABASE_BLOCK_CORRUPTION,用 RMAN 的RECOVER DATABASE从主库补块。根本原因一般是主库上有人对大表做了 NOLOGGING 操作,而强制日志没开。所以第一件事永远是ALTER DATABASE FORCE LOGGING。

6.3 双机热备侧的高频问题

切换后数据库报 ORA-01102(cannot mount database in EXCLUSIVE mode)。这个错误的字面意思是“无法以独占模式挂载数据库”,实际含义是还有另一个实例在占用这套数据文件。绝大多数情况是原主机的实例根本没死——心跳断了但主机还活着,备机急着接管,两边撞上了。这就是典型的未做 fencing 的后果,处理方法只有一个:立刻把备机的实例停掉,确认主机状态,从数据一致性角度评估损失。这种情况出现一次,基本就意味着要从备份恢复。

VIP 能 ping 通但连不上数据库。这是最迷惑人的一类故障,因为网络层看起来完全正常。按顺序查:备机上的监听是否启动(lsnrctl status)、实例是否真的 OPEN(SELECT status FROM v$instance)、监听注册的服务名是否正确(lsnrctl services)、客户端连接串里的服务名和实例注册的是否一致。十次里面有六次是实例没起来但脚本提前退出了,这也是前面强调接管脚本必须做健康检查循环的原因。

频繁切换(flapping)。主节点和备节点来回抢 VIP,业务反复中断。原因通常是健康检查阈值设得太敏感,比如一次 ping 超时就切换,或者备机接管后服务起不来又被判故障,来回拉扯。处理方式是加大检测次数和间隔、在脚本里加冷却时间、nopreempt一定要配。

6.4 三类环境的问题速查表

把上面的排查经验整理成一张表,遇到问题先对号入座,能省掉不少摸索时间。

现象大概率原因首要动作
RAC 节点突然消失私网丢包或心跳超时查 crsd、cssd 日志与私网监控
RAC 跨节点查询变慢Cache Fusion 争用,热点块乒乓查 gv$session_wait 中 gc 类等待,分析对象级争用
RAC 客户端连不上SCAN 解析异常或 local_listener 配置错查 srvctl config scan 与实例注册状态
DG 的 apply lag 持续增长MRP 进程停了或数据文件未同步查 V$MANAGED_STANDBY,重启 MRP,检查 standby_file_management
DG 无法继续应用日志存在归档 gap,缺日志查 V$ARCHIVE_GAP,注册缺失归档
DG 备库报块损坏主库有 NOLOGGING 操作开启 FORCE LOGGING,用 RMAN 从主库补块
HA 切换后报 ORA-01102原实例仍在运行,典型的脑裂立即停止备机实例,评估数据一致性
HA 的 VIP 通但库连不上实例未 OPEN 或监听注册异常手工确认实例状态,检查 lsnrctl services
HA 反复切换检测阈值过敏感,缺少冷却调整检测参数,确认 nopreempt 生效

6.5 几条从实战里换来的经验

第一条,任何容灾方案都必须真实演练过才算数。搭好就放着、从不切换的环境,我见过太多在真出事时掉链子的案例。演练要覆盖的不只是“主库挂了怎么办”,还包括切换过程中的客户端行为、连接池的重连策略、中间件的超时配置。很多时候数据库侧几十秒就切完了,业务侧因为连接池还缓存着旧连接,卡了好几分钟。

第二条,DG 的延迟备库和 Flashback Database 一定要同时开。这两个配置在平时看起来纯属浪费空间,出事的时候能救命。延迟备库防误操作,Flashback 让 Failover 之后原主库能快速归队,两个加起来占用的空间通常不到总容量的 20%,非常值。

第三条,RAC 不要指望它解决性能问题,它解决的是并发和可用性。如果单实例的瓶颈是一条慢 SQL 或者一次全表扫描,上 RAC 之后只会更慢,因为跨实例的协调开销还要额外加上。性能问题先优化 SQL 和执行计划,实在不行再考虑架构改造。

第四条,双机热备的接管脚本要定期在测试环境跑一遍。脚本里的主机名、IP、挂载点、实例名,任何一个因为环境变更而对不上,切换时就会失败。我一般会在变更管理里加一条:凡涉及网络、存储、主机名的变更,必须同步验证一遍 HA 接管脚本。

第五条,监控要盯“结果”而不是“进程”。看 MRP 进程在不在,不如看apply lag是不是在正常范围内;看监听进程在不在,不如真正建一个连接执行一条 SQL 试试。进程在但服务不可用的情况,比进程不在还要多。

这套东西折腾下来,我个人最深的体会是:没有哪个方案是“更好”的,只有“更合适”的。一个日活几千的内部系统,上 RAC 加异地 DG 是典型的过度设计,运维成本高、故障点还多;一个每秒上万笔交易的核心库,只配双机热备则是在走钢丝。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/3 13:00:47

从越权改密看管理平台账户权限校验与系统口令加固

凌晨两点&#xff0c;一个做综合管理平台运维的朋友发来消息&#xff1a;审计报表里出现了一条不该出现的记录——一个只有实时预览权限的普通操作账号&#xff0c;在十分钟内完成了一次系统级口令变更。他第一反应是账号被盗&#xff0c;查完登录日志发现来源地址没变、设备指…

作者头像 李华
网站建设 2026/11/3 13:00:26

TensorFlow 2024安装指南:版本匹配、GPU配置与PyTorch对比

TensorFlow 这个名字&#xff0c;只要你接触过深度学习&#xff0c;大概率绕不开。但真正让大多数人卡住的&#xff0c;往往不是模型设计&#xff0c;而是第一步——装不上、跑不起来、GPU 认不到。我见过太多人在这上面耗掉一整天&#xff0c;最后连一行训练代码都没跑通。这篇…

作者头像 李华
网站建设 2026/11/3 12:59:35

JVM Young GC耗时突增的排查与优化实践

1. 问题现象与背景解析 上周三凌晨2点15分&#xff0c;监控系统突然发出Young GC耗时超过150ms的告警。作为负责支付核心系统的JVM工程师&#xff0c;我立刻从床上弹起来查看详细数据——这个平时稳定在20-30ms的GC操作&#xff0c;竟然出现了持续5分钟的异常波动。更诡异的是&…

作者头像 李华
网站建设 2026/11/3 12:58:20

图论连通性问题:省份数量算法解析与优化

1. 项目背景与问题定义 "省份数量"这个题目看似简单&#xff0c;实际上涉及图论中的经典连通性问题。我第一次接触这个问题是在准备算法面试时&#xff0c;它完美地展示了如何将现实世界的地理概念转化为计算机可处理的图论模型。 问题的标准描述是&#xff1a;给定…

作者头像 李华
网站建设 2026/11/3 12:57:40

高性能序列化技术对比与优化实践

1. 高性能序列化库的核心价值与应用场景 序列化就像把一台拆散的电脑装进快递箱的过程——我们需要把内存中的复杂数据结构转换成可以存储或传输的二进制流。而高性能序列化库&#xff0c;就是专门为这个转换过程设计的"专业包装团队"&#xff0c;它们追求的是用最小…

作者头像 李华
网站建设 2026/11/3 12:57:18

Redis核心配置详解与性能调优实战

1. Redis配置核心概念解析 Redis作为当今最流行的内存数据库之一&#xff0c;其配置文件的合理调优直接决定了生产环境的稳定性和性能表现。我见过太多团队在Redis配置上栽跟头——有的因为maxmemory设置不当导致OOM崩溃&#xff0c;有的因TCP-backlog配置不足在高并发时出现连…

作者头像 李华