rac 遭遇GC BUFFER BUSY 处理思路

一朋友求助说他的ORACLE RAC服务器负载不是很稳定,时高时低,且没有任何规律。摘取负载高峰时间的一段日志来分析,最大的等待如下:

^LTop SQL Statements       DB/Inst: BOSSCENT/bosscent1  (May 19 13:17 to 13:32)
 
       SQL ID    Planhash % Activity Event                             % Event
------------- ----------- ---------- ------------------------------ ----------
f9rf7a8cg40nt         N/A       9.14 gc buffer busy                       2.53
insert into test(id,user_id,point_num,time,point_gettype,sex) values(
:1,:2,:3,sysdate,:4,:5)
 
                      N/A       9.14 gc current block busy                2.22
insert into test(id,user_id,point_num,time,point_gettype,sex) values(
:1,:2,:3,sysdate,:4,:5)
 
                      N/A       9.14 gc current block 2-way               1.42
insert into test(id,user_id,point_num,time,point_gettype,sex) values(
:1,:2,:3,sysdate,:4,:5)
bs6z6hs8sum53  1007834728       8.09 gc buffer busy                       2.16
update test set id=:1 where id=:2

明显看到出现大量gc buffer busy等待,与单实例不同,在RAC环境中,由于多节点的原因,会因为节点间的资源争用产生GC类的等待,而这其中,GC Buffer Busy Waits又是最为常见的,我们看下ORACLE官方对这个等待事件的解释:

gc buffer busy:
This wait event,also known as global cache buffer busy prior to Oracle 10g,specifies the time the remote instance locally spends accessing the requested data block. This wait event is very similar to the buffer busy waits wait event in a single-instance database 。

那么如何解决gc buffer busy带来的性能问题?一般有两种方法:


一、分割应用
就是指把出现gc buffer busy等待的SQL,单独配置一个数据源,在执行的时候指定到集群中的某一个实例。在执行产生gc buffer busy的SQL的时候,使用这个数据源。

这样的缺点是,如果指向一个单实例,这些操作负载太高的话,一个实例可能会抗不住。

二、修改表底层结构

在问题表上加入一个字段inst_id,也就是实例编号,这个字段作为主分区字段,按照这个分区做范围分区。并且每次插入的时候给这个字段赋一个常量,也就是实例编号。

这样的缺点是,需要修改表结构,风险很大,而且如果以后扩展节点的话,还需要重新改表结构。

两种方法各有长短,需要根据实际情况选择,不过我个人还是倾向于第一种方法。

本文转自:http://www.bigheaddba.net/article/y2010/573_rac%e9%81%87%e5%88%b0gc-buffer-busy%e7%9a%84%e8%a7%a3%e5%86%b3%e6%96%b9%e6%b3%95.html


inst_id
分区避免 rac gc buffer busy




通过ASH报告,我看到刚才系统HANG住的时候,主要的等待事件是buffer busy wait


Avg Active


Event Event Class % Activity Sessions


----------------------------------- --------------- ---------- ----------


buffer busy waits Concurrency 72.55 9.31


enq: HW - contention Configuration 14.21 1.82


gc buffer busy Cluster 7.67 0.98


CPU + Wait for CPU CPU 2.13 0.27


-------------------------------------------------------------


看样子是由于热块冲突导致系统HANG住的,而且高水位推进相关的锁等待也很严重,应该系统中有大量的数据插入。从这个情况看想简单的通过调整参数来解决问题是不大可能,必须从应用的特点去分析,才有可能找到解决方案。于是我问郝经理:"你的应用是什么样的,是不是有大量的插入操作?"


郝经理告诉我这个系统是企业应用集成系统,是从其他系统中接收数据,经过处理后存储在本系统中,供经营分析系统使用。目前的压力测试中的主要操作是对34张大表进行大批量的数据插入,其中还有张表里带LOB字段。


