1. 程式人生 > >ORACLE RAC工作原理

ORACLE RAC工作原理

資料庫系統和其他資料管理很重要的一個區別就是 允許併發訪問
 最大挑戰是 資料不一致
 如何保證併發和資料一致是資料庫系統的核心  併發訪問和資料一致性:
  資料不一致的情況
   1 髒讀
   2 不可重複性
   3 幻影讀
   4 資料一致性
 事務和隔離級別
  四種資料一致性級別:隔離級別
   read uncommited:不希望“寫”阻塞“讀”。
   read committed:允許“寫”阻塞“讀”
   repeatable: 目的是避免“不可重複讀”和“丟失資料”
   seralizable: 保證使用者以獨佔方式訪問資料
 Oracle支援的隔離界別:
  read committed,seralizable,Read Only Oracle 單例項的併發控制機制
 Lock
  代表一種控制機制
  在這個機制中有一個成員 LOCK   LOCK框架包含三個元件:
   Resource Structure
   Lock Structure
   Enqueue (排隊機制)    Resource Structure:Onwer,Waiter,Converter
   Lock Structure:Onwer,Waiter,Converter三個成員就是指向由Lock Structure組成的連結串列的指標。
   鎖模式:
    NULL  主要用於資料字典物件
    Share 擁有者本身對資源進行只讀訪問,允許其他使用者併發只讀訪問
    Exclusive 擁有者對資源進行修改訪問,不允許其他使用者訪問
   Enqueue 演算法:
    先入先出
  資料記錄的行級鎖:
   涉及四個資料結構
    ITL:記錄哪些事務修改這個資料庫的內容
    記錄頭ITL索引:每條記錄的記錄頭部都有一個欄位,用於記錄ITL表項號,指向ITL表的指標
    TX鎖:代表一個事務。屬於LOCK機制
    TM鎖:也屬於LOCK機制
   行級鎖機制:
    修改表的內容時:
    1 首先獲得TM鎖,保護事務執行時,其他使用者不能修改表結構
    2 事務修改某個資料塊中記錄時,該資料塊頭部的ITL表中申請一個空閒表項,在其中記錄事務項號,實際就是記錄這個事務要使用的回滾段的地址(應該叫包含)
    3事務修改資料塊中的某條記錄時,會設定記錄頭部的ITL索引指向上一步申請到的表項。然後修改記錄。修改前先在回滾段將記錄之前的狀態做一個拷貝,然後修改表中資料。
    4 其他使用者併發修改這條記錄時,會根據記錄頭部ITL索引讀取ITL表項內容,確認是否事務提交。
    5若沒有提交,必須等待TX鎖釋放
   更多的鎖模式:
    簡單物件 和 複雜物件     六種鎖模式
      Highest level    X>SSX>SX=S>SS>NULL   Lowest level
 Latch:
   一種併發機制。主要用於保護資料結構。
   HASH BUCHET,chain
  
  LOCK和Latch對比:
   latch的請求,獲得,釋放 原子操作,幾個硬體指令完成,時間很短
   LOCK 不是原子操作,很多硬體指令,程序上下文切換 很消耗資源
   latch 程序上下文切換 代價昂貴。不斷嘗試請求。Spin機制。
   latch是搶佔機制
   LOCK是排隊機制
  進一步:
   影子程序
   Oracle 用Lock latch保證程序之間併發和資料一致。
   sql的執行過程:
    解析
    優化
    執行計劃
    返回結果
   Lock和Latch的使用:
    執行計劃對應shared pool中一個複雜的資料結構
    sql語句雜湊值
    找到桶,桶中遍歷
    硬解析 鎖住桶所在的鏈,鎖住shared pool中新申請的一個空大小合適空閒塊的(用來存放編譯後的執行計劃)空閒連結串列。----latch機制 鎖住這兩個鏈。
    編譯執行的過程中,表的資訊讀入資料字典,表不能被改動,表上有TM LOCK
    執行階段 buffer cache中定位資料塊,桶 中 連結串列上找到最終塊 ---latch 機制;同時 訪問資料塊中的記錄時,行級鎖機制
    
  資料庫被指特徵:併發和鎖  RAC下的併發控制:   
 資料庫的主要任務---事務處理 
 分散式鎖管理
 oracle以資料塊作為粒度單位
 
 RAC首先是一個數據庫,必須要解決併發問題。通過鎖,在每個程序訪問修改資料之前,必須對資料枷鎖。鎖機制,保護自己訪問的資料不被別的程序破壞,自己也不去破壞別的程序的資料
 其次 RAC是執行在多臺計算機上的資料庫。一個程序是否可以修改一條資料,取決於是否有其他程序(本地和RAC環境中其他機器中的程序)是否訪問該資料  如何在多臺計算機的環境下感知併發的存在?
  分散式鎖管理器。可以想象成一個“仲裁”,它記錄著哪個節點操作哪個資料,並負責協調解決節點間的競爭。
 DLM的作用舉例:
  1 一個2節點的RAC;
  2 節點1想要修改資料1
  3 節點1向DLM請求,DLM發現數據1還沒有被任何節點使用,DLM就授權給節點1;並且DLM登記節點1對資料1的使用
  4 節點2也想修改資料1
  5 節點2向DLM請求,DLM發現數據1被節點1使用,DLM就會請求節點1“先給節點2用吧”,節點1接到請求後釋放其對資料1的佔用,節點2能夠操作資料1
  6 DLM記錄這個過程
  需要強調的是DLM負責的是節點的協調,而節點內的協調不是DLM負責。繼續上面的例子
  1 現在節點2的程序1修改資料1;
  2 節點2的程序2也想修改資料1
  3 節點2仍然請求DLM,DLM發現節點2現在已經具有許可權,無須授權
  4 程序2對DLM的請求被通過,但是程序2是否能夠修改資料1,還需要進一步檢查
  5 通過傳統的鎖模式,比如“行級鎖”,程序2發現數據1正被程序2修改,所以程序2只能等待。  DLM是在哪個層次上對資源衝突進行協調?資料記錄級別?資料檔案級別?資料塊級別? 選擇資料塊也是從效能方面權衡的結果。
 RAC就比單例項多的就是分散式鎖管理器。DLM的作用就是協調例項之間對資源的競爭訪問。。例項內部的競爭RAC和單例項是沒有任何區別的。學習RAC就是學習DLM。  DLM中資源和鎖
 DLM協調叢集各個節點對資源使用的功能叫做同步。所有資源的訪問都需要同步。叢集間的同步功能是一把雙刃劍。保護資料一致性是它的有利的一面,反過來資料的同步會影響叢集的同步。如果叢集同步活動非常密集,那麼對叢集效能的影響是非常巨大的。
 關鍵的要素是如何在節點間分佈資源和協調任務,把節點間的同步活動降低到最低但有正好滿足需求。
 同步活動的數量取決於資源的數量和資源上活動的密集程度。
 資源分成兩類:
  PCM資源
  Non-PCM資源
  或者叫
  Cache Fusion資源  特別指的是資料塊資源:普通資料塊,索引資料塊,段頭塊(Segenment Header),Undo塊
  Non-Cache Fusion資源 非資料塊資源都:資料檔案,控制檔案,資料字典檢視,Library Cache,Row Cache等
 對應兩種資源 DLM也對應兩種鎖:
  Cache Fusion(PCM)  PCM Lock
  Non-Cache Fusion(Non-PCM)  Non-PCM Lock
 RAC資料塊中對應四大類鎖:
  Global Locks:PCM Lock,Non-PCM Lock  (用於叢集之間併發的控制)
  Local  Locks:Local Locks, Latch             (本地程序間的併發控制)
 
 Non-Cache Fusion 資源:
  典型的Non-Cache Fusion資源是 Shared Pool中的 Row Cache 和 Library Cache中的內容。
  研究一下Library Cache為例(相對較大):
   Library Cache中存放的是所有SQL語句、執行計劃、包等物件,以及這些物件所引用的物件。    當一個語句或包編譯時,這個語句引用的所有物件都會被加一個Library Cache Lock;執行時,所有被引用的物件都會加上一個Library Cache Pin,以保證在語句執行過程中,應用物件的結構不會改變。    編譯完成以後,加在引用物件上的Library Cache Lock會由原來的Share或Exclusive模式變成Null模式。Null也是一種鎖,相當於一個觸發器,當這些物件的定義被修改以後,引用這個物件的所有的物件都變成無效,必須進行重新編譯。    例如select * from a,編譯以後,這個執行計劃會在a物件上加一個NULL模式的Library Cache Lock,以後對a修改結構以後,這個“觸發器”就會導致“select * from a”這個語句執行計劃失效。再次執行這個語句的時候,需要重新編譯新的執行計劃。    RAC環境中,每個節點都可能有引用物件a的SQL語句,無論在任何節點上對a進行結構修改,都需要把所有節點上的引用a的SQL語句置為失效。    除了傳統的Library Cache Lock之外,每個節點的LOCK0程序會對本例項Library Cache中的物件加一個Shared-mode的IV(Invalidation)Instance Lock。    使用者想修改物件定義,必須獲得一個Exclusive模式的IV鎖,這會通知本地的LCK0釋放Shared-mode鎖,本地LCK0在釋放這個鎖之前,會通知其他的節點上的LCK0,其他節點的LCK0收到這個訊息後,就會將本地Library Cache中所有相關物件置為失效,這種機制是一種廣播機制,通過例項的LMD程序完成。
 
   Raw Cache中存放的是資料字典,目的是減少編譯過程中對磁碟的訪問。內容也需要在所有例項之間同步,同步機制同Library Cache,也是LCK0實現。    Non-Cache Fusion鎖實質就是:這邊改了以後,廣播通知所有節點,當然,額外的鎖加在了資源上,只有這些鎖才會觸發廣播。
 Non-Cache Fusion的特點:
  1、資源數量有限
   Raw Cache中存放的是物件定義、Library Cache中存放的是SQL程式碼、執行計劃等。表、檢視、儲存過程、包是有限的,SQL語句雖多,但有限。
  2、資源被修改的頻率很低
  因為這些特點,Oracle採用了廣播這種機制,每個節點的變化都通知給所有節點。  Cache Fusion資源:
  對於資料塊這種資源,Oracle採用的是Cache Fusion機制,這種機制使用的是PCM Lock。
  PCM Lock有三種模式:Shared、Exclusive、Null
  Oracle用另外一個術語來描述加在資料塊上的鎖型別-資料塊狀態(Buffer States)
