RAC下的并发控制
1. DLM
dlm(分布式锁管理):记录着哪个节点正在用哪种方式操作哪个数据,并负责协调解决节点间的竞争
举例说明DLM的作用:
一个两个节点的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能够操作数据
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正被进程1修改,所以进程2只能等待。
oracle RAC徐泽的是以数据块作为粒度单位。也就是说进程想要修改记录1时,向dlm提出的申请是“数据块1的操作权限”,而不是“记录1的操作权限”。
2. dlm中资源和锁
dlm协调集群各节点对资源使用的功能叫作同步。所有的资源访问都是需要同步。
在dlm中把资源分成了两大类。分别叫作PCM RESOURCE (cache fusion resource)AND NON-PCM RESOURCE(non-cache fusion resource)。
cache fusion resource特指数据块资源。非数据块资源全部归为NON-cache fusion resource,包括数据文件,控制文件,数据字典视图,Librarycache 、row cache等
dlm提供的锁分为两种:PCMLOCK AND NON-PCM LOCK 。加上 lock 和latch,在rac数据库中共有两大类4种锁。
Global locks:用于集群间的并发控制,由 后台进程使用
Pcm locks | Non -pcm locks |
local locks:用于本地进程间的并发控制,由用户进程和后台进程使用
Locks |
Latch |
|
GRD中记录PCM lock的信息它位于每个实例的SGA中 但每个实例都仅含部分GRD、所有实例的GRD汇总在一起才是一个完整的GRD
PCM lock有3个主要属性:Mode、Role、PI
① Mode
--S
--X
--NULL
对于S,X两种锁模式这里不再赘述
而NULL代表对应的内存空间可以被重用、在没有被重用之前、实例是不能访问这里的数据
② Role
Role这个属性是用来描述“脏块”在集群间的分布状况
注意,“脏”只是用来描述数据块的内存版本和磁盘版本是否一致、和事务没有关系
Role有两个取值:Local和Global
⑴ 对于Local Role、Mode只会是S或X:
Ⅰ 如果Mode是S,则该数据块内存版本和磁盘版本一致
Ⅱ 如果Mode是X, 则该数据块内存版本和磁盘版本不同
当拥有LocalRole和X Mode的实例给其他实例发送数据块:
Ⅰ 如果接收方收到的也是和磁盘一致的版本的,那么本实例(发送方)仍然保持Local Role
Ⅱ 如果接收方收到的和磁盘版本不一致,那么发送方和接收方的角色就要转换成Global
⑵对于Global Role、Mode可以是S、X、或NULL
Global Role意味着一个“脏块”同时被多个实例拥有
如果想要把这个“脏块”flush到磁盘,必须要联系GRD,让拥有该块Current版本的实例完成写动作
但对于拥有LocalRole的实例而言,如果要把“脏块”flush到磁盘,不需要联系GRD,由本实例完成即可
③ Past Image
下面通过例子说明什么是PastImage
假设一个2节点的RAC集群,块_A在磁盘上的SCN=1
1)node1要修改块_A,从磁盘读入SGA进行修改,修改后块_A在内存中的SCN=2
2)node2也要修改块_A,node1就会通过cachefusion把块_A传送给node2,传的是SCN=2的版本,
即Currentcopy的数据块,这时node1还是会保留这个SCN=2的块在SGA中,但是不能再进行任何修改
这时node1拥有的这个Image就叫做“PastImage”
在node1发送Currentcopy之前,会先把相应的redoentry flush到redolog
3)node2修改这个数据块,修改后SCN=3,但磁盘的版本仍然是SCN=1
4)如果node1发生检查点事件,因为node1上块_A是“脏块”,所以块_A必须被同步到磁盘
5)node1会联系GRD,发现node2拥有块_A的Current版本,GRD会通知node2把这个块写入磁盘
6)node2完成写之后,会通知所有拥有PI版本的实例释放他们所拥有的PI内存。这是node1会在logbuffer中记录一条BWR记录,然后释放pi内存。
7)假设node2没有完成写时就异常宕机,这时就会触发node1进行crashrecovery。虽然之前的修改动作被记录在各个节点的联机日志中,但是因为node1拥有最近的PI,所有只需要利用实例1的PI和node2的联机日志就可以完成恢复。
所以,pastimage 代表着这个实例的sga中是否拥有和磁盘内容不一致的版本,以及版本顺序,并不是代表这个节点是否曾经修改过这个数据块,pastimage主要能够加速crashrecovery的恢复过程。
接下来,我们通过下面的的例子说明在RAC 数据库中访问某个block时会发生什么事情。
1. 节点C要求读取块1008。
1)1008块的主节点被hash到D节点,之后节点C向主节点发送请求,要求以S模式锁定块1008。这时buffer lock的模式是SL0(S?hared ,L?local, 0?没有PI)。
2)主节点把对应的锁赋予节点C。
3)节点C 从数据文件中读取块108。
4)读取完成,节点C 以获得对应的锁,属性为SL0。
2.节点B要求读取块1008。
1) 节点B向主节点D发出请求,要求以S模式锁定块1008。
2) 主节点D发现节点C已经以S模式获得了对应的锁,而且S锁之间是可兼容的,所以,不需要锁的转换,主节点D要求实例C发送块1008 给实例B。
3) 节点C发送对应的块给节点B。
4) 节点B通知主节点D,已经获得了块1008上的S 锁,属性为SL0。
3.节点B要求修改块1008 中的信息。
1) 节点B向主节点D发出请求,要求以X模式锁定块1008。
2) 主节点D发现节点C已经以S模式获得了对应的锁,而且S锁于X锁之间是不兼容的,所以,需要锁的转换,主节点D要求节点C将对应的锁级别降低为N,所得属性为NL0
3) 节点B将自己的所降级,并且将本地的块1008 标识为CR。之后,节点B将块1008 修改为块1009,同时将通知主节点锁的属性为XL0。
4.节点A要求修改块1009。
1) 节点A向主节点D发出请求,要求以X模式锁定块1009。
2) 节点D发现节点B已经以X模式持有了对应的锁,而且X模式的锁是不能兼容的,所以,主节点D 要求节点B降级锁到N模式,同时由于块在节点A和B都被修改,所以,锁的角色变为全局(Global),而且节点B上的块会变成一个PI。也就是说这时,节点B上的锁的属性为NG1(模式—> N, 角色—>G, 存在PI—>1)。
3) 节点B完成锁的降级之后,把块1009传递给节点A。
4) 节点A修改块1009 为1013,同时将自己节点的锁设置为XG0,并且通知主节点。
5. 节点C 查询块1013。
1) 节点C发送请求给主节点D,要求以S模式锁定块1013.
2) 主节点发现节点A拥有最新的块1013,而且这个节点以X模式锁定了这个块,因为X和S锁是不兼容的,主节点发送请求给节点A,要求降级锁。
3) 节点A降级锁为S模式,同时,由于最新的块会发送给节点C,所以在节点A上的块1013变为PI。接下来,节点A把块1013发送给节点C。这是节点A上的锁为SG1。
4) 节点C收到最新的块1013,并且以S模式锁定块,并把自己的锁更新为SG0。最后,通知主节点D。
根据以上的说明,我们能够看到,对于RAC系统,当一个进程需要访问一个块时,一定要首先获得块上对应的锁,之后才能对块进行相应的操作。而且,在RAC系统中,无论数据库包含多少个节点,当访问一个buffer时,最多会有3个节点参与其中,他们是主节点,持有者节点和申请者节点。而且,每一次访问的时候,都要有消息在节点间不断的传递。另外,我们能看到,如果锁的角色是全局,那么我们要做的事情更多,也意味着我们要访问的代码深度也越多。这也从一个角度解释了为什么oracle 会在RAC中推出DRM,read mostly,reader bypass等新特性(关于后两个新特性,我们会在今后的文章介绍)。
最后,对于PCM lock,以上过程都是由 lms进程完成的。而对于enqueue,是由lmdj进程完成的。