FAN不生效的根本原因是客户端未启用oracle.jdbc.fanEnabled=true且服务端未通过srvctl modify service -e SERVICE_RESTART启用FAN事件,二者缺一不可。
为什么 FAN 不生效,连接池还在往宕机节点发请求?
根本原因通常是 jdbc 连接串里没启用 fan,或者 oracle rac 侧没开服务端 fan 支持。fan 是双向机制:数据库要发事件,jdbc 驱动要能收并响应。光配客户端没用。
-
oracle.jdbc.fanEnabled=true必须显式加在连接 URL 或Properties里,缺省是false - 对应的服务(
service_name)必须在 RAC 上用srvctl modify service -f ... -e SERVICE_RESTART -m BASIC -z 1启用了 FAN 事件(-e SERVICE_RESTART是关键) - 使用
OracleDataSource而非DriverManager.getConnection(),后者不支持 FAN 回调注册 - 确认数据库版本 ≥ 11.2,且监听器已配置
ENABLE=ON在listener.ora的USE_DEDICATED_SERVER外围(旧版监听器可能静默丢弃 FAN 包)
OracleConnectionPoolDataSource 怎么配合 FAN 做连接清理?
FAN 本身不自动 close 连接,它只通知“某节点不可用”,清理动作得由连接池自己触发。主流池(如 HikariCP、UCP)靠监听 oracle.ucp.UniversalConnectionPoolAdapter 的 connectionBorrowed 和 connectionReturned 事件间接响应;但原生 OracleConnectionPoolDataSource 需手动集成。
- 必须设置
setFastConnectionFailoverEnabled(true),否则即使收到 FAN 事件也不触发失效检查 - 搭配
setConnectionPoolName("my_pool")后,需在应用启动时调用UniversalConnectionPoolManagerImpl.getUniversalConnectionPoolManager().getConnectionPool("my_pool").setInactiveConnectionTimeout(30),让池定期驱逐卡在宕机节点上的连接 - 不要依赖
setTimeToLiveConnectionTimeout()—— 它只管空闲连接存活时间,对已借出但目标节点宕机的连接无效 - 示例关键参数:
jdbc:oracle:thin:@//rac-scan:1521/my_service?oracle.jdbc.fanEnabled=true&oracle.net.disableOob=true(disableOob可避免某些网络设备拦截 FAN UDP 包)
连接池返回 SQLException: IO Error: Connection reset 还继续重试?
这是典型 FAN 滞后或未覆盖场景:节点刚宕,FAN 事件还没传到客户端,连接池已把旧连接借出,执行时 TCP 层断连。此时不能等 FAN,得靠连接验证兜底。
- 所有连接池都必须开启
connection-test-query或等效机制(如 HikariCP 的connection-test-query=SELECT 1 FROM DUAL),且设为test-on-borrow=true - Oracle 官方推荐用
isValid(2)替代 SQL 查询,更轻量,但需驱动 ≥ 12.1;老版本只能用查询 - 别设过长的
validation-timeout(建议 ≤ 3 秒),否则验证本身会拖慢业务线程 - 注意:FAN 通知的是“服务不可用”,不是“连接已断”。所以验证逻辑和 FAN 是两层防御,缺一不可
为什么 UCP 池里看到 getAvailableConnectionsCount() 没变,但实际请求全失败?
UCP 默认不主动探测连接有效性,getAvailableConnectionsCount() 只统计“没被借出”的连接数,不管它们是否还连着活节点。FAN 事件进来后,UCP 会标记对应物理连接为“stale”,但不会立刻从池中移除,除非被借出时验证失败或超时。
- 调用
getConnectionPool().purgeStaleConnections()可强制清理,但别在每次 FAN 事件后无脑调——它会锁池,影响并发 - 更稳妥的做法是设
setAbandonedConnectionTimeout(60),让 UCP 自动回收长时间未归还且状态可疑的连接 - 监控重点不是可用数,而是
getFailedBorrowCount()和getInvalidConnectionCount(),这两个飙升才说明 FAN + 清理链路有问题 - 别忽略日志:打开
oracle.ucp.level=FINEST,搜FAN_EVENT_RECEIVED和INVALIDATE_CONNECTION,确认事件是否真被接收并处理
srvctl modify service 那一步,以及客户端漏设 fastConnectionFailoverEnabled —— 这两个一缺,其他全白配。

















