这一篇,我们来了解一下基于Shared Disk的Oracle RAC数据仓库的技术。
一、什么是Oracle RAC(Real Application Cluster)?
Oracle Real Application Cluster 简称RAC,也就是Oracle数据库集群,是Oracle新一代数据库中采用的新技术,它具有高可用性,也是Oracle数据库支持网格计算环境的核心技术。
Oracle RAC 是一个具有共享缓存架构(Cache Fusion)的集群数据库,它一般由两台以上的计算机和共享存储设备构成,可提供强大的数据库处理能力。它克服了传统的单机数据库的限制(非共享磁盘),为用户业务提供了一种具有高可用、高性能、可扩展的数据库解决方案。另外,Oracle RAC 也是 Oracle 私有云架构的关键组成部分。 下图简单的描述了单实例数据库和RAC之间的区别。一般来说,出于对数据库业务连续性和安全性考虑,用户可直接搭建RAC,不推荐单实例Oracle数据库。
单例模式下,一个数据库只能通过一个实例进行访问数据库,如果该实例宕机了,那么业务就会中断。因此,单节点的可用性很差。
RAC与单实例最大的区别是:共享数据库文件。一个数据库生成多个相同的实例被用户访问,多个实例管理一个数据库,这个数据库必须安装在共享存储上。
该架构的优点:
- 高可用:个别实例宕机,并不影响该系统对外提供服务。
- 高性能:集群的事务处理功能大大增强,多个实例可以并发的工作。
- 可扩展:当系统性能遇到瓶颈时,通过增加节点可以提高数据库的性能。
RAC系统是作为一个整体对外提供服务,如上图所示是由三个实例共享同一份数据库,这样是在三个实例之间做了冗余,任意两个实例坏了,业务都可以访问到剩下的一个实例,可以正常的工作。RAC不是分布式系统,因为它只有一个存储,分布式系统是指数据存储在不同的数据库上,RAC还是一台数据库,多个实例,RAC提供了在实例级别的冗余。
由上可知,Oracle RAC的本质上是不同服务器上的Oracle实例能够同时访问同一个Oracle数据库,每个节点间通过私有网络进行通信,互相监控节点的运行状态。Oracle数据库所有的数据文件都放在集群的共享存储上,即:RAC使用共享存储实现数据的共享。共享存储的实现方式有很多种,可以通过自动存储管理(ASM)、Oracle集群文件系统(OCFS)、裸设备(RAW)、网络附加存储(NAS)等来保证整个集群系统的数据一致性。 下面我们就来看下RAC的架构及论文中的实现描述。
二、RAC架构
传统Shared-Disk(共享磁盘)机制:
在传统的基于共享磁盘shared-disk的应用中,多个节点通过分布式锁来读写共享磁盘。共享磁盘是做为数据交互的唯一手段。比如:节点A读取的Page页面在节点B上是脏页,节点A必须等待节点B刷新脏页后,节点A才能读取到这个Page页面的最新数据。
RAC Cache Fusion(共享高速内存) 机制 :
超大规模的磁盘阵列的发展和IP-SAN/FC-SAN存储的广泛应用给数据库架构提供了新的可能性。 充分发挥新网络硬件的大带宽、低延迟特性,数据的共享通过高速专用存储网络,而不是共享存储,因为访问磁盘的IO代价比网络传输要高的多。这使得不同的Oracle实例直接通过高速网络读取其他节点上Page页面中的最新数据,避免了昂贵的磁盘IO开销。
于是,RAC中引入了一个叫Cache Fusion(共享高速缓存)的机制,扩展了基于Shared-Disk(共享磁盘)架构的交互方式,采用shared-disk + shared-buffer,即:共享磁盘+共享缓存。允许不同节点间通过私有高速网络共享数据库内部的buffer数据块,数据直接从一个节点的buffer缓存传递到其他节点上,避免了读写共享磁盘,从而提高了性能。简单理解就是,Cache Fusion实现了多个节点之间的共享内存,也就是把所有机器的内存当成一个整体的内存来使用。
三、Overview of RAC
这里只对RAC原理做简单介绍,详细内容可见论文《Cache Fusion: Extending Shared-Disk Clusters with Shared Caches》中的描述。
如上所述,Cache Fusion实现了多个节点之间的共享内存,要管理这块内存以及协调各个节点对这块内存的访问,Oracle引入了GCS(Global Cache Service)、GES(Global Enqueue Service)、GRD(Global Resource Directory)这三个概念,GRD、GCS、GES是Cache Fusion结构的核心。
全局缓存服务 GCS(Global Cache Service)
负责数据库在实例间的传递,控制不同实例对数据块的访问,后台进程使用GCS在全局buffer cache中维护缓存的一致性。GCS对数据块的状态和位置进行跟踪,同一时间只允许一个节点修改一个cache resource(data block),并通过内部连接将块传输到其他节点的实例中。GCS知道所有数据块的分布视图,因此可以把一个读写请求转发到一个最合适的节点来处理。比如:一个节点要修改一个数据块,GCS可以把这个请求直接转发给该数据块当前的持有节点holder,该holder再把修改之后的数据块最新数据传给发起者,同时GCS标记该数据块Block的持有节点holder为这次请求的发起者。
GCS是一个去中心化的分布式结构,这样设计有两个好处: 1)避免单点性能瓶颈,使global cache资源的维护均摊到了每个节点上; 2)避免单点故障,单个硬件或者软件故障不会影响其他节点,故障节点维护的资源暂时不可访问(由recover流程来恢复),其他资源仍然能够继续使用。
全局队列服务 GES(Global Enqueue Service)
负责锁的管理,控制对锁的访问。管理所有Non-Cache Fusion资源的同步,GES主要控制数据库中所有的Dictionary Cache锁和Library Cache锁,这些资源在单实例数据库中是本地性的,但是到了RAC群集中变成了全局锁资源。全局锁资源也是用来保护数据的锁,进行事务的管理,同时,还对所有死锁和资源死锁起到检测的作用。
全局资源目录 GRD(Global Resource Directory)
GRD是Cache Fusion的内部数据库,保存着所有实例资源的分布情况。用来记录数据块拷贝在集群节点间的状态分布图,模拟一个横跨集群内所有节点的全局SGA。
GRD中包括如下共享资源信息:
(1)数据块的标识符,例如:数据库地址(Data Block Address, DBA)。
(2)如果数据块在集群中多个节点的Buffer Cache中存在,GRD中保存该数据块最新版本的位置。
(3)实例持有的数据块的模式:Null(N)、Shared(S)、Exclusive(X)。
(4)每个实例持有的数据块角色:Local或者Global。
GRD中的信息是Cache Fusion的元数据信息,是Cache Fusion协调资源和管理的来源。GRD分布在各个实例中,每个实例维护GRD的一部分,GRD由GCS和GES共同管理。
GCS和GES会根据一定的算法,在RAC的各个节点中选择出一个节点作为Resource Master。这个Resource Master负责处理数据块的请求。
并且Resource Master会在内存中记录每个instance中GRD的索引,在RAC的Master Node上记录了该资源在所有节点上的使用信息,而每个节点的使用信息记录在本节点上。
Cache Fusion协议
Cache Fusion协议:通过节点间快速的消息传递,来共享节点的local buffer cache内容(数据块),从而产生了集群范围内的global buffer cache。 简单来说就是:通过网络来共享节点间的buffer cache。
有2中共享模式:
1)Read-Sharing:用来查询操作时,访问其他节点上的buffer cache的机制。基于Consistent-Read机制(current page+undo)实现的多版本read-sharing协议允许直接从其他节点读取buffer,而无需节点间维护始终维护缓存一致性。
2)Write-Sharing:用来更新操作时,访问其他节点上的buffer cache的机制。允许直接从其他节点上拉取buffer到本地,然后再更新,允许其他节点上这个页面当前是脏页。
Cache Fusion协议减少了IO,依赖节点间高性能的数据传输。核心思想是通过data sharing协议充分发挥网络IO,减少共享盘IO。
RAC的容错
RAC中的实例,除了有单实例固有的那些后台进程,还会多一些用来进行RAC实例之间进行交互的进程。在RAC中,每个实例有自己单独的redo log和undo表空间。因为每个实例都要独自处理事务,但是这些redo和undo文件同样要放置在共享磁盘中,因为一旦实例崩溃,但是实例的redo并没有坏,还放置在共享存储上面,它的redo还是允许其他实例访问的,其他的实例读取到该实例的redo和undo进行事务的恢复。比如:当节点A坏了,不仅仅只是将业务切换到节点B,这个时候还要处理节点A坏了遗留下来的问题,主要是一些提交和未提交的事务,节点A最后将所有的数据写到磁盘之后产生的所有的redo应用,该回滚的回滚,该恢复的恢复。
Oracle DLM分布式锁
RAC数据库主要任务就是事务处理,而解决多个节点间的并发问题是通过分布式锁管理器DLM(Distributed Lock Manager),传统的分布式锁管理器DLM最早由VMS操作系统提供,首次出现在Digitial于1982年发布的VMS版本3中。从1984年发布的VMS版本4之后,其对用户提供的应用编程接口基本确定。2006年,开源操作系统Linux的版本2.6.19内核正式集成了与VMS DLM接口几乎一致的DLM。
Oracle RAC的Cache Fusion在多个实例节点内存之间操作page cache时,需要对page cache上锁,因此就需要有一个高性能的分布式锁的组件DLM,即:DLM是以数据库为单位进行粒度调节的,因此该DLM分布式锁是:1)数据平面的;2)锁的信息无需落盘。而像etcd,zookeeper中实现的分布式锁是基于复制协议实现的,其主要使用场景是配置管理,集群拓扑管理等,属于控制平面,复制协议在运行过程中,会对日志落盘。
使用传统DLM的系统软件有:Oracle RAC的分布式锁,OCFS2中的DLM,以及RedHat公司开发的GFS2(Global File System2)中的DLM,它们都是参考了美国Digital Equipment Corporation公司的VAX/VMS操作系统中分布式锁的设计。
DLM是去中心化的设计,所有的节点是对等的,每个节点都只存储了一部分的锁信息。一个锁会涉及到3个角色:
1、请求锁的节点Requester Node:发起请求上锁的节点。
2、锁的目录节点Directory Node(持有锁的节点):持有当前锁资源上高级别锁的节点。
3、锁主节点Master Node:管理锁内容的授权节点。
在DLM中,一个锁的信息有2个副本: 一个是Master Node,这是锁的真正管理者,维护该锁的队列以及锁状态;另一个是Requester Node上的Shadown或锁副本,用于在本节点维护已经上了哪些锁,以及锁的模式等。
简单描述加锁的流程,有3个节点:A,B,C,
-
节点A计划对资源R1上锁,先在本地构造该锁dlm_lock,也称为锁的shadow;
-
节点A,通过R1的lockid以及一个hash函数,计算出这个R1所对应的目录在B上;
-
节点A请求节点B,得到R1的目录信息,目录信息中记录了R1的锁的master在C上;
-
节点A向节点C发起对R1上锁的请求;
-
节点C维护R1的锁请求队列,如果允许A上锁,则返回成功;
-
节点A更新本地R1锁shadow相关信息,上锁成功; 论文《The VAX/VMS Distribute Lock Manager》中有对DLM分布式锁的详细描述,还可以参考本人在OCFS2技术专栏中对DLM实现介绍,需要注意的是,OCFS2中并没有完全按照论文中的细节去实现的DLM,而是做了一些裁剪,比如说锁模式,DLM的论文中抽象出了6种锁模式,级别高的锁跟级别低的锁模式的兼容性如下所示:
下面是6种模式以及每种模式使用场景:
在如上DLM原生的锁模式中,我们可以看到:
CR:Concurrent Read Mode,并发读,一个节点在读一个已授予的锁资源时,允许其他的节点同时读CR、PR,并且该模式与CW(并发写)、PW(保护写)是兼容的,这意味着允许写操作,此时CR读是不受保护的,即:读到的不是最新数据。
CW:Concurrent Write Mode,并发写,一个节点在写一个已授予的锁资源时,允许其他的节点同时读CR,并且该模式与CW(并发写)是兼容的,这意味着允许多写操作,此时CW是不受保护的。
PW:Protected Write Mode,保护写,只有一个写者,写操作是被保护的。允许有其他的读者,不允许同时写。
而在OCFS2中只使用了其中的3中锁模式:EX/PR/NL,EX是排他锁,写锁时加EX锁级别;PR是共享锁,读锁时加PR锁;NL是空锁。
由下图兼容性可知,对同一个锁资源lockres来讲:
1)如果一个节点持有EX锁,那么其他节点只能是NL锁,此时如果有节点是EX锁或PR锁,它必然要做降级处理,即:写操作只有一个节点,只允许一个写,也不允许写的时候同时读;
2)如果一个节点持有PR锁,那么其他节点可以获得PR锁和NL锁,即:可以多个节点读操作。
3)NL锁是空锁,与所有锁兼容。
OCFS与RAC
OCFS1问世于2002年10月,它是Oracle公司为了让RAC(Real Application Cluster)用户避免必须要与裸设备打交道而开发出来的。这个文件系统用来存放数据库相关的文件,比如:数据文件,控制文件,在线日志文件,归档日志文件等。
OCFS2是下一代的Oracle集群文件系统,它已经被设计成为一种为通用的文件系统,它不仅可以存放数据库相关的文件,还可以存放Oracle二进制文件(指Oracle_home下的软件文件)和配置文件,从而使RAC的管理更加轻松。目前Oracle公司同样将其用于虚拟化场景,其用于保存虚拟机镜像文件和相应的配置文件。
OCFS2文件系统在内核中处于VFS(虚拟文件系统)下层,如果对OCFS2文件系统中的文件进行读写操作,与其他具体的文件系统一样,用户都是通过普通的read和write接口调入到VFS层通用接口,然后再根据具体的文件系统指针找到对应的文件系统处理函数进行处理,因此linux内核能够方便的处理多个具体的文件系统。
在OCFS2内核代码结构主要包括以下几个方面:集群服务结构Cluster(TCP、o2hb、o2nm、quorum)、分布式锁管理器DLM、用户空间和内核空间DLM的接口(DLMFS)、具体文件系统层。OCFS2的具体实现分析,详见本人的OCFS2技术专栏。