客户端连不上、切换不自动、某台机器被挡在外面,这三类问题经常同时出现在“连接层”。前者归 TNSNAMES 管,后者归 sqlnet.ora 管,两边都不需要改数据库参数。本文上半部分讲怎么让客户端在 RAC 里自动分流和故障转移,下半部分讲怎么用监听层做 IP 白名单和黑名单,并给出单机与 RAC 的差异。
所有示例基于 Oracle 19c,单机监听端口示例为 1526,RAC 使用 SCAN。主机名、IP、服务名都要按实际环境替换。
一、TNSNAMES:让连接自动选节点
一个最朴素的 TNS 条目只写了地址和服务名,能连上,但不会分流,也不会在主节点故障时自动重连。加上下面几个参数后才有高可用行为:
LOAD_BALANCE = ON:在地址列表中随机挑选,分摊新连接。FAILOVER = ON:某个地址连不上时尝试下一个。FAILOVER_MODE:连接建立后,实例故障时会话级的重试与重建。
要区分两件事:FAILOVER 管的是“连接建立阶段换地址”,FAILOVER_MODE 管的是“会话已经建立后,实例挂了怎么办”。前者对所有环境有效,后者只有 RAC(或配置了 Data Guard 的 TYPE=SESSION 场景)才有意义。
1. 按 VIP 配置多节点
TEST =
(DESCRIPTION =
(LOAD_BALANCE = ON)
(FAILOVER = ON)
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = ora19c01)(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = ora19c02)(PORT = 1521))
)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = test)
(FAILOVER_MODE =
(TYPE = SELECT)
(METHOD = BASIC)
(RETRIES = 180)
(DELAY = 5)
)
)
)
节点更多时继续往 ADDRESS_LIST 里加 ADDRESS 即可。LOAD_BALANCE 只在 ADDRESS_LIST 内生效,写在 DESCRIPTION 下但没有地址列表时不起作用。
FAILOVER_MODE 的参数含义:
TYPE = SELECT:故障时把未提交的 SELECT 重新执行。SESSION只重建会话,不重放语句;NONE关闭。METHOD = BASIC:连接失败时立即尝试下一个地址。PRECONNECT会预先建立备用连接,切换更快但常驻占用资源。RETRIES = 180、DELAY = 5:每 5 秒重试一次,最多 180 次,合计 15 分钟。
TYPE = SELECT 只对查询友好。有未提交事务的会话切换过去会失败,这是设计如此,不要指望它接管写事务。
2. 用 SCAN 的三种写法
RAC 环境下更推荐连 SCAN,由 SCAN 监听把连接分到各节点,客户端不需要知道节点名单。
多个 SCAN IP,显式地址列表:
TEST =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = ora19c-scan-ip1)(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = ora19c-scan-ip2)(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = ora19c-scan-ip3)(PORT = 1521))
)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = test)
(FAILOVER_MODE =
(TYPE = SELECT)
(METHOD = BASIC)
(RETRIES = 180)
(DELAY = 5)
)
)
)
单个 SCAN 主机名,交给 DNS 轮询:
TEST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = ora19c-scan)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = test)
(FAILOVER_MODE =
(TYPE = SELECT)
(METHOD = BASIC)
(RETRIES = 180)
(DELAY = 5)
)
)
)
单个 SCAN IP:
TEST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = ora19c-scan-ip1)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = test)
(FAILOVER_MODE =
(TYPE = SELECT)
(METHOD = BASIC)
(RETRIES = 180)
(DELAY = 5)
)
)
)
只有多个 SCAN 地址时才需要 LOAD_BALANCE。单个 SCAN 主机名时,DNS 返回多个 A 记录,客户端默认取第一个,开 LOAD_BALANCE 反而可能因为地址顺序问题带来额外延迟,按实际测试结果决定。
3. 负载均衡不是“智能调度”
原文里有一张“按业务场景选算法”的表,把 OLTP 对应会话计数、OLAP 对应响应时间。需要说清楚:客户端 LOAD_BALANCE 做的是连接建立时的随机选择,不是按负载动态调度,也不会在运行中迁移会话。真正的运行时负载均衡要靠服务端的连接池、Resource Manager 或中间件。
如果业务是短连接为主,客户端随机分流效果明显;如果是长连接,连接一旦建立就不再变化,节点间会逐渐倾斜。这种情况用 SCAN 加服务端配置更合适。
二、sqlnet.ora:在监听层做 IP 访问控制
比起在数据库里建触发器,sqlnet.ora 的限制发生在连接建立阶段,成本低得多,也不会因为触发器失效而被绕过。三个参数:
tcp.validnode_checking = yes
tcp.invited_nodes = (ip1, ip2) # 白名单
tcp.excluded_nodes = (ip1, ip2) # 黑名单
规则:
- 开
invited_nodes时,不在列表里的 IP 和主机名全部拒绝。 - 开
excluded_nodes时,只拒绝列表中的地址,其余放行。 - 两者互斥。同时存在时
invited_nodes优先。 - 必须把本机地址和集群其他节点加进白名单,否则监听可能起不来。
- 只对 TCP 生效,IPC 连接不受影响。
- 改完执行
lsnrctl reload或重启监听即可,不需要重启数据库。
白名单模式风险更高:漏掉一个应用服务器就是一次故障。上线前先把所有来源 IP 列全,或者先用黑名单挡掉明确的恶意地址。
1. 黑名单:拒绝某台机器
在数据库主机 192.168.61.137 上编辑 $ORACLE_HOME/network/admin/sqlnet.ora:
# sqlnet.ora Network Configuration File: /oracle/app/19.3.0/db_1/network/admin/sqlnet.ora
# Generated by Oracle configuration tools.
NAMES.DIRECTORY_PATH= (TNSNAMES, ONAMES, HOSTNAME)
SQLNET.ALLOWED_LOGON_VERSION_SERVER=8
SQLNET.ALLOWED_LOGON_VERSION_CLIENT=8
tcp.validnode_checking = yes
tcp.excluded_nodes = (192.168.61.138)
重启监听:
[oracle@ora19c-single admin]$ lsnrctl stop
[oracle@ora19c-single admin]$ lsnrctl start
[oracle@ora19c-single admin]$ lsnrctl status
此时如果监听原本没在跑,stop 会报 TNS-12541: TNS:no listener,属于正常现象,直接 start 即可。
在 192.168.61.138 上验证:
[oracle@ora19c-gt admin]$ tnsping single
TNS Ping Utility for Linux: Version 19.0.0.0.0 - Production on 03-APR-2026 19:38:43
...
Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.61.137)(PORT = 1526)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = single)))
TNS-12547: TNS:lost contact
[oracle@ora19c-gt admin]$ sqlplus 'system/[email protected]:1526/single'
ERROR:
ORA-12547: TNS:lost contact
注意报错是 TNS-12547 而不是“拒绝连接”。这是监听接受了 TCP 握手后在协议层断开,容易被误判成网络问题。看到 12547 又确认网络通,先查 sqlnet.ora。
2. 白名单:只允许指定机器
把 excluded_nodes 注释掉,换成 invited_nodes,本机 127.0.0.1 和自身 IP 必须写进去:
tcp.validnode_checking = yes
#tcp.excluded_nodes = (192.168.61.138)
tcp.invited_nodes = (127.0.0.1, 192.168.61.137, 192.168.61.138)
同样重启监听后,从 192.168.61.138 连接应当成功:
[oracle@ora19c-gt ~]$ sqlplus 'system/[email protected]:1526/single'
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
如果本机 sqlplus / as sysdba 用的是 IPC 或 BEQ,不受影响;但通过 TCP 连本机监听时,127.0.0.1 和主机名解析出的 IP 都要在列表里。主机名和 IP 混用时,Oracle 会做反向解析,解析结果不一致也会被拒——这是白名单最常见的坑,建议统一写 IP。
3. 顺手关掉本地认证
如果希望禁止 sqlplus / as sysdba 这类本地 OS 认证登录,在 sqlnet.ora 里加一行:
sqlnet.authentication_services=(none)
这一条影响面很大:所有依赖 OS 认证的脚本、RMAN 备份、crontab 都会失效。改之前先确认没有这类任务,或者保留密码文件认证作为替代。
4. RAC 环境的差异
配置内容与单机一致,差别在生效范围:每个节点都有自己的 sqlnet.ora,要逐个修改;监听要用 srvctl 管理,SCAN 监听也要重启。
srvctl stop listener -n ora19c-rac01
srvctl start listener -n ora19c-rac01
srvctl status listener -n ora19c-rac01
srvctl stop listener -n ora19c-rac02
srvctl start listener -n ora19c-rac02
srvctl status listener -n ora19c-rac02
srvctl stop scan_listener
srvctl start scan_listener
lsnrctl status LISTENER_SCAN1
只改一个节点会出现“连得上、连不上全看 SCAN 把你分到哪”的随机故障。白名单里还要包含所有节点 VIP、SCAN VIP 以及客户端网段,否则节点间的心跳或服务注册可能被自己挡住。
三、检查清单
- TNS 条目先用
tnsping确认解析到预期地址,再看sqlplus是否成功。 - RAC 场景确认
SERVICE_NAME是服务名而不是实例名,srvctl status service看服务是否在目标节点运行。 - 出现
ORA-12547/TNS-12547,先排除网络,再查sqlnet.ora的excluded_nodes。 - 开白名单前,把本机、集群节点、SCAN VIP、应用服务器 IP 全部列全。
- 改完用
lsnrctl reload生效,RAC 用srvctl逐节点重启并检查lsnrctl status。
原文首发于微信公众号「止水研习社」。
文章评论