导读:本期聚焦于印尼程序员创作的《Oracle RAC集群中如何配置Service实现AQ队列与DML语句的正确路由?》,敬请观看详情。在Oracle RAC集群中运行高级队列AQ(Advanced Queues)时,如果Service没有绑定到特定实例,入队和出队操作可能被负载均衡分散到不同节点,引发队列争用、全局缓存等待甚至ORA错误。本文从AQ与DML在多实例环境下的常见异常入手,分析Service的负载均衡属性与故障切换参数对事务路由的影响,给出通过DBMS_SERVICE创建专属Service并设置clb_goal与failover属性的完整步骤,同时结合srvctl命令验证配置效果,帮助DBA让队列操作与DML语句稳定落在同一实例上,提升集群整体稳定性。

Oracle RAC集群通过多个实例共享同一套存储,为业务提供了高可用与横向扩展能力。但在实际运行中,很多故障并非出在集群本身,而是出在连接路由上:同一个业务模块的会话被负载均衡算法分散到不同实例,导致AQ队列表的块在实例之间频繁传递,DML语句遭遇gc buffer busy等待,队列消费者甚至读取不到自己刚入队的消息。这类问题的根源往往是Service配置不当。本文围绕RAC环境下Service、AQ队列与DML三者之间的关系展开分析,并给出可直接落地的配置方案。

Oracle RAC集群中如何配置Service实现AQ队列与DML语句的正确路由?

一、为什么AQ队列在RAC中对Service配置格外敏感

高级队列(Advanced Queues,简称AQ)的队列表本质上是一组普通的堆表加上后台的队列机制。消息入队(ENQ)和出队(DEQ)都会对这些表的特定数据块加锁。在单实例数据库中,这些锁与缓冲区都在同一个SGA内,开销可控;而在RAC环境中,如果入队会话连接在节点一、出队会话连接在节点二,队列表的热块就必须在两个实例的缓冲区之间通过内部互联来回传递。

这种跨实例传递会带来两类典型问题。第一是性能问题:全局缓存等待事件如gc buffer busy acquiregc buffer busy release会显著增加,队列吞吐量不升反降。第二是语义问题:AQ的出队默认基于提交后的可见性,如果生产者和消费者在不同实例上并发操作同一个队列,索引块争用会加剧,甚至出现消息延迟可见的现象,业务层表现为“消息丢了”,实际上只是还没提交可见。

因此,Oracle官方的建议是把AQ的生产者和消费者尽量固定在同一个实例上运行,实现方式就是创建一个专用的Service,并将其绑定到首选实例。这样所有通过该Service连接的会话都会落在同一个节点,队列表的热块不再跨节点流动,DML对队列表的更新也自然集中。

二、Service的负载均衡与故障切换属性对DML的影响

Service在RAC中决定了“连接去哪个实例”。与DML关系最密切的属性有两个:clb_goal(连接负载均衡目标)和failover(故障切换模式,即TAF属性)。

clb_goal有两个取值:DBMS_SERVICE.CLB_GOAL_THROUGHPUT表示按吞吐量均衡,适合长连接;CLB_GOAL_SHORT表示按连接数均衡,适合短连接频繁建立的OLTP系统。对于AQ这类需要会话亲和性的场景,光设置clb_goal还不够,因为负载均衡仍然可能把会话分到不同节点。真正起作用的是在OCR中为Service指定-preferred(首选实例)和-available(备用实例),配合srvctl命令让Service默认只在首选实例上运行。

TAF属性则决定了实例故障时会话的行为。对于普通DML,BASIC模式的FAILOVER会重新建立连接但不会自动重放未提交事务,应用层必须处理事务级重试;而PRECONNECT会在备用实例上预先建立连接,代价是占用双份资源。对于AQ消费程序,一般建议使用BASICSESSION级别的切换,让应用捕获错误后重新出队,因为队列消息本身是持久化的,实例重启后消息不会丢失。

-- 查看当前Service的配置情况
SELECT name, failover_method, failover_type, failover_retries,
       clb_goal, goal
