必须使用 address_list 语法并配置 failover_mode 才能启用 rac 故障转移;需通过 tnsnames.ora 管理连接串,初始化时调用 init_oracle_client(),连接池设 max_lifetime_session=0,并停实例而非监听来验证故障转移。

cx_Oracle 连接字符串里必须用 ADDRESS_LIST 才能启用 RAC 故障转移
默认单实例连接方式(比如只写 host=rac-node1)完全不触发 RAC 的 SCAN 或故障转移机制。cx_Oracle 要识别 RAC 集群,必须显式使用 Oracle Net 的 ADDRESS_LIST 语法,并开启 FAILOVER=on。
常见错误是把 RAC 连接串写成普通主机+端口形式,结果节点一宕,cx_Oracle.connect() 直接抛 ORA-12170: TNS:Connect timeout occurred,根本等不到切换。
- 正确结构:用
(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=node1-vip)(PORT=1521)) (ADDRESS=(PROTOCOL=TCP)(HOST=node2-vip)(PORT=1521))) - 必须加
(CONNECT_DATA=(SERVICE_NAME=myservice)(FAILOVER_MODE=(TYPE=SELECT)(METHOD=BASIC)(RETRIES=3)(DELAY=5))) - 整个串要套在
(DESCRIPTION=...)里,否则 cx_Oracle 解析失败,报ORA-12154: TNS:could not resolve the connect identifier
使用 tnsnames.ora 文件比硬编码连接串更可靠
把 RAC 连接描述写进 $ORACLE_HOME/network/admin/tnsnames.ora(或通过 cx_Oracle.init_oracle_client() 指定 config_dir),然后在 Python 里只传别名,能规避字符串拼接错误、特殊字符转义问题,也方便 DBA 统一维护。
注意:Python 进程启动前,tnsnames.ora 必须已存在且可读;如果用 init_oracle_client(config_dir="/path/to/network"),路径末尾不能带斜杠,否则 Oracle 客户端会静默忽略该目录。
- tnsnames.ora 示例片段:
(MYRAC = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = rac1-vip)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCP)(HOST = rac2-vip)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = orcl) (FAILOVER_MODE = (TYPE = SELECT)(METHOD = BASIC)(RETRIES = 3)(DELAY = 5)) ) ) ) - Python 中调用:
cx_Oracle.connect("user/pass@MYRAC") - 若环境无 $ORACLE_HOME,必须显式调用
init_oracle_client(),否则报cx_Oracle.DatabaseError: DPI-1047: Cannot locate a 64-bit Oracle Client library
连接池配置要设 max_lifetime_session=0 防止失效连接滞留
RAC 故障转移后,旧连接的后台会话可能被数据库强制 kill,但 cx_Oracle 的连接池默认保留这些“半死”连接,后续 execute() 会直接报 ORA-03113: end-of-file on communication channel。
关键参数不是 max_sessions 或 increment,而是 max_lifetime_session——它控制连接在池中存活最长时间。设为 0 表示禁用自动过期,看似反直觉,实则因为 RAC 场景下连接有效性依赖网络和实例状态,靠时间判断不如靠实时探测。
- 推荐池初始化写法:
pool = cx_Oracle.create_pool( user="user", password="pass", dsn="MYRAC", min=2, max=10, increment=2, getmode=cx_Oracle.POOL_GETMODE_WAIT, max_lifetime_session=0, # 关键:禁用基于时间的清理 session_callback=set_session_callback # 可选:每次取连接时做健康检查 ) - 更稳妥的做法是在
session_callback里执行SELECT 1 FROM DUAL,捕获异常后主动raise cx_Oracle.Error,让池自动丢弃该连接
测试故障转移必须关掉数据库实例,不能只停监听
很多人用 lsnrctl stop 模拟故障,但这只会让新连接失败,已建立的连接仍能工作(因为监听器不参与数据传输),根本测不出 FAILOVER 是否生效。真正验证得停掉一个数据库实例(如 srvctl stop instance -i orcl_1 -d orcl),再发查询看是否自动切到另一节点。
观察点有两个:一是应用日志里是否出现 ORA-03114: not connected to ORACLE 后迅速恢复(说明重连成功);二是查 v$session 确认 machine 和 inst_id 是否变了。如果没变,大概率是连接串漏了 FAILOVER_MODE 或用了错误的 SERVICE_NAME(比如用了 INSTANCE_NAME)。
RAC 高可用不是开个开关就完事的事——连接串结构、客户端初始化、连接池策略、验证方法,四个环节缺一不可。少配一个括号,或者测试时只停监听,都会让你以为“已经好了”,上线后第一个节点宕机就露馅。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