PCM 鎖模式 資料塊狀態 說明
X  XCUR  如果資料塊的狀態是XCUR,這個狀態描述了兩方面的內容。首先在這個資料塊上的鎖是X模式的,而且這個資料塊的版本是最新版本,也就是CURRENT,因此    eXclusive+CURrent構成了上面的縮寫。
S  SCUR  這個資料塊的狀態是SCUR,也是描述了兩方面的內容,首先這個資料塊的鎖是S模式的鎖,而且這個資料塊的版本是最新版本,即Current版本,SCUR實際上是    Shared+CURrent的縮寫。
NULL  CR  例項沒有對資料塊加PCM鎖。
  1、開始兩個例項都讀取這個資料塊內容,因此兩個例項對這個資料塊的鎖是S鎖,資料塊的版本是CURRENT,所以資料塊狀態是SCUR。
  2、例項1要修改這個資料塊內容,例項1必須獲得這個資料塊的X模式的鎖:因為X模式的鎖和S模式的鎖不相容,因此例項2必須釋放其S模式的鎖。
  3、最終例項1擁有X模式的PCM Lock,而資料塊狀態是XCUR,而例項2的鎖模式是Null,資料塊狀態是CR。   
 GRD(Global Resource Dictionary)資料塊拷貝在叢集節點間的狀態分佈圖。
  GRD裡面記錄著每個資料塊在叢集間的分佈圖,位於每個例項的SGA中。
  每個例項都是部分GRD,所有例項的GRD彙總在一起才是一個完整的GRD。
  RAC會給每一個資源(資料塊)選擇一個節點作為它的Master Node,而其他節點作為Shadow Node。Master Node的GRD中記錄了該資源在所有節點上的使用資訊,而shadow node的GRD只需要記錄資源在該節點上的使用資訊。
  這些資訊就是PCM Lock資訊。
  GRD在各個節點上是不同的,但是資源數是相同的。
   :
 PCM LOCK:
 1 MODE 鎖的模式
  Exclusive:持有這種鎖的例項對資料塊進行讀、寫操作。而其他的例項不能再獲得X、S模式的鎖,不能進行任何操作,叢集中最多隻能有一個例項擁有這個模式的鎖。這個只是資料塊級別的寫許可權,獲得這個鎖以後,是否可以修改其中的記錄,還要看記錄上的行級鎖,這一點和單例項的機制一樣。
  Shared:擁有這個模式的例項可以對資料塊進行只讀操作,而其他的例項可以獲得S模式的鎖,進行讀操作。但是其他例項不能獲得X模式的鎖,可以同時有多個例項擁有這個模式的鎖。
  Null:這個模式代表對應的記憶體空間可以被重用。
 2 Role
  Oracle修改資料塊時,要先把資料塊讀到記憶體,在記憶體中修改,但是提交以後並不立即寫回到磁碟。而是採用延遲寫的技術,在被寫回磁碟以前,記憶體資料塊和磁碟資料塊內容不一致,這時記憶體中的這個資料塊是“髒資料塊”。“髒”是用來描述資料塊的記憶體版本和磁碟版本是否一致,和事務沒有關係。事務提交時,只會把日誌寫到聯機重做日誌檔案,但是資料塊不會立即寫回到磁碟,這是記憶體中的就是“髒資料塊”。
  每個資料塊可以被多個節點修改
  資料塊被修改以後,事務提交,但是資料塊沒有被寫回磁碟中,這個資料塊可以在記憶體中被另外一個事務再次修改(等同於寫回磁碟、讀取出來再次修改)。如果一個事務沒有提交,這個資料塊不能被別的事務修改(通過X鎖實現)
  Role這個屬性就是用來描述這種“髒資料塊”在叢集間的分佈狀況。
  Role的取值:Local、Global  Role結合Mode
  Local Role:
   S鎖:代表這個記憶體資料塊是和磁碟上的內容完全一致的
   X鎖:代表這個記憶體資料塊做過修改,修改沒有寫回磁碟,這是一個髒 資料塊,如果需要把這個資料塊寫回磁碟,不再需要聯絡GRD,本例項 就可以完成。
   如果擁有X+Local的例項要給其他例項傳送這個資料塊,如果傳送的是和磁碟一致的版本,也就是說接收方收到的也是和磁碟一致的版本,那麼本例項就仍然保持Local Role。如果傳送的是和磁碟不一致的版本,那麼角色就要轉變成Global,同時接收方的角色也是Global,代表同時有多個例項擁有“髒資料塊”版本   Global Role:
   Null、S、X
   Global Role意味著有多個例項擁有和磁碟不一致的版本,這時如果想要把這個資料塊寫回到磁碟,必須聯絡GRD,由擁有資料塊Current版本的例項完成寫動作。
   不會出現多個數據塊同時擁有X鎖的情況。
 Past Image:
  舉例說明什麼是Past Image :假設一個2節點的RAC叢集,某個資料塊在磁碟上的SCN=100
  1、例項1要修改這個資料塊,從磁碟讀入SGA進行修改,修改後記憶體中的SCN=110
  2、例項2也要修改這個資料塊,例項1就會通過Cache Fusion把這個資料塊傳送給例項2,傳送的版本是SCN=110,即Current Copy的資料塊。這時例項1還會保留這個SCN=110的資料塊在SGA中,但是不能在進行任何修改操作,這時例項1擁有的這個拷貝就是Past Image,其SCN=110.在例項1傳送這個資料塊以前,會先把log buffer內容寫回到redo log中。
  3、例項2修改這個資料塊,修改後SCN=120,磁碟上的版本仍然是100.
  4、假設例項1現在因為日誌切換,觸發了檢查點動作,因為例項1上這個資料塊是個髒資料塊(不是最新的髒),所以需要同步到磁碟
  5、例項1會查詢GRD,發現例項2擁有的是這個資料塊的Current版本,GRD會通知例項2把這個資料塊寫入磁碟。
  6、例項2完成寫以後,會通知其他例項(所有擁有PI版本的例項)釋放它們擁有的PI記憶體,例項1就會在Log Buffer中記錄一條(Block Write Record)記錄,然後釋放PI記憶體。
  7、假設例項2沒有完成寫操作就異常down機了(假設已經提交事務,但是資料塊沒有寫回到磁碟中),這時就會觸發例項1進行Crash Recovery(不同於單例項的Instance Recovery)。因為例項1擁有最近的PI,所以只需要利用例項1的PI及例項2的聯機重做日誌就可以完成恢復。
  PI代表著這個例項的SGA是否擁有和磁碟內容不一致的版本,以及版本順序。PI主要能夠加速Crash Recovery的恢復過程。
  例項恢復可以認為是資料塊進行恢復,資料塊根據自己的SCN+日誌中的記錄,恢復到最新的SCN,所有的資料塊都進行同樣的操作,就是例項恢復。
  最新的PI+日誌記錄,可以大大的縮短資料塊的恢復速度。  例項恢復與媒體恢復的區別
  例項恢復自動使用線上日誌檔案(current和active)。媒體恢復需手工進行,只有在線日誌檔案中有足夠的資訊,即使是在非歸檔模式下也可以進行媒體恢復。媒體恢復需要將所有執行緒日誌按照scn/seq的順序進行合併,因為資料檔案可能被多個例項修改。
  例項恢復中的雙路恢復:緩衝區塊超時或增量檢查點將寫資料塊到資料檔案而不更新檔案頭資訊。當DBWR完成資料塊的寫操作時將增加一條redo記錄以描述被寫入的資料塊,被稱作寫塊記錄BWR(Block Written Record)。在例項恢復中線上日誌檔案被讀取兩次。
  第一次讀日誌構建日誌中相關的資料塊列表。其中部分塊存在於BWR記錄中,表明這些塊已經寫入檔案。去掉這些塊之後的第一次掃描列表就是未寫出的數塊。
  第二次讀日誌將僅僅處理列表中的塊,以減少資料塊的讀寫,如果資料庫不能進行雙路恢復將使用單路進行恢復。_TWO_PASS=false可忽略雙路例項恢復。
  媒體恢復:在媒體恢復過程中,恢復後的資料塊等待寫入檔案。在log switch時發生恢復checkpoint,恢復檢查點更新控制檔案,以防止例項恢復重新啟動時重新應用日誌。恢復檢查點同時也更新資料檔案頭。媒體恢復可以是完全或不完全的,不完全恢復需要使用resetlogs開啟資料庫。在9i之前,如果媒體恢復失敗或stuck,資料庫可能處於不一致狀態,需要重新restore and recover incomplete,從9i開始資料塊在恢復被修改時寫入,在恢復失敗時資料庫處於一致狀態。
     
