Oracle RAC资源依赖全解析:从VIP/ASM到服务的启动顺序与故障排查
2026/9/17 12:31:36 网站建设 项目流程

凌晨四点,监控平台的红灯把值班手机震得嗡嗡响。登录一看,某套Oracle RAC集群的节点2实例自动重启后一直停留在INTERMEDIATE状态,数据库资源在线,但服务资源迟迟不启动,VIP资源在反复FAILOVER。排障折腾了快一个小时,最后发现问题的根源根本不在数据库本身,而是资源依赖关系被配乱了:服务没有随实例启动,监听因为没有VIP而注册不上去,客户端连接自然全线超时。那次之后我越来越确信一件事:Oracle RAC集群的高可用,本质上是集群件把计算、网络、存储、数据库资源编排成一张“启动/停止依赖关系网”,谁先起、谁后起、谁挂了谁必须跟着挂,全部由依赖配置决定。不懂这张网,平时风平浪静,一出故障就是连锁反应。

这篇文章,我想把RAC集群的资源依赖关系从头到尾梳理一遍。适合刚接触RAC的DBA,也适合那些已经维护有一套RAC环境、但还没仔细看过资源依赖配置的运维同学。看完之后,你能回答三个问题:集群里有哪些资源?它们之间为什么必须按顺序起?出了问题怎么定位和处理。

1. 理解资源依赖体系,先看清集群里的“编排底牌”

1.1 资源树的两级代理:OHASD与CRSD

Oracle RAC发展到11g以后,集群件体系从底层就可以分成两块:OHASD(Oracle High Availability Services Daemon)和CRSD(Cluster Ready Services Daemon)。OHASD是操作系统启动后最先拉起来的集群代理,负责管理节点级别的底层资源,比如ora.mdnsd(组播DNS,用于集群成员发现)、ora.gipcd(集群内部互联协议,负责节点间心跳通信)、ora.gpnpd(网格即插即用配置,管理profile文件)、ora.crf(集群健康监视器)和ora.drivers.acfs(ACFS文件系统驱动)。这些资源在节点上一旦出问题,整个节点都没法加入集群。

CRSD则管理集群级别的业务资源,包括ora.asm、ora. .db、ora. . .sys、ora. .vip、ora. .LISTENER.lsnr、ora.scan1.vip、ora.LISTENER_SCAN1.lsnr,以及OCR、voting file对应的磁盘组资源。CRSD负责把这些资源按照依赖关系编排起来,启动、停止、FAILOVER、重启策略全由它来调度。

从进程架构看,就是这样一个金字塔:操作系统内核 -> init/ systemd -> OHASD -> CRSD -> 具体资源。OHASD和CRSD都自带高可用能力,如果CRSD进程本身异常退出,OHASD会自动把它拉起来,而OCR和voting file必须始终在线,否则CRSD会进入“脑裂保护”状态,集群开始进入隔离流程。这也是为什么我们反复强调OCR和voting file必须放高可用存储上,它们不是在给数据库服务,而是在给调度器本身续命。

1.2 资源依赖的两种形式:启动/停止依赖与属性依赖

Oracle官方文档里,资源依赖通常被分成两类。

第一类是启动/停止依赖(START_DEPENDENCIES / STOP_DEPENDENCIES)。启动依赖决定了资源在启动前必须满足哪些条件,比如数据库实例依赖ASM实例,那就必须等ASM在线且磁盘组挂载完成后,数据库资源才会被允许启动。停止依赖则决定了停止操作的传播条件,比如某个资源在停止时,需要连带停止哪些资源,或者不能被先停止。

第二类是属性依赖(Attribute Dependency),这种依赖更温和。它不会强制等待对方启动,而是在被依赖资源的属性发生变化时,触发当前资源的属性同步。比较典型的就是ACL(访问控制列表)和profile里的tuning参数传递。属性依赖在很多运维场景中不起眼,但在角色切换、资源属主变更时很关键,尤其是Data Guard搭配RAC时,切换脚本里如果没处理好属性依赖,很容易出现主备角色状态不一致。

