oracle rac本身不提供原生读写分离能力,services仅控制连接路由,不干预已建立连接中的sql类型分发;必须依赖应用层识别sql类型并显式连接对应service,或借助shardingsphere-jdbc、adg等外部方案实现。

Oracle RAC 本身不提供原生读写分离能力,Services 只是连接路由的抽象载体,不能自动把 SELECT 发到某节点、INSERT/UPDATE 发到另一节点——必须配合应用层逻辑或中间件才能实现读写分离。
为什么直接用 RAC Services 做读写分离会失败
RAC 的 SERVICE(如通过 srvctl add service 创建)本质是服务名 + 节点亲和策略(preferred/available)+ 故障转移配置,它只控制“连接建立时去哪个实例”,不干预已建立连接中的 SQL 类型分发。
常见错误现象包括:
- 应用连上
read_service后仍执行了UPDATE,事务在只读意图的节点上成功提交 - 设置了
LOAD_BALANCE=ON,但所有读写请求仍随机打到同一节点,没按语义分流 - 误以为
FAILOVER_TYPE=select能让读请求自动切到备节点——它只对已断开的查询会话生效,不改变路由规则
真正可行的读写分离路径:Services + 应用识别 SQL 类型
要靠 Services 实现读写分离,必须让应用自己判断 SQL 类型,并显式连接对应 Service。这是最轻量、最可控的方式,无需引入代理层。
清晰、专业的暖通空调服务客户教育手册,包含图片、常见问题及可操作的下一步,帮助客户理解并提升参与度。
关键实操点:
- 创建两个 Service:
app_rw(preferred指向所有节点,用于写)和app_ro(preferred指向部分节点,如仅rac1,用于读) - 应用代码中区分数据源:
DataSource配置两套 URL,分别指向app_rw和app_ro的 TNS 名 - DAO 层或注解(如 Spring 的
@ReadOnly)决定走哪个数据源;避免在同一个事务里混用 - 禁止在
app_ro连接上执行 DML——RAC 不拦截,但业务语义上应报错或拒绝
Service 配置中容易被忽略的参数细节
Service 的行为高度依赖几个关键参数,设错会导致路由失效或负载不均:
-
clb_goal = SHORT:启用客户端负载均衡,让新连接按节点负载动态分配;若设为LONG(默认),则连接基本固定在首次选择的节点 -
rlb_goal = SERVICE_TIME:开启运行时负载均衡,监听器会根据各实例当前响应时间重定向新连接;需配合DBMS_SERVICE.MODIFY_SERVICE动态调整 -
failover_type = SELECT仅对已执行的查询有效,且要求客户端启用 TAF(Transparent Application Failover),否则断连即报错 - 不要给
app_ro设置available节点——否则故障时读请求可能漂移到写节点,破坏读写隔离边界
比 Services 更现实的替代方案:ShardingSphere-JDBC 或 Oracle ADG
如果应用无法改造 SQL 路由逻辑,硬要用 RAC 做读写分离,实际落地更常采用以下组合:
- 用
ShardingSphere-JDBC嵌入应用,配置READWRITE_SPLITTING规则,将SELECT自动路由到指定 RAC Service,DML 固定走主 Service;它能识别 SQL 类型,且不依赖数据库自身功能 - 放弃 RAC 内部读写分离,改用 RAC(主) + ADG(物理备库)架构:
ADG备库开启READ ONLY WITH APPLY,通过独立 Service 暴露只读端点,此时读写分离由物理复制层保障,RAC 只负责主库高可用 - 注意:ADG 备库的延迟不可控,
SELECT可能读到旧数据,必须在业务可接受范围内评估APPLY LAG
真正难的不是配置 Service,而是界定“读”与“写”的边界——比如带子查询的 UPDATE、函数索引触发的隐式读、自治事务里的 DML。这些场景下,任何基于 SQL 文本的路由都可能出错,必须结合业务语义做兜底设计。