例項講解Cache Fusion:
 針對一個數據塊、這個資料塊的master node是例項2,PCM Lock使用Mode、Role、Pasting格式描述,這些內容都在GRD中。SL0代表Shared Mode、Local Role、0個Past Image。
 一、併發讀操作
  1、例項1想要讀取這個資料塊,計算該資料塊的Master node是例項2,於是向例項2發出請求,請求資料塊以及PCM鎖(SL)
  2、例項2查詢自己的GRD,發現數據塊沒有被任何例項使用,同意例項1的請求。
  3、例項1:從本地讀取資料塊到Buffer Cache中,SCN是1000,獲得資料塊的 PCM Lock(share-mode、local mode)。
  4、更新例項2的GRD
  5、例項3要讀取這個資料塊,向例項2發出請求
  6、例項2向例項1發出通知,讓例項1傳送資料
  7、例項1向例項3傳送資料塊,強調例項3必須以shared mode方式訪問資料(如果例項1釋放了該資料塊,也會通知例項3,例項3會自己從磁碟讀取資料塊)
  8、例項3通知例項2,更新GRD
  
 二、讀併發寫(繼續上一個場景)
  1、例項3要修改資料塊,向例項2請求Exclusive mode PCM鎖請求
  2、例項2:檢查GRD,發現例項1以Shared-mode持有資料塊,於是向例項1發出請求,請求其Mode轉換為Null Mode,意味著例項1可以釋放這塊資料所佔有的記憶體。
  3、例項1向例項3傳送資料塊,並釋放自己的PCM鎖
  4、例項3獲得Exclusive-mode PCM鎖,通知例項2,更新GRD
  5、例項2更新GRD,刪除了例項1持有這個資料塊的條目
  6、例項3修改資料塊,資料塊的SCN變成2000
  為了減少網路互動次數,Oracle對資訊的傳送做了捆綁處理,比如例項1收到例項2的請求後,並不給例項2返回響應,而是在例項3給例項2的響應中,隱含了例項1對例項2的響應。
   
 三、寫併發寫(繼續上一個場景)
  1、例項4想修改資料,向例項2發出Exclusive-mode PCM鎖請求。
  2、例項2檢視GRD,確定例項3持有的是“當前版本”(Current Version),於是向例項3轉發請求
  3、例項3傳送資料塊到例項4,把自己的鎖降低到null-mode
  4、例項4收到資料塊,獲得exclusive-mode鎖,通知例項2更新GRD
  5、例項4對資料塊進行了修改,SCN變成2100
   
  注意:例項3必須完成下面的工作才能傳送資料塊
  1、把所有的log寫入到redo log file中
  2、把buffer標識為null mode,PI=1,表示持有的這個資料塊的PI版本,必須等到Current Version寫到磁碟後才能清空
  3、傳送的資料塊是current state,也就是帶著修改內容傳送過去的Cache Fusion是跨事務邊界的,也就是不必等待例項3上的事務完成,就可以傳送這個PI資料塊。   場景4、寫入磁碟
   1、假設例項3因為log switch觸發了檢查點,要把所有dirtey buffer內容寫入磁碟
   2、例項3通知例項2寫入磁碟
   3、例項2檢視GRD,確定例項4持有的是Current Version,向例項4發出寫請求
   4、例項4將資料塊寫入到磁碟,同時在日誌中記錄一條BWR記錄記錄,並把鎖降級為XL0
   5、例項4通知例項2,寫完成,更新GRD
   6、例項2通知所有擁有PI的例項,可以清空PI空間,所有擁有PI的例項都會在logfile中記錄一條BWR記錄
   7、例項3會清空記憶體空間,在logfile中記錄BWR記錄,同時釋放鎖
      在叢集環境中,只有當需要清空的資料塊是current或者PI的時候,才需要發出寫請求,也就是例項曾經改變過資料塊,才要發出寫請求。
  上面的例子中,例項1要清空這個資料塊,可以直接清空,因為沒有改變過資料塊,但是例項3和例項4需要清空資料塊的話,就需要發出寫請求。
  真正的執行寫入操作的是擁有Current版本的例項完成的,在叢集中,只有一個例項擁有Current Version版本,所有持有PI版本的例項,必須等到持有Current版本的例項完成寫操作以後,才能清空這塊記憶體。   五、寫併發讀
   1、例項1想要讀取資料塊,向例項2請求
   2、例項2查詢GRD,例項4持有Current Version,向例項4轉發請求
   3、例項4傳送資料塊,模式將為SG1
   4、例項1獲得資料塊,獲得share模式的鎖
   (注:Oracle 10g的演算法中,例項4在第一次傳送資料塊時並不會立即降級為share mode,仍然繼續持有exclusive模式,同時例項4會計算髮給例項1的次數,如果次數超過了預設引數_fairness_threashold,就把自己降級為share mode)
      AST:
   下面我們來詳細的研究一下分散式鎖管理器是如何工作的?資料塊在例項之間是如何傳遞的。
   
   1、程序1和程序2擁有資料塊的S鎖模式,因此在Granted Queue中有記錄。假設現在程序2要獲得X模式的鎖,程序2必須先向DLM提出請求
   2、請求提交給DLM後,DLM就要把程序2放入到Converte Queue中,向擁有不相容模式鎖的程序1傳送一個Blocking ASTs(BAST),這是一個非同步請求,所以DLM不必等待響應。
   3、程序1接收到這個BAST以後,就會把lock降級為Null模式,DLM把程序2的鎖模式轉化為X鎖模式
   
   4、然後DLM傳送一個Acquisition ASTs(AAST)給程序2,並把程序2放到Granted Queue中
    RAC併發控制總結:
   1、針對資源性質不同,分為Cache Fusion和Non-Cache Fusion。針對不同的資源,使用不同的鎖機制。之所以使用不同的方式,主要是考慮效能問題,並不是資源併發需求不同。
   2、在Cache Fusion中,每一個數據塊都被對映為一個Cache Fusion資源,或者說是一個PCM資源,PCM資源實際上是一個數據結構,資源的名稱就是資料塊的地址(DBA)。每個資料請求動作是分步完成的,首先把資料塊地址X轉化為PCM資源名稱,然後把這個資源請求提交給DLM,DLM進行Global Lock的申請和釋放活動。只有程序獲得了PCM Lock,才能繼續下一步,也就是說第一步“例項要獲得資料塊的使用權”。
   3、除了獲得資料塊的使用權,還要考慮資料塊狀態,在單例項中,程序要想修改資料塊,必須在資料塊的當前版本(Current Copy)上進行修改。在RAC環境中也是一樣,如果例項要修改資料塊,必須獲得這個資料塊的當前版本拷貝,這就涉及一系列問題:如何獲得資料塊拷貝在叢集節點間的分佈圖,如何知道哪個節點擁有當前拷貝,如何完成傳遞過程,使用的技術就是記憶體融合技術(Cache Fusion),一旦獲得了訪問許可權,並且得到了正確的版本,程序就可以訪問資源。程序間仍然使用Lock和latch,和單例項一樣。
