深入理解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 相關的等待在我們工作中很常見,通過上面的測試可以看,同一個塊在修改和查詢時,如果運用不當的話會產生很大的異常等待,對數據庫性能造成很嚴重的影響

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