深入理解gc相关的等待事件

二、分析过程

关于gc的简单描述,就是当实例1 发起请求时发现需要请求的块已经在另一个实例,这个时候就需要通过GCS(LMS)通过私网把相应的块传递到实例1,这个过程就是集群的cache fusion。请求的块又分为当前块和CR。

其中最常见的等待事件包括 gc buffer busy acquire、gc cr block busy。 其中gc buffer busy acquire是当session#1尝试请求访问远程实例(remote instance) buffer,但是在session#1之前已经有相同实例上另外一个session#2请求访问了相同的buffer,并且没有完成,那么session#1等待gc buffer busy acquire。gc cr block busy是指实例1和实例2的buffer cache都含有某个block,某个时刻实例1修改了这个block并且没有提交;这个时刻实例2上的会话1读取这个block需要通过undo record 来构造CR块。且构造的过程中必须将改变记入到实例1的redo,这个时候发生的等待就是gc cr block busy等待。

 

这里先使用两个节点进行模拟下

1、实例1上面开启一个session 对表QXY发起300W次查询

2、实例1上面的另开启一个session对表QXY同样发起300W次查询

3、实例2上面开启一个session对表QXY发起update操作

4、统计实例1上面的会话的等待事件。

 

-----创建表的脚本如下

create table qxy (name varchar2(20), id number, birth date) tablespace USERS;

 

-----插入数据量

insert into qxy select dbms_random.string('l',20), level lv, sysdate from dual connect by level < 100;

 

------循环语句

declare

ct number;

begin

for i in 1..3000000 loop

select count(*) into ct from qxy;

end loop;

end;

/

------创建一个新表记录会话开始前的等待事件 start.sql

define v_inst1=&1

define v_inst2=&3

define v_sid1=&2

define v_sid2=&4

drop table begin_table;

create table begin_table as select inst_id,sid,event,total_waits

from gv$session_event

where (inst_id=&v_inst1 and sid in (&v_sid1))

or (inst_id=&v_inst2 and sid in (&v_sid2))

order by inst_id,sid,event;

 

------通过前后相减统计查询之间产生的等待事件 end.sql

define v_inst1=&1

define v_inst2=&3

define v_sid1=&2

define v_sid2=&4

drop table end_table;

create table end_table as select inst_id,sid,event,total_waits from gv$session_event

where (inst_id=&v_inst1 and sid in (&v_sid1)) or (inst_id=&v_inst2

and sid in (&v_sid2)) order by inst_id,sid,event;

col event format a30

set linesize 120 pagesize 60

select ed.sid,ed.event,ed.total_waits - nvl(st.total_waits,0) diff_waits

from begin_table st,end_table ed

where st.inst_id(+)=ed.inst_id and st.sid(+)=ed.sid and

st.event(+)=ed.event order by event,sid;

 

----简单测试1

实例1 session 1

实例1 session 2

实例1 session 3 先查询会话统计信息

实例1 的session1 和 session 2 同时执行查询语句,实例2 的session执行update语句

实例1 session1

实例1 session 2

实例2 session 1

 

实例1 的session 3 统计查询结束之后的等待事件

通过上面的测试发现,如果在另外一个节点对块进行了更新之后快速提交的话,gc cr block busy等待事件不是很高,基本都是在各位数。注意上面的update语句,虽然是30s更新一次,但是更新之后是立马提交的,只是之后睡眠了30s。

 

-----简单测试2 (如果更新之后,等待30s提交是什么效果呢)

实例1 的session1 和 session 2 同样同时执行查询语句,实例2 的session执行update语句(但是这里update是停留30s之后在提交)

实例1 session 1

实例1 session 2

实例2 session 1

实例1 session3

通过第二个测试可以看到,如果跨实例访问块的时候,并且块被修改之后一直没有提交,这个时候另外一个节点在访问这个块的时候,gc的相关等待会成倍数级上涨。这主要是因为实例1和实例2的buffer cache都含有某个block,T1时刻实例2修改了这个block;T2时刻实例1上的会话1读取这个block修改前的CR copy,因为CR copy需要通过应用undo record才能构造出来,并且undo的访问时候是单块读,所以会大大影响速度,这个过程就产生了大量的gc 等待。

所以gc cr block busy的过程如下:

1)实例1的LMS向实例1的LMS发起block 读请求;

2)实例2的buffer cache里已经存在了这个block修改后的最新副本C1',实例2的 LMS在本地的buffer cache里根据C1'再复制出一个新的副本 C1'',此时C1'和C1''的内容是完全相同的;

3)实例2的LMS从undo segment里找到undo record用来applied到C1''上,把C1''回滚到修改前的状态,记为C1;

4)这时实例2的buffer cache 里包含了C1',C1,其中C1是C1'修改前的内容。

5)利用undo record将C1''回滚到C1这一过程是会产生redo的,实例2 的LMS进程通知Lgwr进程把redo写入online redolog,写成功后才能 进入下一步

6)实例2上的Lgwr通知实例2上的LMS redo写入完成,实例2上的LMS将C1传输给实例1的LMS

7)实例1的LMS将结果返回给实例1上的会话1的server process

------简单测试3 (构造CR块的时候需要产生REDO)

实例2 session1

执行一个update,但是不提交

实例2 session 2

统计redo size、 CR块

 

实例1 session 1

查询qxy 表,查询实例2修改的这行记录,这样就可以构造CR块。

实例2 session 2

再次统计redo size、 CR块

可以看到CR blocks created、data blocks consistent reads - undo records applied、redo entries、redo size的值都发生了变化。

 

------测试 4(本地节点select远程节点cache里未提交的数据块开销到底有多大)

1、远程节点修改后提交,本地节点两个session并发select同一张表

实例2 session 1

实例1 session 3 统计查询前的等待事件

实例1 session 1

实例1 session 2

实例1 session 3 统计查询之后的等待事件

 

2、远程节点修改后不提交,本地节点两个session并发select同一张表

实例2 session 1 不提交

实例1 session 3 统计查询前的等待事件

实例1 session 1

实例1 session 2

 

实例1 session 3 统计查询之间产生的等待事件

可以看到,从实例2的修改之后立刻提交到实例2修改之后没有提交,两次的查询从16s上升到了26分钟。差距十分巨大。

同时也说明了,虽然只在实例2修改了一个块,但是实例1的session 1 和session 2循环100W次,每次循环的时候都要构造CR,也就是说CR块不同共用。

 

实例2的 TOP 情况

 

可以看到,实例2 CPU的使用情况, LMS使用了23%, lgwr使用了21%。LGWR也正好从反面验证了构造CR块的时候需要写redo。

 

总结:

gc 相关的等待在我们工作中很常见,通过上面的测试可以看,同一个块在修改和查询时,如果运用不当的话会产生很大的异常等待,对数据库性能造成很严重的影响

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章