从底层配置看,资源依赖都被记录在OCR里的资源配置中。CRSD会根据OCR里面的资源profile来解析依赖,构建出集群当前的有向依赖图,然后按照拓扑来调度起停顺序。Oracle称之为dependency graph。整个逻辑比较像编译器的依赖解析:先处理没有依赖的资源,再逐层向上满足依赖,直到所有必要资源在线。

1.3 为什么需要依赖关系,没有依赖会怎样

打个比方,做一道菜,必须先把食材备好、锅热了,再下锅翻炒。如果你非要提前下菜,菜糊了,锅也裂了。RAC集群也是一样的道理:如果ASM实例还没起来,数据库实例就去连接磁盘组,会直接报ORA-15054(磁盘组不存在或不满足一致性)或ORA-17503等错误;如果VIP还没绑定成功,监听服务启动时会因为无法绑定地址而失败,客户端通过VIP连接自然全部超时;如果数据库实例都没起来,服务资源强行启动也只能是OFFLINE状态,并且会在crsd.log里反复出现无法启动的报错。

依赖关系还不只是“启动顺序”,它同时也是“存活判据”。举个例子,当节点上的VIP因为网络异常不可用时,监听资源会被联动标记为OFFLINE,数据库实例对外提供的可用性就自动降级;当ASM实例异常退出时,依赖它的数据库实例不会立马被杀掉,但数据库会hang住,因为I/O路径已经断了,CRSD会在超时之后按预设的restart策略重新拉起整个依赖链。

所以理解依赖关系,是理解RAC高可用底座的钥匙。集群故障转移不是某个魔法瞬间完成的,而是沿着依赖图逐级检查、逐级恢复的。

2. 核心依赖链路——从网络到存储到数据库的“串糖葫芦”

2.1 网络层的起点:VIP、SCAN与监听资源

网络是整个依赖链的最底层。每一个RAC节点通常有一个VIP(Virtual IP),它是由集群件托管的虚拟地址,平时绑定在节点上,节点故障时会漂移到其他存活节点。VIP存在的意义是让客户端连接能够快速感知节点故障:客户端连的是VIP,节点挂了,VIP漂移到别的节点,客户端通过TCP超时更快发现连接断开,而不是死等。

本地监听(ora. .LISTENER.lsnr)在启动时,会优先绑定本节点的VIP地址和主机名。因此在依赖上,监听资源通常依赖VIP资源。如果用crsctl stat res -t查看,很多环境里可以看到LISTENER的START_DEPENDENCIES里包含hard 的ora. .vip依赖。这就是为什么我们常说“监听起不来先看VIP”,VIP都没在线,监听怎么绑定都不能工作。类似的,SCAN监听依赖SCAN VIP,SCAN VIP又依赖名称解析(DNS或GNS)。SCAN本质上是给客户端提供单一入口地址,SCAN监听收到连接请求后,会把请求负载均衡到各节点本地的监听。

在实际运维中,前几年我遇到过一套RAC环境里,客户改了网络配置但没有同步更新OCR里的VIP掩码,导致VIP资源启动后网络不可达,本地监听一直FAILOVER。查到最后就是VIP资源的START_DEPENDENCIES和网络属性对不上,监听一直注册不进去,客户端连接报ORA-12545。这种问题只看数据库端是永远定位不了的,必须往依赖链下方查。

2.2 存储的命门:ASM实例与磁盘组依赖

ASM实例在RAC集群中处于绝对核心的位置,相当于存储卷管理器。数据库要打开,必须先把数据文件所在磁盘组挂载出来,而磁盘组的挂载由ASM实例负责。因此,数据库资源对ASM实例存在硬依赖,这在资源profile里表现为:ora. .db对象的START_DEPENDENCIES中带有hard依赖的ora. .asm,以及ora.ASM. .dg。

更深一层的依赖在于,OCR和voting file本身也常常存放在ASM磁盘组里。启动CRSD之前,OHASD必须先拉起ASM实例、挂载承载OCR的磁盘组,然后CRSD才能开始读取OCR配置。从这个角度看,ASM就是集群的地基,OCR是地基上的图纸,voting file是地基上的裁判。ASM实例一旦异常,不只是数据库读写故障,而是整个集群的调度都面临瘫痪。