FROM   dba_services
WHERE  name LIKE '%aq%';

-- 查看Service在集群各实例上的运行状态
SELECT inst_id, name FROM gv$active_services ORDER BY name, inst_id;

如果查询结果显示AQ业务使用的Service在多个实例上都处于运行状态,而业务连接串又没有指定INSTANCE_NAME,基本可以断定队列操作正在跨实例执行,这就是问题所在。

三、创建专用Service并绑定实例的完整步骤

下面以两节点RAC(实例orcl1、orcl2)为例,创建一个名为aq_svc的专用Service,首选实例为orcl1,可用实例为orcl2。整个过程分三步:用srvctl在集群层注册Service、启动Service、配置客户端连接串。

第一步,用grid用户执行srvctl命令完成注册并启动:

# 注册服务:首选实例orcl1,可用实例orcl2
srvctl add service -db orcl -service aq_svc \
  -preferred orcl1 -available orcl2

# 启动服务
srvctl start service -db orcl -service aq_svc

# 检查服务状态,确认只运行在orcl1上
srvctl status service -db orcl -service aq_svc -v

第二步,如果需要精细调整负载均衡与切换属性,可以登录数据库用DBMS_SERVICE修改:

BEGIN
  DBMS_SERVICE.MODIFY_SERVICE(
    service_name => 'aq_svc',
    clb_goal     => DBMS_SERVICE.CLB_GOAL_LONG,   -- 长连接,减少连接抖动
    failover_method => DBMS_SERVICE.FAILOVER_METHOD_BASIC,
    failover_type   => DBMS_SERVICE.FAILOVER_TYPE_SESSION,
    failover_retries => 10,
    failover_delay   => 5
  );
END;
/

第三步,客户端TNSNAMES中使用该Service名连接。注意这里的Service名即透明故障切换的入口,连接串不需要再写SID:

AQ_CONN =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = scan-ip)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = aq_svc)
    )
  )

配置完成后,所有AQ生产者与消费者统一使用AQ_CONN连接。正常情况下它们都会被路由到orcl1;当orcl1故障时,Service自动切换到orcl2,队列消息因为存储在共享存储上,消费者重新连接后可以继续出队,实现业务层无感切换。

四、配置后的验证与常见误区排查

验证工作要从两个层面做。会话层面,让业务连接后查询gv$instance确认所在实例,多开几个连接看是否都落在orcl1:

-- 在业务会话中执行,确认当前实例
SELECT instance_name, host_name FROM v$instance;

-- 在DBA侧统计各Service的会话分布
SELECT inst_id, service_name, COUNT(*)
FROM   gv$session
WHERE  service_name = 'aq_svc'
GROUP  BY inst_id, service_name;

性能层面,对比配置前后的等待事件。可以在AWR或gv$session_wait中观察gc buffer busy类等待是否明显下降,队列队表相关的enq: TX争用是否减少。如果吞吐量有量化数据,配置前后各压测一轮是最有说服力的验证方式。

常见的误区有三个。其一,只在TNS连接串里写了SERVICE_NAME但没在集群中用srvctl注册服务属性,结果SCAN监听按默认负载均衡把会话随机分配到两个节点,等于没配。其二,使用了旧的service_names参数方式(在init参数里直接设置),这种方式不会写入OCR,集群重启后Service不会自动在指定实例上拉起,RAC环境下应一律改用srvctl。其三,把AQ的Service配置成了双活(两个实例都是preferred),看似高可用,实则把队列热块争用又引回来了,除非使用Oracle 12c以后的Application Continuity配合队列分片方案,否则不建议这样配置。

总结来说,RAC环境下AQ与DML的稳定性高度依赖Service的实例绑定策略:专用Service绑定首选实例解决会话亲和性,TAF属性解决故障切换,srvctl注册保证配置随集群生命周期管理。把这三点做扎实,队列跨节点争用和DML全局缓存等待问题基本可以杜绝。

Oracle RACService配置AQ队列修改时间:2026-09-02 11:20:51

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编写,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260902/48895.html,基于非商业使用的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。