Oracle RAC的多节点架构本身就是为了分摊压力、提升可用性,但如果客户端连接配置不到位,就会出现所有会话集中在一个实例上的尴尬局面,负载均衡形同虚设。客户端负载均衡是RAC连接管理中最基础也最容易出错的一环,它决定了一条新建连接最终落在哪个节点上。本文从参数原理、配置方式、常见问题三个层面展开,帮助读者把客户端负载均衡真正配置到位。

客户端负载均衡的核心参数与工作原理
先厘清一个容易混淆的概念:客户端负载均衡和透明应用故障切换(TAF)是两件不同的事。负载均衡负责的是建立连接时决定连到哪个节点,而故障切换负责的是连接断开后如何切换到存活节点。前者由连接串中的LOAD_BALANCE参数控制,后者由FAILOVER参数以及TAF相关设置控制,两者可以独立开启也可以同时开启。
LOAD_BALANCE的工作机制其实很简单:当连接描述中包含多个地址(ADDRESS)或多个节点信息时,客户端会在建立连接前随机挑选一个地址发起请求。注意这里是纯随机,不带权重,也不感知各个节点的当前负载。这意味着如果客户端的连接数不够多、或者连接生命周期长短差异很大,随机分配的统计特性就会失真,出现明显的倾斜。理解这一点非常重要,因为很多人以为开了负载均衡就能自动把压力平摊,实际上它只是随机分发,后期的均衡还要靠应用侧的连接池来稳住。
与之配合的FAILOVER参数默认值就是on,当它开启时,客户端会按顺序尝试地址列表中的下一个节点。如果同时开启LOAD_BALANCE和FAILOVER,行为是先随机打乱地址顺序,再依序尝试,这样既做到了均衡分发又保留了故障切换能力。如果只想按固定顺序连接(比如优先本机房节点),就需要显式写LOAD_BALANCE=off,此时的地址列表顺序就是优先级顺序。
三种常见配置方式的完整示例
方式一:tnsnames.ora传统配置
对于使用OCI客户端、sqlplus或老的C/S程序,负载均衡靠tnsnames.ora文件实现。下面是一个双节点RAC的典型配置:
RACDB =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.10.11)(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.10.12)(PORT = 1521))
(LOAD_BALANCE = yes)
(FAILOVER = on)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = racdb)
)
)
这里写了两个VIP地址,开启LOAD_BALANCE后,客户端每次新建连接时会随机选择其中一个VIP。需要注意的是,地址里写的一定要是VIP而不是物理IP,因为故障切换时VIP会漂移到存活节点,客户端才能无感知地重连成功。如果写成物理IP,节点宕机后该地址直接不可达,连接建立阶段就会失败。
方式二:JDBC瘦客户端连接串
Java应用大多不走tnsnames.ora,而是直接使用JDBC URL。Oracle提供的长格式连接串同样支持这两个参数:
String url = "jdbc:oracle:thin:@(DESCRIPTION=" +
"(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.10.11)(PORT=1521))" +
"(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.10.12)(PORT=1521))" +
"(LOAD_BALANCE=yes)(FAILOVER=on)" +
"(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=racdb)))";
这种写法的好处是不依赖客户端本地配置文件,应用部署时不需要额外分发tnsnames.ora,版本管理也更清晰。缺点是连接串写死在代码或配置文件里,节点IP变更时需要修改并重新发布,因此更推荐结合方式三的SCAN地址一起使用。
方式三:SCAN地址简化配置
从11g R2开始,Oracle引入了SCAN(Single Client Access Name)机制。客户端只需要写一个SCAN地址,连接请求会先到达SCAN监听器,由它根据各节点的负载情况把连接定向到负载较轻的节点。这实际上把随机分发升级成了服务端感知的分发,配合客户端的LOAD_BALANCE效果更好:
RACDB_SCAN =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = scan-rac.ippipp.com)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = racdb)
)
)
SCAN地址通过DNS轮询解析到三个SCAN VIP,客户端随机拿到其中一个,再由SCAN监听器转发到实例。这种配置极大简化了客户端维护工作,节点扩容或缩容时客户端完全不用改动。使用SCAN的前提是DNS或GNS配置正确,三个SCAN IP都要能正常解析,否则会出现连接时快时慢的问题。
常见问题与排查思路
负载倾斜:一个节点忙死一个节点闲死
这是最常见的问题,原因通常有几个。第一是短连接场景下随机分发的样本量太小,比如一上午只有几十个连接,随机结果自然不均匀,这种情况建议应用侧改用连接池,把随机误差摊平到整个生命周期。第二是应用服务器本地的DNS缓存或hosts文件写死了某个节点地址,导致所有连接都走同一个入口,需要检查/etc/hosts中是否残留了旧的节点IP映射。第三是服务定义问题,如果数据库侧的服务(Service)只在单实例上激活,客户端无论怎么随机,最终都只能连到那个实例,此时需要用srvctl status service确认服务的首选节点和可用节点配置。
连接卡顿与ORA-12545报错
ORA-12545报错提示因目标主机或对象不存在导致连接失败,在RAC环境里最典型的原因是客户端使用了SCAN连接,但连接重定向阶段拿到了节点的VIP或主机名,而客户端本地无法解析这个主机名。排查方法是在客户端机器上分别nslookup或pingSCAN名称和各节点的VIP主机名,确保都能解析。如果客户端环境不允许解析节点主机名,可以在数据库参数上做文章,例如确保监听注册的是VIP地址而非主机名,或者在客户端hosts文件中补充节点VIP的映射条目。
TAF切换不生效
有些同学配置了故障切换但实例重启后会话直接报错断开,多半是把TAF理解错了。连接级别的FAILOVER=on只保证建立连接阶段可以尝试下一个地址,会话运行过程中节点宕机,恢复需要依赖TAF的FAILOVER_MODE配置。下面是带TAF的完整示例:
RACDB_TAF =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.10.11)(PORT = 1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.10.12)(PORT = 1521))
(LOAD_BALANCE = yes)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = racdb)
(FAILOVER_MODE =
(TYPE = SELECT)
(METHOD = BASIC)
(RETRIES = 3)
(DELAY = 5)
)
)
)
其中TYPE=SELECT表示正在执行的查询在切换后可以继续返回结果,METHOD=BASIC表示切换时才建立备用连接,开销最小。要注意TAF对DDL和未提交的DML无能为力,切换后事务会回滚,应用必须有重试逻辑。另外,如果使用SCAN,更推荐把TAF配置放到服务端,通过srvctl add service的-failover_restore等参数或DBMS_SERVICE包统一管理,客户端就不用维护复杂的故障切换细节了。
总结
客户端负载均衡的关键点可以归纳为三句话:地址写VIP或SCAN而不是物理IP,参数上LOAD_BALANCE与FAILOVER各司其职,运行期均衡靠连接池而不是靠随机分发本身。优先采用SCAN加服务端服务划分的方案,客户端配置最简单,扩缩容成本最低。遇到负载倾斜或连接报错时,按照DNS解析、VIP状态、服务配置的顺序逐层排查,绝大多数问题都能快速定位。
Oracle RAC客户端负载均衡JDBC连接修改时间:2026-09-05 03:38:37