oracle rac应用秒级故障切换需服务端fan启用、ons跨节点互通、客户端禁用tns干扰参数三者缺一不可;仅设fanenabled=true无效,必须验证service状态、逐节点onsctl ping、精简jdbc url并显式启用fcf。

Oracle RAC 应用连接池要实现秒级故障切换(1–3 秒),必须绕开 TNS 层的重试逻辑,走 FCF(Fast Connection Failover)事件驱动路径——只设 oracle.jdbc.fanEnabled=true 没用,漏掉服务端 FAN 或客户端 ONS 通信任一环,切换就退化成 20+ 秒的 connect-time failover。
FCF 生效的三个硬性前提缺一不可
FCF 不是“配个参数就生效”的功能,而是服务端发事件、网络传事件、客户端收事件、连接池响应事件的完整链路:
- 服务端 RAC service 必须启用 FAN:执行
srvctl config service -d <db></db>,确认FAILOVER_TYPE不是NONE,且 service 状态为ENABLED - ONS(Oracle Notification Service)必须通:在应用服务器上逐节点执行
onsctl ping -h <node_ip> -p 6200</node_ip>(默认端口),不能只 ping 本地onsctl ping - 客户端 JDBC URL 不能含 TNS 层干扰项:禁用
LOAD_BALANCE=ON、FAILOVER=ON、RETRIES等参数,URL 只保留基础格式,例如:jdbc:oracle:thin:@myrac-scan:1521/my_service
UCP 连接池启用 FCF 的正确姿势
用 UCP(Universal Connection Pool)时,仅设置 JDBC 属性是无效的,必须显式调用池实例方法:
- 创建池后,必须调用
pool.setFastConnectionFailoverEnabled(true),而不是依赖connection.setProperty("oracle.jdbc.fanEnabled", "true") - service 名必须与 RAC 中定义的完全一致(大小写敏感),且该 service 是通过
srvctl add service添加并启用-e SELECT或-e SESSION - 禁用隐式连接缓存(implicit caching):调用
pool.setImplicitCachingEnabled(false),否则 FCF 清理掉失效连接后,应用仍可能从缓存中取出坏连接
Spring Boot 场景下为什么 AbstractRoutingDataSource 是必选项
Spring Boot 原生 HikariCP 或 Tomcat JDBC Pool 不感知 RAC 实例状态,也无法响应 FAN 事件——它们只管“连得上”,不管“连的是哪个活实例”:
-
AbstractRoutingDataSource是唯一能动态路由到不同数据源的方案,需配合ThreadLocal绑定当前会话期望的实例 ID(如"rac-node1") - 必须自行实现健康检查线程,定期执行
SELECT 1 FROM DUAL并剔除不可用节点,否则路由逻辑会把请求发给已宕机的实例 - 事务方法需用切面拦截,在
@Transactional开始前校验目标数据源存活,避免事务启动后才发现连接失败
ojdbc8 驱动和参数匹配的隐蔽坑
Oracle 19c RAC 环境下,用错驱动或参数会导致“能连不能用”:
- 必须用
ojdbc8(如com.oracle.database.jdbc:ojdbc8:21.10.0.0),ojdbc6无法解析 SCAN 地址中的负载均衡信息,也缺失 Application Continuity 协议字段 - 禁用
oracle.jdbc.useFetchSizeWithLongColumn(默认true),否则查询含 LOB 字段时会报ORA-22922: nonexistent LOB value - JDBC URL 若显式写死多个地址(如
(ADDRESS=(HOST=node1)...)(ADDRESS=(HOST=node2)...)),会触发 TNS 层轮询逻辑,与 FCF 冲突;应只用 SCAN 地址
真正卡住 FCF 的地方往往不在代码里,而在服务端 service 状态、ONS 网络连通性、以及连接池是否关闭了隐式缓存——这三个点不验证清楚,调再多客户端参数都没意义。