这里有一个经验点:生产环境里尽量不要手动killASM实例来“测试故障转移”,因为依赖关系不会立刻把所有数据库实例全部杀掉,数据库会全部hang住,等待I/O超时之后CRSD才会介入重启。表面上看“看起来没挂”,实际上业务已经完全中断,等待时间可能远超你的预期。真实的故障演练要控制粒度,先停一个实例,再观察依赖资源如何联动,再逐步扩大范围。

2.3 数据库与服务的映射:Service依赖和TAF

Service是RAC对外提供连接逻辑上的入口。一个服务可以映射到一个或多个实例,客户端连接服务名时,通过监听分发到对应实例。服务资源在被CRSD管理时,通常依赖数据库资源,也依赖监听资源。只有实例真正OPEN后,服务才能变为ONLINE,客户端才能顺利连接。

这里有一个经常被忽略的点:RAC中真正的负载均衡和故障转移大多基于服务实现。比如TAF(Transparent Application Failover),它的配置就是在服务上设置的,srvctl add service 命令中会指定preferred和available实例列表、failovertype、commit_outcome等参数。如果服务依赖没配好,数据库实例都正常,但服务的preferred节点一直不正常,客户端连接就会被路由到不健康的实例上,造成间歇性连接超时。

我见过不少项目,建服务的时候图省事,用-s参数直接加了个服务名,preferred、available都没填,服务虽然建出来了,但两个实例都被当成候选实例,轮流接收连接。一旦其中一个实例有性能问题,整个服务的响应都会被拖累。所以服务层面的依赖和路由策略,真的不是写个服务名就完事。

2.4 特殊场景:GNS与SCAN扩展依赖

GNS(Grid Naming Service)是Oracle为无DNS环境设计的方案。它允许集群内部通过GNS来动态解析主机名和SCAN地址。如果使用GNS,SCAN IP就不需要预先在DNS中解析,而是由GNS从DHCP分配的地址池中动态分配。依赖链上,GNS依赖平台提供的DHCP与固定IP,SCAN VIP则依赖GNS的在线,SCAN监听又依赖SCAN VIP。

在数据中心生产环境里,大部分团队还是选择传统DNS方案,因为GNS要求网络侧有DHCP基础设施,对安全审计和网络管理来说改动太大。但如果是做实验环境或私有云内部快速搭建RAC,GNS会省掉很多DNS的协调成本。

不管用哪种方案,名称解析都必须在VIP/SCAN依赖链中提前规划好。实际运维中,SCAN解析、SCAN VIP与SCAN监听三者不齐,经常会导致客户端间歇性连不上:看起来是“应用连接池超时”,实际是SCAN监听所在节点漂移后,DNS转发缓存还没有刷新。

3. 把依赖关系“翻译成命令”——查询与诊断工具集

3.1 crsctl status resource:一眼看出状态与目标

排查依赖问题,第一件要做的事就是看资源状态。最常用的命令是:

crsctl stat res -t

这个命令会把集群中的所有资源按层级以树形打印出来,每一行都可以看到资源名、TARGET状态、STATE状态。TARGET列表示集群期望这个资源达到什么状态(ONLINE或OFFLINE),STATE列表示资源当前实际状态。当TARGET是ONLINE但STATE是OFFLINE或INTERMEDIATE时,说明资源正在被集群恢复,或者恢复卡住了。

用-v参数可以显示更多细节,比如启动次数、最后错误时间;用-p参数可以输出完整的资源profile,里面就是依赖关系的原始定义。

很多人只看STATE和TARGET,忽略掉中间的“错误信息”列。实际上资源启动失败后,crsd会记录最近一次的失败原因,很多情况下就直接告诉你是哪个被依赖资源没有在线,或者命令执行超时。这个信息真的比看日志快很多。

3.2 用资源profile读懂依赖字段

资源profile是理解依赖关系的核心文档。以数据库资源为例,执行:

crsctl config res ora.orcl.db -p

输出的字段虽然多,但最需要关注的其实是这几个:

  • START_DEPENDENCIES:硬依赖,列出启动前必须存在的资源列表。
  • STOP_DEPENDENCIES:停止时连带处理的资源。
  • CARDINALITY:资源实例数量,在RAC中通常为节点数。
  • RESTART_ATTEMPTS:失败后的最大重启尝试次数。