我和郝经理研究了一下,对这些数据的访问,除了大规模的数据插入外,一般来说是按主键访问,或者按某些分类条件的小范围查询,每次范围查询顶多占整个表数据量的几万分之一,并且范围查询的比例相对较小,仅占整个系统查询数量的10%不到。这种情况是典型的可以使用HASH分区的,通过HASH分区既可以解决BUFFER BUSY WAIT的问题,又可以解决enq: HW -contention的问题。于是我建议郝经理把这几张表按照主键MSG_IDhash分区,先尝试一下16个分区,看看能不能解决问题。


按照我的建议做了HASH分区后,压力测试重新开始了,这回看样子效果很不错,从em控制台上看,buffer busy wait等待已经少了很多,而且enq: HW - contention等待也消失了。



Avg Active


Event Event Class % Activity Sessions


----------------------------------- --------------- ---------- ----------


gc buffer busy Cluster 90.69 14.83


gc current request Cluster 6.05 0.99


CPU + Wait for CPU CPU 1.05 0.17


目前的主要等待是gc buffer busy,由于目前在连个节点上各有40个并发插入的会话在进行数据插入,因此全局BUFFER等待的问题肯定是存在的,目前压力测试已经进行了1个多小时了,从em观察到的情况来说系统一直还很平稳。现在的时间已经是中午的12点半了,郝经理建议我们先去吃饭,等吃完饭回来再看看结果。


在下面的食堂里简单吃了点东西,我们就回到了办公室,现在是下午的1320分了,压力测试也已经开始了差不多2个小时了,系统的状态依然和我们吃饭前一样,还没有出现hang住的现象。不过从平均事务响应时间来看,现在比一个小时前要慢了40%,这是一个十分不好的现象,如果这种趋势延续下去的话,很可能会再次出现系统HANG住的现象。


看着郝经理他们兴奋的样子,我给他们泼了盆冷水,可能问题还是没彻底解决,从目前的趋势上看,有可能系统还会HANG住。我正在和他解释为什么我会有这种预感,突然从EM上看到系统活跃情况突然下降了,系统可能又HANG住了。


我连忙做了一个3级的hanganalyze,从trace上看:


Open chains found:


Chain 1 : :


<0/786/9/0xff010e58/9474/gc buffer busy>


-- <0/785/26/0xff011e38/9512/gc current request>


Chain 2 : :


<0/791/32/0xff00e6a8/9404/gc buffer busy>


-- <0/785/26/0xff011e38/9512/gc current request>


Chain 3 : :


<0/792/12/0xff00ee98/9408/gc buffer busy>


-- <0/785/26/0xff011e38/9512/gc current request>


Chain 4 : :


<0/794/19/0xff00d6c8/9334/gc buffer busy>


-- <0/785/26/0xff011e38/9512/gc current request>



大量的gc buffer busy导致了大量的gc current request等待。很多会话由于gc buffer busyHANG住一段时间,实际上系统并没有真正的HANG住,而是变得十分慢而已。不过如果这种情况的范围如果扩大的话,就会导致应用软件出现问题,产生丢失数据的现象。过了几分钟,郝经理那边也确认了这次系统HANG住,1号节点的应用被挂起了35秒钟,丢失了70多条数据,实验再次失败了。


看样子GC BUFFER BUSY最终还是导致了严重的问题。由于他们的应用没有针对RAC进行优化,同一个应用分别在2个节点上跑,所以导致了严重的节点间的热块冲突。也许把这个应用集中在一个节点上就能够解决问题。我把我的想法和郝经理说了,郝经理觉得可以试试,不过他们的系统发展起来特别快,所以从最初做设计的时候就考虑要使用RAC,而且今后不仅要支持双节点,还可能扩展为3节点甚至4节点。目前的业务有可能单节点能够支持,不过今后一个节点可能无法支撑所有的负载。


