taf是唯一保障长连接不中断的客户端failover机制;client-side connect time failover仅作用于初始连接,连接建立后节点故障即断开,对tomcat等长连接池场景无效;tnsnames.ora中failover_mode必须嵌套在connect_data内,且需配合连接池健康检测(如testonborrow)和正确jdbc url配置(含oracle.net.tns_admin)才能生效。

Oracle RAC节点切换时Tomcat连接池“挂死”,本质不是连接池本身坏了,而是它没收到故障通知、又没配置TAF,结果卡在已失效的连接上等响应——直到超时(可能几十秒甚至几分钟),期间所有新请求排队阻塞。
为什么Connection Pool不自动切到活节点
Tomcat默认用BasicDataSource或HikariCP这类连接池,它们只管复用已有连接,不感知RAC底层实例状态。只要JDBC URL里没配FAILOVER_MODE,哪怕RAC节点A挂了,连接池仍会把请求发给A对应的VIP,然后卡住等TCP超时或Oracle报错(如ORA-03113)。
- Client-Side Connect Time Failover(
FAILOVER=ON)只在建连时起作用,对已建立的连接完全无效 - Tomcat连接池初始化后,所有连接都绑定到某个RAC实例的VIP;切换发生时,这些连接不会自动重路由
- 若应用没做连接有效性校验(比如
testOnBorrow=true+validationQuery=SELECT 1 FROM DUAL),坏连接就一直留在池里
tnsnames.ora里必须写对FAILOVER_MODE嵌套位置
很多人写了FAILOVER=ON就以为启用了TAF,其实那只是connect time failover。真正让运行中连接自动迁移的,是FAILOVER_MODE,而且它必须放在CONNECT_DATA块内部,不能挂在DESCRIPTION顶层。
- ❌ 错误写法(被Oracle静默忽略):
(DESCRIPTION=(FAILOVER_MODE=(TYPE=select))(ADDRESS=...)(CONNECT_DATA=(SERVICE_NAME=...))) - ✅ 正确写法:
(DESCRIPTION=(ADDRESS=...)(CONNECT_DATA=(SERVICE_NAME=...)(FAILOVER_MODE=(TYPE=session METHOD=basic RETRIES=3 DELAY=5)))) -
TYPE=session比TYPE=select更轻量,适合OLTP场景;METHOD=basic避免连接数翻倍,RETRIES/DELAY控制故障恢复窗口
JDBC URL里别漏掉oracle.net.tns_admin和tns_alias
Tomcat启动时,JDBC驱动需要读取tnsnames.ora,但默认不自动找。如果只写jdbc:oracle:thin:@myrac却不告诉驱动tnsnames.ora在哪,它就会当普通单机地址解析,彻底绕过TAF逻辑。
- 必须显式指定路径:
jdbc:oracle:thin:@myrac?oracle.net.tns_admin=/u01/app/oracle/network/admin - 确保
/u01/app/oracle/network/admin/tnsnames.ora存在且权限正确(Tomcat进程可读) - 检查
myrac这个alias是否真在tnsnames.ora里定义,并且内容含FAILOVER_MODE - 别依赖
HOST直连(如@192.168.1.10:1521/orcl):那样根本走不了TAF
Tomcat连接池要配健康检测,否则坏连接永远不释放
即使TAF生效,连接池里已存在的连接也不会自动重建。得靠连接池自身的验证机制把坏连接踢掉,再从池里拿新连接(这时才会触发TAF重连)。
- HikariCP推荐配置:
connection-test-query=SELECT 1 FROM DUALvalidation-timeout=3000test-on-borrow=true(或test-on-return) - DBCP2对应参数:
validationQuery=SELECT 1 FROM DUALtestOnBorrow=trueremoveAbandonedOnBorrow=true - 注意:验证语句必须轻量,别用
SELECT SYSDATE FROM DUAL之类带函数调用的——某些旧驱动在TAF切换过程中执行失败率更高
最常被忽略的一点:TAF不是“开关一开就自动续命”,它依赖客户端网络层能及时收包、JDBC驱动版本支持、以及连接池配合验证。三者缺一,故障时照样挂死。尤其当tnsnames.ora路径错、FAILOVER_MODE位置错、或连接池没开testOnBorrow时,现象都是“看起来连上了,但请求全卡住”。