举个例子,假设输出是:

START_DEPENDENCIES=hard(ora.asm,ora.DATA.dg,ora.voting.dg) weak(type:ora.database.type) STOP_DEPENDENCIES=hard(intermediate:ora.asm)

这意味着数据库资源启动前,ASM实例和两个数据磁盘组必须在线;同时数据库资源对type为database类型的资源有弱依赖。停止依赖里的intermediate关键字表示:ASM状态只要不是ONLINE,数据库就视为需要停止。这就是为什么ASM实例重启时,数据库往往会被连带处理。

读profile的时候,我习惯把每个资源的START_DEPENDENCIES列出来,形成一个文本拓扑图,比如:

VIP -> LISTENER SCAN_VIP -> SCAN_LISTENER ASM -> DATA_DG -> DB DB -> SERVICE

这样一看就清楚整个集群的启动顺序了。

3.3 从日志与数据库视图多管齐下

依赖问题通常不是单一资源的问题,而是链路断了某个环节。除了crsctl查询,日志是另一个重要抓手。

集群层面的日志主要看$GRID_HOME/log/<hostname>/crsd.log,资源启动失败、依赖不满足、状态切换等信息都会记录在这里。比如crsd.log里出现“ORA-27504”或“Resource is not ONLINE”这样的词句,往往意味着某个依赖没有满足。CSS层面的心跳问题和脑裂问题要看cssd.logocssd.log,这个日志文件往往也是确认节点是否被逐出集群的关键证据。

数据库实例内部,可以通过如下SQL检查服务和实例状态:

SELECT inst_id, name, status FROM gv$active_services ORDER BY inst_id; SELECT username, program, service_name, count(*) FROM gv$session GROUP BY username, program, service_name;

gv$active_services能直接看到每个实例上对外可用的服务状态,如果某个服务在某个实例上没有出现在这个视图里,说明服务层面没有正确映射到这个实例,客户端的连接请求自然不会被分发过去。

3.4 用srvctl查看服务和数据库配置

crsctl负责看资源本身,而服务和数据库的配置细节,用srvctl更顺手。例如:

srvctl config database -d orcl -show-all srvctl config service -d orcl -s orcl_svc srvctl config nodeapps -s

第一条命令可以看到数据库的spfile路径、磁盘组、角色等;第二条命令能看到服务的preferred实例、available实例、failovertype等参数;第三条命令能看到SCAN的配置和监听端点。

在实际排查中,这些命令能快速回答“服务应该跑在哪些实例上”。如果服务资源在线,但连接始终过不来,十有八九是把服务的preferred实例列表配错了,或者数据库和服务的profile不一致。用srvctl命令调整后再crsctl stat res -t验证,比人肉去翻OCR靠谱得多。

4. 常见故障场景与处理——依赖配置出错长什么样

4.1 场景一:实例起来了,服务没起来

这是最常见的依赖问题。从crsctl stat res -t看,数据库资源是ONLINE,但对应的ora.orcl.orcl_svc.sys资源一直是OFFLINE,客户端的连接池全部报错。

排查顺序一般是:

srvctl config service -d orcl -s orcl_svc crsctl stat res ora.orcl.orcl_svc.sys -p

如果profile里服务资源的START_DEPENDENCIES中,没有正确依赖数据库资源,或者服务资源本身就是手动模式,则不会随数据库自动启动。处理上,可以先手工拉起服务:

srvctl start service -d orcl -s orcl_svc

但更稳妥的方式是修改服务的持久属性,让它在数据库资源路由时就自动启动。服务建好后,用--preferred--available-noautomatic这些选项控制它是否随实例启动。从这个场景也能看出,服务资源和数据库资源的依赖,不只是名称上的关联,而是真实影响着客户端可用性的关键配置。

4.2 场景二:VIP资源不停FAILOVER,监听注册不上

VIP在节点之间反复漂移,是网络和依赖链路的双重故障。现象通常表现为:某个节点的ora. .vip资源反复从ONLINE变成FAILOVER,监听始终注册不到VIP地址,客户端连接随机报错。

