oracle 19c rac 本身不支持只读架构,所谓“只读流量路由”是通过创建专用服务(如ro_service)并配合clb_goal、goal及客户端failover_mode.type=select等配置实现连接分流,而非数据库设为只读;alter database open read only在rac中非法,因所有实例必须同步处于read write模式。

Oracle 19c RAC 本身不是只读架构,而是多实例并发读写同一数据库;所谓“Read-Only架构分担只读流量”,实际是指在 RAC 环境中通过客户端连接策略、服务配置与负载均衡机制,将只读请求定向到特定实例或节点,避免干扰 OLTP 主流负载——这不是靠数据库设为只读实现的,而是靠服务层控制。
如何用 SERVICE_NAME 实现只读流量路由
RAC 中每个实例可注册多个服务(SERVICE_NAME),其中可显式指定 CLB_GOAL、GOAL 和 ENABLED 属性来影响连接分发行为。只读流量调度的核心是创建一个专用只读服务,并绑定到目标实例上。
- 在主库(或任一节点)执行:
srvctl add service -d <db_unique_name> -s ro_service -r "<inst1>,<inst2>" -P BASIC -e SELECT -m BASIC -z 180 -w 0</inst2></inst1></db_unique_name>(-e SELECT表示启用只读故障转移,-w 0表示不启用连接时权重轮询) - 启动该服务:
srvctl start service -d <db_unique_name> -s ro_service</db_unique_name> - 确认服务已注册到监听器:
lsnrctl status | grep ro_service,并检查V$ACTIVE_SERVICES中状态是否为ENABLED - 客户端连接串中使用该服务名,例如:
(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=rac-scan)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ro_service)))
注意:-r 参数指定的是“首选实例”,但若未配合 CLB_GOAL = LONG 和 GOAL = SERVICE_TIME,RAC 默认仍按短连接轮询分发,无法真正隔离只读负载。
为什么不能直接 ALTER DATABASE OPEN READ ONLY
RAC 架构下所有实例必须同时处于 MOUNT 或 OPEN 状态,且必须全部为读写模式(READ WRITE)。执行 ALTER DATABASE OPEN READ ONLY 在任意节点都会报错 ORA-01109: database not open 或 ORA-1092: opiodr aborting process —— 因为 RAC 的控制文件和数据字典锁机制不允许混用读写/只读模式。
- 试图对单个实例设为只读:不被 Oracle 支持,
ALTER SYSTEM SET STANDBY_FILE_MANAGEMENT=MANUAL等参数在 RAC 主库无效 - 误以为开启
ADG_REDIRECT_DML=TRUE可用于 RAC 主库:该参数仅对 ADG 备库生效,对 RAC 主库无意义,且启用后反而可能引发 DML 重定向失败的隐式错误 - 真实只读需求应走 ADG 备库 + DML 重定向,而非在 RAC 主库上“模拟”只读
客户端驱动与应用层必须配合的服务属性
即使服务端配置了 ro_service,若 JDBC、ODBC 或 UCP 连接池未启用对应特性,流量仍会落到任意实例。关键配置项必须显式声明:
- JDBC URL 示例:
jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=rac-scan)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=ro_service)(FAILOVER_MODE=(TYPE=SELECT)(METHOD=BASIC)(RETRIES=180)(DELAY=5)))) -
FAILOVER_MODE.TYPE=SELECT是必须项,否则只读故障转移不会触发 - 应用代码中需设置
setReadOnly(true),部分驱动(如 ojdbc8)会据此选择匹配的服务,但并非所有版本都可靠识别 - Oracle UCP 连接池需配置
connectionFactoryClassName=oracle.jdbc.pool.OracleDataSource并启用enableImplicitCaching=true,否则连接重用可能绕过服务路由逻辑
容易被忽略的性能陷阱:CACHE FUSION 与只读实例绑定冲突
当把只读流量固定到某实例(如 inst1),而业务仍存在跨实例查询(如全局临时表、DBLINK 调用、物化视图刷新),Cache Fusion 通信量会陡增,私网带宽可能成为瓶颈,表现为 GCS CR BLOCK RECEIVE 等等待事件飙升。
- 验证方式:
SELECT event, time_waited_micro/1000000 sec FROM gv$session_event WHERE event LIKE 'gcs%' AND time_waited_micro > 0 ORDER BY 2 DESC - 缓解手段:避免在只读服务中执行含 DBLINK 的查询;物化视图刷新任务应安排在非高峰时段,且禁用并行(
PARALLEL 1) - 更稳妥的做法是:将只读流量导向 ADG 备库,而非 RAC 主库中的某个实例——后者本质仍是共享写入路径,只是连接入口做了分流
真正能卸载主库只读压力的,不是 RAC 内部服务路由,而是把只读请求彻底迁移到物理备库;RAC 上的服务级“只读”只是轻量级分流手段,适用场景有限,且依赖全链路(网络、驱动、SQL 写法)配合,稍有疏漏就失效。