RAC架構:
 
 SGA的變化:
  RAC Instance的SGA最顯著的變化是多了一個GRD部分
  Oracle中的資料操作都是在記憶體SGA區中完成的,和傳統的單例項不同,RAC是有多個,每個資料塊可以在任何一個Instance的SGA中都有拷貝,RAC必須知道這些拷貝的分佈、版本、狀態,而GRD就是這麼一個記憶體資訊區,沒有明確的引數來標識GRD,每個SGA中只有部分GRD。  後臺程序的變化
  每個RAC的例項和傳統的單例項一樣,都有DBWR、LGWR、ARCn、CKPT這些後臺程序。
  每個例項還增加了若干RAC特有的程序。
  注意:程序名稱和程序提供的服務名稱差異很大,主要是因為程序名稱是從OPS時代延續下來的,但是服務卻已經在RAC中重新設計和命名。
  LMSn
   這個程序是Cache Fusion的主要程序,負責資料塊在例項間的傳遞,對應的服務叫做GCS(Global Cache Service)。這種程序的數量是通過引數GCS_SERVER_PROCESSES來控制,預設是2個,取值範圍是0-9.
  LMD
   這個程序負責提供的是GES(Global Enqueue Service),具體來說,這個程序負責在多個例項之間協調對資料塊的訪問順序,保證資料的一致性。
  LMSn、LMD、GRD構成了RAC最核心的功能Cache Fusion。
  LCK
   負責Non-Cache Fusion資源的同步訪問,每個例項有一個LCK程序。
  LMON
   各個例項的LMON程序會定期通訊,以檢查叢集中各個節點的健康狀況,當某個節點出現故障時,負責叢集重構、GRD恢復等操作,它提供的服務叫做Cluster Group Services(CGS)
   叢集中,健康檢測是非常重要的,如果健康檢測出現問題,那麼可能出現”腦裂問題“。叢集的健康檢測分為幾個層次:
   1、叢集軟體的健康檢測
    Network、OS、ClusterWare
   2、應用程式健康檢測
    對於RAC來說,應用程式就是例項,因此例項間的檢測就是應用程式層 面的檢測。
    例如Instance的異常關起,通過Network、OS、Clusterware層面進行 檢測,很可能檢測不出來,如果依靠LMON進行檢測,就可以輕鬆的檢 測到。
    資料庫必須有自我監控的機制。
    記住:LMON是RAC例項的一個程序。屬於典型的應用程式級別的檢測。屬於典型的資料庫自我監控機制。
    注意:CM在LMON的下面,LMON屬於應用層。CM屬於叢集層。
   Oracle RAC的LMON程序,被賦予自檢功能,這個功能就是LMON提供的CGS服務。
   1、LMON提供了節點監控(Node Monitor)功能,這個功能是用來記錄應用層各個節點的健康狀況,節點的健康狀況是通過一個儲存在GRD中的點陣圖(Bitmap)來記錄的,每個節點一位,0代表著關閉,1代表著正常執行。各個節點間的LMON會相互通訊,確認這個點陣圖的一致性。
   2、節點上的LMON程序會定期進行通訊,這個通訊可以通過CM層完成,也可以不通過CM層,直接通過網路層。
   3、LMON可以和下層的Clusterware合作也可以單獨工作,當LMON檢測到例項級別的腦裂時(例項認為對方已經down掉,自己還健在),LMON會先通知下層的Clusterware,期待藉助Clusterware解決腦裂問題。但是RAC並不假設Clusterware肯定能夠解決問題,因此LMON程序不會無盡等待Clusterware層的處理結果。如果發生等待超時,LMON程序會自動觸發IMR(Instance Membership Recovery)也叫做Instance Membership Reconfiguration。LMON提供的IMR看作是Oracle在資料庫層提供的”腦裂“、”IO隔離“機制。
   4、LMON主要也是藉助兩種心跳機制來完成健康檢測。
    節點間的網路心跳(Network Heartbeat):可以想象成節點間定時傳送Ping包檢測節點狀態。如果能夠在規定的時間內收到響應,就認為對方健在。
    通過控制檔案的磁碟心跳(Controlfile Heartbeat):每個節點的CKPT程序每隔三秒更新一次控制檔案的一個數據塊,這個資料塊叫做Checkpoint Progress Record,控制檔案是共享的,因此例項間可以相互檢查對方是否及時更新以判斷狀態。   DIAG
   DIAG程序監控例項的健康狀況,並在例項出現執行時錯誤時收集診斷資料包記錄到Alter日誌中
  GSD
   這個程序負責從客戶端工具,比如srvctl接收使用者命令,為使用者提供管理介面。  檔案:
  Oracle資料庫檔案分成幾類
   Oracle二進位制執行檔案、引數檔案(pfile、spfile)
   密碼檔案、控制檔案、資料檔案、聯機日誌、歸檔日誌
   備份檔案
  在RAC中檔案的佈局如下:
  1、spfile:需要所有節點訪問,需要放在共享儲存上
  2、Redo Thread:RAC環境下有多個例項,每個例項都需要自己的一套Redo Log檔案來記錄日誌,這套Redo Log就叫做一個Redo Thread。單例項下只有一套Redo Thread。
   因為RAC中每個例項都需要一個Redo Thread,因此對redo檔案的要求也同樣適用於RAC中對每個例項的要求。每個redo log thread至少要有兩個redo log group;每個log group成員大小相等,每組最好由兩個以上成員,這些成員放在不同的磁碟上。
   RAC環境下,redo log group是在整個資料庫級別進行編號的,比如例項1有1、2、3三個日誌組,那麼例項2的日誌組就應該從4開始編號。
  3、RAC環境下,所有例項的聯機日誌必須放在共享儲存上,某個節點異常關閉,剩下的節點就要進行Crash Recovery,執行Crash Recovery的這個節點必須能夠訪問到故障節點的聯機日誌,需要將聯機日誌放在共享儲存上。
  Archive Log:
   RAC中每個例項都會產生自己的歸檔日誌。歸檔日誌只有在執行media recovery的時候才能用到,所以歸檔日誌不必放在共享儲存上,每個例項可以在本地存放歸檔日誌。但是如果在單個例項上執行備份歸檔日誌、或者進行media recovery操作,要求這個節點必須能夠訪問到所有例項的歸檔日誌。
   1、使用NFS
   
   對於每個例項來說,/arch1+/arch2是所有的歸檔日誌,歸檔日誌位於兩個節點上。
   每個例項都配置一個歸檔日誌位置。
   2、例項間歸檔(Cross Instance Archive CIA)
    也是一種比較常見的配製方法。兩個節點都建立兩個目錄/arch1和/arch2分別對應例項1、例項2產生的歸檔日誌。每個例項都配置兩個歸檔日誌位置。位置1對應本地目錄、位置2對應另一個例項。
   引數   例項1   例項2
    log_archive_dest_1 location=/arch1  location=/arch2
    log_archive_dest_2 service=instance2 service=instance1
    standby_archive_dest /arch2   /arch1
   每個節點本地存放所有的歸檔日誌。
   3、使用ASM
    歸檔到共享儲存上   Undo Tablespace
   和Redo Log一樣,在RAC環境下,每個例項都需要有一個單獨的回滾段表空間。通過引數sid.undo_tablespace來配置。  SCN:
  在RAC環境中,由GCS負責全域性維護SCN的產生,預設使用的是Lamport SCN生成演算法。該演算法的大致原理是,在所有的節點通訊內容中都攜帶SCN,每個節點把接收到的SCN和本機的SCN對比,如果本機的SCN小,則調整本機的SCN和接收到的SCN一致。如果節點間通訊不多,則會主動地定期相互通報,因此即使節點處於idle狀態,還是會有一些redo log產生。另外一種演算法就是廣播(broadcast),這個方法是在每個Commit操作之後,節點要向其他節點廣播SCN,這種方式系統負載會大一些,但是確保每個節點在Commit之後,都能立即看到SCN號。
  Lamport系統負載小,但是節點間會有延遲。廣播雖然有負載,但是沒有延遲。
  在節點1上修改了資料並提交以後,立即在節點2上查詢這些資料,如果用Lampport演算法並間隔時間足夠的短,則在節點2上查詢結果可能就是修改前的狀態。如果有這些特點,那就需要使用廣播演算法。Oracle 10g 的RAC中,預設使用的是Broadcast演算法。  Cache Fusion、GCS、GES:
  記憶體融合技術(Cache Fusion)就是通過高速的Private Interconnect,在例項間進行資料塊的傳遞。這是RAC最核心的工作機制,他把所有例項的SGA虛擬成一個大的SGA區。
  每當不同的例項請求相同的資料塊,這個資料塊就需要在例項間進行傳遞。在oracle7的ops中,這種傳遞是通過磁碟完成的,也叫做Disk-Based Ping。也就是第1個例項必須先把這個資料塊寫回到磁碟,然後第2個例項再從磁碟上讀取這個資料塊,這種通過磁碟傳遞資料的方法極大影響了系統性能。在Oracle8i中,oracle引入了Net-Based Ping技術,開始通過Private-Interconnect來傳遞資料塊,但是Oracle8i只能傳遞沒有修改過的資料塊,對於修改多的資料塊,只能通過磁碟傳遞。到了oracle 9i的cache fusion,所有的資料塊(無論是否修改過)都可以通過Private Interconnect傳遞,因為Net的資料傳遞速度要遠遠的高於磁碟寫,因此RAC的效能和伸縮性得到了極大的提高。
  真個的Cache Fusion有兩個服務組成:GCS和GES。前者專職於資料塊在例項間的傳遞,後者負責鎖管理。 RAC和Clusterware的互動:
 RAC的最主要的功能還是併發控制
 RAC還是一個HA(高可用叢集),當某個例項發生故障的時候,叢集必須能夠進行調節。就是能夠根據叢集狀態的變遷自動重構,這就需要和Clusterware進行互動。
 Clusterware要決定叢集組成、成員身份、成員狀態,Clusterware並不關心上層的應用到底是一個數據庫還是web站點,他只是負責收集叢集的節點狀態完整檢視,並向上層提供這個檢視。RAC要依賴與Clusterware,他需要從Clusterware獲得這個檢視,根據檢視調整自己。
 RAC不是完全的依賴Clusterware,很多時候RAC是兩條腿走路:先看Clusterware 能不能解決,如果能解決,皆大歡喜;如果不能解決,RAC自動解決。  Clusterware層
  所有節點的Clusterware組成一個叢集,這些節點構成了一個叢集成員列表(Cluster Membership List),每個節點會分配一個成員ID(node id)。這些Clusterware間相互通訊,以瞭解各節點的狀態,並從中選出一個節點作為Master Node,Master Node負責管理叢集狀態的變遷,當有新的節點加入叢集或者有節點離開叢集的時候,叢集的狀態就會發生變遷,變遷的結果達到一個新的穩態。每個穩定的狀態用一個數值來表示,這個數值叫做Cluster Incarnation Number,當從一個穩態轉變成另外一個穩態的時候,CIN也會改變。
  RAC中的各個例項也構成了一個例項成員列表(Instance Membership List),RAC的每個例項也使用Clusterware層的node id作為身份標識,這個node id在整個叢集生命週期內是不會變的。RAC Instance在啟動時會把LMON、DBWR等需要操作共享儲存的程序作為一個組註冊到Clusterware中,並從Clusterware獲得node id作為組ID。
  RAC叢集和節點叢集是兩個層次的叢集,兩個叢集都有腦裂、IO隔離等問題。這兩個叢集都有各自的故障檢測機制,對於RAC叢集來說,如果在RAC層檢測到“節點故障”,RAC會做如下的工作:
   1、RAC暫停對外提供服務
   2、RAC通知Clusterware這種異常,並等待Clusterware完成叢集重構,達到一個新的穩態
   3、Clusterware叢集完成重構後,會通知上層的RAC叢集,RAC叢集接收到這個訊息後,RAC叢集開始重構。
   RAC層
  RAC的叢集狀態維護是由RAC的LMON程序提供的,這個程序提供了CGS和NM兩個服務。
  最下層是NM(Node Management)服務,它是RAC叢集和Clusterware叢集的通訊通道,通過它把本節點的資源(Cluster Resource)狀態登記到本地的Clusterware。進而由後者提供給其他節點的Clusterware,NM還要從Clusterware 獲得其他節點的資源(Cluster Resource)狀態。
  叢集層和應用層各負其責,應用層負責將自己的狀態通報給叢集層,叢集層負責將應用層的狀態通報給其餘節點,應用層同時從叢集層獲得其餘節點的應用層狀態。很多的簡單的叢集軟體並沒有提供應用層監控功能,只是簡單的網路和OS監控。缺少了應用層給叢集層狀態的過程。
  1、NM組(NM Group)
   每個RAC都有很多程序在工作,比如DBWR、LGWR、LMON等。其中任何一個程序出現故障,這個節點所有其它程序活動都應該受到限制,否則可能破壞共享磁碟上的資料。因此RAC的每個例項的所有程序是作為一個組(NM Group)註冊到Clusterware中的,其中LMON程序作為組裡的Primary Member註冊並獲得Member ID,而其它程序作為這個組的Slave Member並以相同的Member ID註冊到Clusterware。
   整個叢集的節點成員資訊是通過一個位圖(bitmap)來維護的,每個節點對應1個bit,0代表節點down、1代表up,整個點陣圖有一個有效/無效標誌位。這個點陣圖在整個叢集中作為一個全域性資源永久記錄,當有新節點加入叢集時,該節點需要讀入這個點陣圖,找到自己對應的bit,把值從0改為1,並且把點陣圖的無效標誌位置為1,這個點陣圖狀態變為無效(內容是正確的,根據需要變為無效)。其餘節點定時讀入這個點陣圖,一旦發現這個點陣圖狀態無效,就會觸發叢集重構,達到新的穩態後,再把點陣圖狀態置為有效。當叢集重構完成後,NM會把這個事件傳遞給CGS層,CGS負責同步所有節點間的重構。
   對於例項正常的啟動和關閉,該例項的NM會向Clusterware進行註冊或取消註冊,在註冊過程中,NM同時從Clusterware獲得叢集其餘節點列表,然後NM通知其他節點的NM,最後NM事件傳送給CGS層,有CGS協調整個叢集組的重構。CGS完成重構以後,通知GCS、GES進行例項的重構(主要是GRD的重構)。正常的啟動和關閉,Clusterware、NM都會獲得通知。如果是例項異常關閉,Clusterware、NM就不會知道,這時需要CGS提供的IMR功能進行感知,然後重構。
   IMR是由CGS提供的重構機制,用於確認例項之間連通性、快速的排除故障節點以減少對資料的損壞。在這個過程中,每個例項都需要做出投票,投票的內容就是它所認為整個叢集現在的狀態,然後由一個例項根據這些投票,重新規劃出一個新的叢集(最大的Subgroup),並把這個投票結果(Voting Result)記錄到控制檔案,其他例項讀取這個結果,確認自己是否屬於叢集,如果不屬於叢集,就要自動重啟,如果屬於叢集,則參與執行重構過程。
   在投票過程中,所有成員節點都嘗試獲得控制檔案中的一個欄位(CFVRR Control File Vote Result Record)已進行更新,但只會有一個成員獲得。這個成員負責記錄投票內容。
       如果IMR發現出現split-brain,既叢集中出現兩個group,這時IMR會先通知CM,然後等待CM解決這個split-brain,等待時間是_IMR_SPLITBRAIN_RES_WAIT,預設是600毫秒。超時後IMR自己執行節點排除。在CGS完成節點的重構以後,GCS、GES才進行資料層面的重構,也就是Crash Recovery。   2重構觸發型別
   有多種原因可以造成叢集的重構
   1、由於某個節點加入或離開叢集而觸發叢集重構,這個重構是NM觸發的
   2、Network Heartbeat異常:因為LMON或者GCS、GES的通訊異常,這些程序要定期通訊,如果傳送失敗或者接受響應超時,就會觸發重構,這個超時時間由引數_cgs_send_timeout控制,預設是300秒,這時的重構是IMR觸發的。
   3、Controlfile Heartbeat異常:每個例項的CKPT程序每隔3分鐘都會更新控制檔案的一個數據塊,這個資料塊叫做Checkpoint Progress Record,並且是每個例項對應一個。因此不會出現資源爭奪現象,在建立資料庫時create database ….max instance引數就確定了會建立多少個這種記錄,這種重構也是由IMR觸發的,時間由引數_controlfile_enqueue_timeout控制,預設是900秒。 總結Clusterware和RAC的關係:
 1、Clusterware是由不同廠商包括Oracle提供的,用於維護管理節點的狀態
 2、RAC Instance是構建在Clusterware之上的資料庫應用或者叫Instance的叢集
 3、Clusterware維護的是節點叢集、RAC維護的是Instance叢集
 4、兩者各有自己的機制來進行狀態檢測及重構,也就是說RAC叢集雖然使用Clusterware,但不完全依賴Clusterware