排查思路分两步。第一步看网络层,检查节点间心跳网络和业务网络的连通性,必要时用arping等工具,测试VIP地址是否能在节点间正常切换。第二步看服务器层,用crsctl stat res -t看VIP资源状态,用crsctl relocate resource ora.<node>.vip -n <node>把VIP手动重新定位,观察是否再次漂移。

这类问题很多情况下不是Oracle自身故障,而是网络设备自身的ARP缓存没有及时刷新,或者交换机上的端口安全策略禁止VIP地址的MAC漂移。如果确认是ARP缓存问题,网络侧需要调整老化时间;如果是端口安全策略,需要把VIP漂移的MAC加入白名单。依赖关系配置再对,底层网络不支持VIP漂移,一切白搭。

4.3 场景三:ASM没起来,数据库起不来

数据库实例启动时报ORA-15054或者ORA-17503,这类错误本质上就是ASM依赖不满足。比如ASM实例手动停止后,直接crsctl start res ora.orcl.db -n node1启动数据库,CRSD会检查数据库资源的START_DEPENDENCIES,发现ASM不在线,根本不会执行启动数据库的动作,或者执行到一半就报错。

正确处理是先把依赖链底层拉起来,尤其要保证ASM实例和一个可用的磁盘组在线:

crsctl start res ora.asm -n node1 crsctl stat res -t

等ASM资源状态变为ONLINE之后,再启动数据库资源,或者直接srvctl start database -d orcl让CRSD自己判断依赖。

这里要特别提醒:不要为了“绕过依赖”去修改数据库资源的START_DEPENDENCIES,把ASM依赖去掉。数据库实例强行在无ASM的情况下启动,会直接报错或产生不可预知的文件访问问题,修复成本远比等ASM恢复高得多。

4.4 场景四:改了网络配置后,VIP地址冲突或漂移异常

有时候机房调整IP规划,或者换交换机后,RAC环境里VIP资源开始报地址冲突。排查时会发现VIP虽然处于ONLINE状态,但监听日志里全是“Cannot assign requested address”之类的报错。

根源大概率是VIP地址掩码、网段和实际网卡配置不一致。Oracle的VIP资源在OCR里有独立的掩码和接口属性,如果只改了操作系统网卡的IP,没有同步更新OCR里对应VIP资源的属性,VIP启动时会绑定到错误的接口上,导致地址冲突。

处理上,需要先停掉VIP资源,然后更新资源属性,比如:

crsctl modify resource ora.node1.vip -attr "SUBNET=192.168.10.0/24,ADDRESS=192.168.10.66" crsctl start res ora.node1.vip -n node1

改完VIP,再依次启动监听和数据库服务。这类问题再次说明,RAC的资源和底层系统配置是强绑定的,改网络必须连集群资源配置一起评估。

4.5 场景五:依赖链过重,启动时间被无限拉长

依赖关系不是说配得越多越安全。过度配置会导致启动时大量相互等待,轻则启动慢,重则CRSD调度忙不过来,资源被误判为超时失败。

我见过一个环境,维护人员在数据库资源上配了所有磁盘组的hard依赖,又把服务依赖绑定在多个VIP和监听上,等于把整个集群一半的资源都串到了同一条链路上。每次节点重启,CRSD要等所有资源全部在线才开始启动数据库,一旦某个磁盘组状态轻微异常,整个链路卡住,数据库死活起不来。

正确的做法是,按最小依赖原则配置:ASM依赖磁盘组,数据库依赖ASM和自己需要的数据磁盘组,服务依赖数据库和监听,监听依赖VIP。不要过度依赖,也不要把无关资源强行绑定在一起。依赖关系是故障隔离的边界,不是业务上层的“强一致保证”。

5. 依赖关系的设计、调整与巡检习惯

5.1 设计阶段就输出一张依赖矩阵

部署RAC的第一天,就该把资源依赖关系梳理成文档。不必复杂,一张表格就够:

资源类型依赖资源依赖类型说明
VIP网络接口硬依赖漂移依赖底层网络可达
ListenerVIP / SCAN VIP硬依赖绑定VIP地址接收请求
ASM实例网络、OCR磁盘组硬依赖需要能读出OCR和voting file
数据库实例ASM实例、数据磁盘组硬依赖必须能挂载数据文件所在磁盘组
Service数据库实例、Listener硬依赖实例OPEN且监听在线才能对外
SCANDNS/GNS软/弱依赖DNS不可用时SCAN解析失败

