oracle 19c rac连接负载均衡必须client-side与server-side协同生效:client-side要求load_balance=on置于每个description内(非顶层或connect_data),且多address须用description_list包裹并分别配置;server-side依赖remote_listener指向scan地址、pmon每3秒上报v$servicemetric.current_load,缺一则连接全打首节点。

LOAD_BALANCE=on 放错位置,客户端根本没启用随机选地址
很多人在 tnsnames.ora 或 JDBC URL 里写了 LOAD_BALANCE=on,但连接还是全打第一个节点——不是 Oracle 不干活,是这行参数压根没被 TNS 解析器读到。
必须满足三个硬性条件:
-
LOAD_BALANCE=on要放在DESCRIPTION块内,且紧邻ADDRESS后面(不能塞进CONNECT_DATA,也不能挂在DESCRIPTION_LIST外层) - 如果用多个 VIP 直连(比如
rac1-vip和rac2-vip),必须用DESCRIPTION_LIST包裹,并且每个DESCRIPTION都要单独写一次LOAD_BALANCE=on - 只配 SCAN 地址(单个
HOST=rac-scan)时,LOAD_BALANCE=on无效——TNS 没得可选,直接忽略
错误示例:(DESCRIPTION=(ADDRESS=...)(CONNECT_DATA=...)(LOAD_BALANCE=on)) → 不生效
正确示例:(DESCRIPTION_LIST=(LOAD_BALANCE=on)(DESCRIPTION=(ADDRESS=(HOST=rac1-vip))(CONNECT_DATA=(SERVICE_NAME=mydb)))(DESCRIPTION=(ADDRESS=(HOST=rac2-vip))(CONNECT_DATA=(SERVICE_NAME=mydb))))
SCAN Listener 看不到各节点真实负载,只能 round-robin
客户端随机挑了个地址发过去,但最终落到哪个实例,由 SCAN Listener 决定。它靠什么判断?不是猜,是看每个实例通过 PMON 主动上报的 V$SERVICEMETRIC.CURRENT_LOAD。
常见失效点:
-
REMOTE_LISTENER指向了 VIP、localhost 或错误的 GNS VIP(若用 GNS,必须指向 GNS VIP,不是 SCAN) - 改完
REMOTE_LISTENER后没立刻执行ALTER SYSTEM REGISTER,PMON 可能延迟数分钟才推送新负载 -
lsnrctl status LISTENER_SCAN1输出中,对应服务条目没有load=xx字段(例如缺少service_handler="DEDICATED", load=12)
验证命令:srvctl status service -d <db> -s <svc></svc></db> + 查 v$services 中 LOAD_BALANCE 列是否为 YES
连接池预热导致初始连接全扎堆一个实例
HikariCP、UCP 等连接池默认开启 minimumIdle 或执行 connectionInitSql,会在启动时批量建连。此时若 DNS 缓存未刷新或 TNS 解析结果固定(比如 SCAN 返回 IP 顺序不变),所有连接会落在同一实例。
这不是配置错了,而是时间窗口问题:
- 连接池初始化阶段的连接是“静态快照”,不参与后续负载变化
-
loadBalance=true只影响新建连接时的地址随机选择,不重路由已有连接 - RAC 的负载均衡是连接级的,不是语句级的;连接复用后,所有 SQL 都走原实例
临时缓解:启动前清空本地 DNS 缓存(sudo systemd-resolve --flush-caches 或 Windows 上 ipconfig /flushdns);长期建议关闭 minimumIdle 或延迟初始化
Service-level Load Balancing Goal 对普通 JDBC 完全无效
srvctl modify service -B SERVICE_TIME 这类命令看起来很专业,但对 sqlplus、tnsping、普通 JDBC 连接完全无效——它们不订阅 FAN 事件,压根不看这个配置。
只有以下情况才真正起作用:
- 启用了 FAN 的客户端:UCP 连接池、WebLogic 数据源
- 显式设置了
oracle.jdbc.fanEnabled=true的 OJDBC - 服务创建时带
-B参数,且修改后重启了服务(查v$services确认GOAL列非 NULL)
别在普通应用里配 GOAL=SERVICE_TIME 然后等它自动分请求——它不会动,连日志都不会打
最常被忽略的一点:负载是否均衡,必须在应用启动后立刻查 v$session 的 inst_id 分布,而不是等运行几小时后再看。连接池扎堆一旦形成,后续流量就固化在那几个连接上,和 LB 配置再无关系。