我考虑了一下,刚才应用放在两个节点上跑的时候,两个服务器的CPU使用率都已经超过60%了,如果跑在一个节点上,确实负载挺大的,一个节点还真有可能支持不了,更不要说今后系统扩展性的问题了。看样子必须从底层结构上进行调整了。我问郝经理,如果在表里面加一个字段,并且每次插入的时候给这个字段赋一个常量,这样修改程序他们的工作量大不大。郝经理想了想说应该问题不大,修改一下也就是10分钟的事情。


我说如果这样就好办,我们可以对表结构做一个调整,来彻底解决这个问题。我们重新对表进行分区,使之成为一个复合分区表,在这张表上加入一个字段inst_id,也就是实例编号,这个字段作为主分区字段,按照这个分区做范围分区后,再设置msg_idhash分区。调整后的表结构如下:


CREATE TABLE QSTORE


(


MSG_ID VARCHAR2(64 BYTE) NOT NULL,


DOCE_ID VARCHAR2(100 BYTE) NOT NULL,


DOC_KEY VARCHAR2(100 BYTE) NOT NULL,


BUS_NAME VARCHAR2(100 BYTE),


MODULE_NAME VARCHAR2(100 BYTE),


CATEGORY VARCHAR2(64 BYTE),


SUB_CATEGORY VARCHAR2(64 BYTE),


DOC_SIZE NUMBER(11) DEFAULT 0,


CREATE_TIME DATE,


MODIFY_TIME DATE,


EXPIRED_TIME DATE,


DOC_FLAG NUMBER(2),


Inst_id number


) initrans 20 pctfree 20 tablespace TS_DATA_EAI


PARTITION BY RANGE(inst_id)


SUBPARTITION BY HASH(msg_id) SUBPARTITIONS 8


(PARTITION p1 VALUES LESS THAN (2),


PARTITION p2 VALUES LESS THAN (3));;


Inst_id的值就是插入进程连接到的实例的ID,这样调整后,在1号节点上插入的数据将全部被插入到inst_id=1的分区,插入操作就不会产生大量的global cache request了。这种做法也是在RAC上解决GC BUFFER BUSY的常用方法之一。


郝经理很快就明白了我的意思,上楼去安排开发人员修改应用了。我也趁机休息休息,准备下面的测试了。这时候老储的电话又打了进来,那个问题终于解决了,通过hcheck对数据字典进行检查,发现有一张表的数据字典出现了不一致,在tab$中还有记录,但是在obj$里的记录缺失了,查找这个表空间中有什么对象找不到,但是删除tablespace的时候又删除不了。把tab$中的数据手工删除后,表空间就成功的删除了。


刚和老储通完电话,郝经理的电话就打了进来,他说应用已经修改好了,他已经开始了测试,大概10分钟后压力就会加载到数据库上,让我监控一下有没有什么问题。从测试刚开市的情况看,gc buffer busy基本上消失了,系统也比较平稳,从EM的监控情况来看,系统一切都很平稳,系统已经运行了一个多小时,从awr报告来看,现在的平均事务响应时间,和系统刚刚启动时差别不大,并且gc buffer busy 等待事件也已经不在top 5等待时间里了。看样子通过这么优化,系统趋于稳定了。郝经理建议我们先回去,压力测试做一晚上,明天上午10点再来看结果。如果那时候发现系统一切正常,那么说明问题已经解决了。


select t.INSTANCE_NUMBER into p_inst_id from v$instance t


通过procedure进行插入,在执行的开始,取得instance_id


本文转自:http://yu85910.blog.china.com/200903/4504368.html


gc buffer busy: 产生这个等待事件是由于实例间产生热块争用造成的,要解决这个问题有两种方法:


第一、分割应用:把应用集中在一个节点上运行


第二、对表添加一个字段,这个字段存放实例的id号,如果在节点1执行的那么存放节点1的实例id号, 如果在节点2执行的那么存放节点2的实例id,在执行之前首现获取实例的id号。


[@more@]

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/25462274/viewspace-2138366/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/25462274/viewspace-2138366/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值