这张表在安装、变更、扩容时都应该拿出来核对一遍。特别是扩容节点时,新增节点的VIP和监听资源如果没有按老节点的依赖方式配置,往往会在新节点加入集群时出现一大堆超时问题。

5.2 推荐的一组srvctl配置模板

以一套两节点RAC为例,常见的部署命令大概长这样:

# 添加数据库 srvctl add database -d orcl -o $ORACLE_HOME -c RAC -p +DATA/ORCL/spfileorcl.ora -a DATA,FRA -role PRIMARY # 添加服务 srvctl add service -d orcl -s orcl_app -preferred orcl1 -available orcl2 -failovertype TRANSACTION -commit_outcome TRUE -retention 86400 -failovermethod BASIC

数据库资源会自动依赖ASM实例和+DATA+FRA磁盘组。服务资源通过-preferred-available明确了主备路由实例,这样客户端通过服务名连接时,CRSD会保证它只在preferred实例在线时路由过去,preferred不可用时才路由到available实例。

如果需要自定义依赖,比如想让服务在数据库READ WRITE打开后再上线,可以使用-startoption等参数控制启动选项。但建议在完全理解依赖含义之前,先保持默认,避免制造出第4章里那些奇怪故障。

5.3 调整依赖关系的正确姿势

依赖关系并不是完全不能改,但要改得谨慎。调整依赖的基本命令是:

crsctl modify resource ora.orcl.orcl_svc.sys -attr "START_DEPENDENCIES=hard(ora.orcl.db,ora.LISTENER.lsnr)"

修改后需要重启资源才能完全生效。改动之前,强烈建议先用ocrconfig backup把当前OCR配置做一个备份,以便出问题时回退。依赖字段的语法一旦写错,CRSD可能直接拒绝加载资源,甚至影响整个集群启动。

我就是在一套升级环境中吃过亏:本想给服务资源追加一个依赖,结果把原有的依赖覆盖掉了,导致服务资源启动时不再等待数据库在线,直接报错。后来只能从备份恢复OCR,才把集群拉回来。所以调整依赖前,真的要打印profile留底、备份OCR、尽量选业务低峰期,并且先在测试环境验证。

5.4 巡检脚本化:依赖健康度一目了然

资源依赖能不能即时发现问题,关键看巡检是否到位。我日常使用的一个简单巡检思路是这样:

#!/bin/bash crsctl stat res -t -v | egrep "ora\.|ONLINE|OFFLINE|INTERMEDIATE|UNKNOWN|FAILED"

这个脚本会把所有资源状态列出来,再通过告警平台把包含OFFLINE或INTERMEDIATE的资源名提取出来,形成故障单。如果要更精细,可以针对每个关键资源单独检查:

crsctl status res ora.orcl.db -n node1 crsctl status res ora.orcl.orcl_svc.sys -n node1

巡检不是只盯数据库资源本身,而是要把依赖链上的所有节点都覆盖到。因为很多问题是先出现在底层,再传递到上层。VIP状态诡异、监听注册不全、ASM磁盘组有异常,都会在依赖链上形成连锁反应。如果脚本能提前捕捉到一个磁盘组状态变成DEGRADED,就能在数据库实例真正出问题之前告警,这比事后救火要省心得多。

回到开头那起半夜故障,后来我把那个环境的资源profile全部导出来,把每一层依赖关系补成矩阵文档,发现确实是服务资源的START_DEPENDENCIES少了内容,导致服务没有跟随实例启动。补上依赖、确认VIP和监听都在线之后,整套集群很快恢复稳定。我个人最大的体会是:RAC不是一堆服务的堆叠,而是一张有向依赖网。排查故障时多问自己三句话——这个资源依赖谁?谁依赖它?被依赖方挂了,它会怎样?多问几遍,绝大多数资源类问题都能快速定位。另外一个很实用的习惯是,闲的时候在一台测试机上把VIP、ASM、数据库、服务分别手动stop和start,观察依赖链如何传递,比看十篇文档都有用。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询