关闭

RAC原理 转载自http://blog.csdn.net/xabc3000/article/details/7078399

205人阅读 评论(0) 收藏 举报
分类:
数据库基本原理
 数据库系统和其他数据管理很重要的一个区别就是 允许并发访问
 最大挑战是 数据不一致
 如何保证并发和数据一致是数据库系统的核心
 并发访问和数据一致性:
  数据不一致的情况
   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
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:2661次
    • 积分:96
    • 等级:
    • 排名:千里之外
    • 原创:7篇
    • 转载:2篇
    • 译文:0篇
    • 评论:0条
    文章存档