首页 理论教育分布式数据库技术-分布式数据库技术

分布式数据库技术-分布式数据库技术

【摘要】:Oracle公司的OPS环境比一般的(单实例)Oracle环境复杂得多。不同结构下的OPS的实施略有不同。图14.23OPS体系结构为了利用这些特性,需要专业人员合适的设计以及恰当的手工配置。下面对有些关键问题进行简单讨论,讨论中会涉及一些Oracle系统专用的术语,读者可参阅Oracle公司的相关文档。DLM与Oracle进程一起工作并相互通信。DLM相关的初始化参数在每个实例的SGA[12]中分配必要的结构以处理消息机制、封锁与实例相关的Cache管理,这样就为各种Oracle进程操纵提供了基础。

Oracle公司的OPS环境比一般的(单实例)Oracle环境复杂得多。简单来说,OPS是一种数据库配置,在这种配置下可以同时运行多个实例[10],每一个实例引用相同的物理数据文件集合(见图14.23)。OPS是在特殊环境下的一种配置,它要求有多个系统(节点),所有节点共享磁盘(数据文件存放于磁盘上),即集群系统,或基于MPP的系统。不同结构下的OPS的实施略有不同。例如,在MPP结构下,可以同时利用不同的节点进行队列处理,并且因为节点间是高速互联结构,所以数据移动十分迅速,从而增加了系统吞吐量。但是在某些集群平台下未必是这样的情况。每一个支持实例的节点称为“参与”节点,它们都可以访问共享磁盘。每个实例与其他实例之间是一种兄弟关系,而不是父子关系。因此,一个或多个节点发生故障,并不会让整个数据库不可访问。理论上讲,只要有一个幸存的实例,数据库可用性就不会受到冲击。从单方面的视图来看,每个参与节点的实例可以看成是一个常规的(非OPS)实例。因此,两个或多个实例构成OPS配置。每个实例对共享磁盘的访问是通过称为DLM(distributed lock manager,分布式封锁管理器)特殊的软件进行同步和控制的。

在OPS下,如果一个节点发生了故障,通过其他节点仍然可以访问数据库,这样就避免了整个系统成为单一的故障点。如果一个节点发生了故障,并且该节点上的实例失效,那么某个幸存的节点(检测到发生实例故障的节点)可执行必要的实例修复。

如果不能自动检测到故障,实例的修复就发生在该实例手动重启之时。

OPS具备的特点:在节点出现故障时仍能提供可用性。在节点间歇性故障发生后,它能自动启动实例修复进程,因此提高了MTTR。它通过负载均衡提升了性能(访问分布式的实例,允许同时利用来自不同节点的内存和CPU)。通过允许利用大量节点(新的节点可以根据需要“插入”),可提供高容量和可扩展性,这在MPP配置中特别有用。

图14.23 OPS体系结构

为了利用这些特性,需要专业人员合适的设计以及恰当的手工配置。

下面对有些关键问题进行简单讨论,讨论中会涉及一些Oracle系统专用的术语,读者可参阅Oracle公司的相关文档。

OPS结构构件和操作:在OPS配置中,每个实例以共享/并行模式(不同于一般的非OPS配置中的互斥模式)打开数据库。每个实例使用它自己的init.ora文件[11],该文件列出了许多与实例相关的参数。

另外,每个实例使用某些对不同实例具有相同值的参数(这些参数一般放置在config.ora文件中)。正如前面所讲的,这些参数被DLM使用,以同步所有的实例。

与一般(非OPS)环境相比,下面讨论比较特殊的内核级OPS构件,其中最重要的就是分布式封锁管理器(DLM)。

1.DLM

分布式封锁管理器(DLM)是一个十分重要的系统。DLM与Oracle进程一起工作并相互通信。DLM相关的初始化参数在每个实例的SGA[12]中分配必要的结构以处理消息机制、封锁与实例相关的Cache管理,这样就为各种Oracle进程操纵提供了基础。这些结构是逻辑性的,被称为DLM资源结构。DLM资源有可能是多个节点请求的对象,因此,对其访问时需要在节点之间进行协调。DLM资源的例子,如数据文件内的块、控制文件结构和共享池中的对象等。每个需要访问由DLM保护的资源的进程必须先获得该资源上的封锁,因为这些资源在不同的参与节点内存中,所以节点之间需要不断地进行协调。在特定状态下,被某节点使用的资源不能并行地被其他节点使用。

DLM提供的服务包括以下几方面。

●维护系统资源的可用信息,实施封锁机制,以控制对这些资源的共享访问(内部实例之间)。

●后台进程与前台进程之间实现的远程和局部进程间的通信。

●内在的故障检测机制,例如死锁检测和在合适情况下进行应用修复。当进程突然意外终止时,它所占有的资源会被释放到可用的资源池。

DLM通过封锁来协调资源的使用。访问某一资源的不同进程会请求以特定的模式(类似于行(元组)/表(关系)加锁)锁住资源。例如,实例A上的进程A以EX(互斥)模式请求锁住某一资源并且获得该资源。稍后,实例B上的进程B也请求以EX模式锁住该资源。显然,进程B此时需要等待,直到进程A已经完成并且通知了DLM。一旦DLM知道进程A已经完成,DLM就允许进程B(假设没有同等优先级或更高优先级的进程在等待)获得锁。DLM也允许通知进程A,进程B正等待它所占用的锁。这里,不一定按照先来先服务的原则分配封锁,实际上,这是按照一种基于进程优先级(对特定进程来说,是获取一个锁的紧迫程度)的优化算法。资源也可以以兼容模式(例如S(共享)模式)封锁,只要进程间不互相干扰,它们就可以同时访问资源(通过锁转换)。这里有两个主要的与锁相关的队列:GRANTED和CONVERT。那些已经获得锁资源的进程放入GRANTED队列,正等待获取锁资源的进程则放入CONVERT队列。一旦获得了锁资源,该进程就会从CONVERT队列移至GRANTED队列。在系统中,不同类型的封锁有不同的目的,例如协调访问不同的文件、回滚段等。

封锁信息和其他DLM维护的结构被称为DLM数据库。DLM在所有参与的实例间按照冗余方式分布它的数据库,因此就避免了在节点发生故障时出现重要元数据丢失的情况。这也允许故障加速时进行锁重建,因为可以对不同节点的DLM结构的请求进行平衡,所以一般可以提高性能。

DLM主要由以下三个子构件构成。

●锁守护进程(lock daemon,LD):LD是DLM数据库的拥有者,它用于控制各种锁的请求(GRANTED和CONVERT请求),通知等待的进程封锁已经可用、管理超时和执行死锁检测。当一个进程以特定的模式请求封锁时,LD检查是否可将相应的锁授予该进程,如果可以,则可通过“获取异步系统捕获”(acquisition asynchronous system trap,AAST)通知客户进程。如果因为另一个进程(阻塞者)拥有不兼容的锁,则该锁无法授予进程,就通过“阻塞获取异步系统捕获”(blocking asynchronous system trap,BAST)对阻塞者发送一个信号。阻塞可能位于相同的节点(本地)或者位于不同的节点(远程)。当阻塞者收到暗示后,它就会尽可能快地释放锁。如果无法释放,就尽量降低锁模式的级别,这样新到的进程就不得不等待直到需要的锁可用为止(即处于CONVERT队列)。当两个进程都试图获取不兼容的锁,并且二者都不愿意回退/等待时,就会发生死锁。死锁是一种相对较少发生的情况,只发生在非PCM锁上。PCM锁不会发生死锁。LD以时间片轮转为基础,定期在每个节点上检查死锁。初始化死锁检测时,要将阻塞者(也是等待者)放入“搜索列表”。如果判定某进程处于死锁状态,就通知该进程。如果死锁仲裁超时,那么那个进程就会被移至搜索列表的尾部,这样就有机会处理其他的进程,其他潜在的死锁可以被检测到(这样就避免了只进行一个死锁仲裁)。

●锁监控器(lock monitor,LM):LM负责创建DLM数据库,并且恢复正在使用DLM的死锁进程(释放死锁进程申请的资源)。它为DLM数据库中的结构分配内存,为进程间的通信准备通道,允许参与节点交换锁和其他资源信息。LM也与连接管理器(connection manager,CM)协同工作,必要时恢复进程。当LM为DLM数据库分配完空间后,它在大多数情况下处于睡眠状态(除非被唤醒执行修复),然后定期被唤醒以搜索DLM进程表中的死锁进程。在特定的情况下,LM在所有节点间重新分布DLM资源。这些特定的情况包括新节点插入集群配置、存在的节点被去掉、LCK后台进程发生故障等。

●连接管理器(CM):当一个新节点被插入集群配置,或者去掉一个存在的节点时,都需要在DLM的CM中进行注册。CM与集群组服务(cluster group services,CGS)交互以跟踪节点状态,使数据库拥有所有参与节点的信息(CGS是由供应商提供的构件,与硬件/操作系统结合紧密)。CM通过虚电路完成节点之间的通信,这样就能确保节点之间可以相互通信。通信是基于虚电路上交换的“心跳”消息。这种消息可以保证节点处于运行状态。如果节点在指定的超时间隔内不响应,则系统将进行重新配置以忽略不响应的节点。同时还需要系统管理员的手工操作,确保节点平滑地退出集群配置。

这些子构件的功能作用域可能会根据所利用的DLM实施情况发生变化(与特定的Oracle或者特定的硬件供应商相关)。

除此之外,DLM还有一些要素值得考虑,如下。

1)DLM数据库

正如前面所讲的,DLM需要监控资源上的(封)锁、当前被授予的模式、哪些进程当前正等待这些锁被释放、等待进程当前正寻求什么锁模式,等等。所有这些信息被DLM维护在一个数据库中,该数据库由特定的资源结构构成,例如维护锁的分配/释放/转换信息的结构和由所有参与节点维护的目录树信息。这种信息存储处被称为DLM锁数据库(DLM lock database)。存放锁数据库的确切位置是变化的,这依赖于最常请求指定锁的节点位置。DLM通过将锁数据库复制到最常请求锁的节点上,建立节点之间的联系。刚开始时,当一个节点第一次请求时,要在该节点上创建必要的DLM结构。如果另一个节点请求不同的锁,那么要在这个节点上复制必要的结构,这样就避免了节点之间频繁交换与锁相关的信息,这些与锁相关的消息包括锁确认、锁模式改变、锁释放等。最初的结构(在第一个节点上)被定时刷新。随着越来越多的节点开始请求锁,资源会移植到最常请求锁的节点。实际上,节点数是有限的,所以锁数据库的移植不会太频繁。(www.chuimin.cn)

2)目录树

目录树是DLM进程内存的一部分。DLM进程内存维护DLM资源信息,以及拥有这些资源节点的信息。当节点请求某特定资源上的锁时,目录树要确定资源是否已被该节点拥有;否则,会被其他节点拥有。因为目录树是DLM数据库的一部分,它的一部分可以在所有节点间传播。资源名字使用哈希算法来决定哪个节点拥有目录树的相关部分(利用它们跟踪被请求的资源)。一旦节点被识别出来,封锁请求就被分配给该节点。

3)后台进程

除一般的后台进程如PMON、DBWR、SMON、LGWR和ARCH外,OPS至少应配置一个(封)锁进程,即LCKn进程。LCKn进程主要负责在当前节点/实例上管理锁(包括转换、分配和释放)。属于当前实例的锁请求被LCKn进程处理。某些锁请求被前台服务器进程(如事务锁和某些会话级锁)和后台进程(如由DBWR请求的介质恢复锁和由LGWR请求的SCN实例锁)自己处理。默认情况下,单一锁进程LCK0就会不够使用,可以根据需要启动其他锁进程(如从LCK1到LCK9)。在LCK0成为瓶颈的环境下,LCKn进程增加了恢复和启动时间。所有实例必须设置成使用相同个数的锁进程。

在Oracle 8中开始引入集成DLM的概念。DLM引入了LMON和LMD0两个新的后台进程来协调全局锁管理。当新的实例被启动(在以前的非参与节点上)或者存在的节点被关掉时,LMON会重新配置和重新分配全局锁。如果利用这些全局锁的服务器进程(或实例)突然意外终止,则LMON会清除并使这些全局锁无效。LMD0主要负责失败时恢复远程全局锁请求。

在DLM检查目录且将锁请求重新路由到远程节点后,初始化锁请求的节点就与远程节点上的LMD0进行协调,以获取锁。

一旦某个节点上的实例启动,它就可以获取各种DLM锁,这些锁主要划分为PCM(parallel cache management)锁和非PCM锁。PCM允许多个实例同时访问共享资源,允许一个节点访问位于另一个节点的缓冲区中的数据。PCM锁用于锁住数据库块,非PCM锁则用于锁住所有其他共享的DLM资源(如共享池中的数据文件和对象)。

PCM锁:启动时,所有PCM锁以NULL模式被请求。因为NULL模式不会与其他任何模式发生冲突,所以这些请求可以被满足。DLM就在局部内存中记录锁结构。DLM构建在最先启动实例的节点上,称为该节点“控制了”DLM资源。重新控制发生在锁数据库被移植到其他启动它们相应实例节点上的时候。每一个节点上的实例在初始化时可以获取的锁个数是由各种GC_*初始化参数决定。

非PCM锁:是指将原来非OPS的形态封锁在并行状态使用形态,在并行状态,多个实例的封锁呈现全局状态,这样就呈现为非PCM锁。

与非PCM锁相关的Oracle中的两种典型的锁是门闩锁和排队锁。门闩(latch)锁是复杂的细粒度串行化构件,用来控制对SGA(系统全局区)内部结构的访问。换句话说,门闩锁用来串行化对临界代码和内存组成部分的访问,防止多个进程执行相同的代码或对相同的内存结构同时写。门闩锁运行时的优先级很低,并且在很大程度上依赖于操作系统(OS)。

与门闩锁相似,排队(enqueue)锁也保护特定的结构。排队锁允许并管理多个进程对特定内存资源的并发访问。换句话说,除了依赖互斥策略,排队锁允许资源在多个级别共享。每个进程需要一个处于特定状态的排队锁,访问资源的级别由这个排队锁仲裁决定。

非PCM锁主要由全局排队锁构成。

下面简单讨论节点发生故障后是如何自动修复的。

发生故障的原因可能有多种,例如是由节点(构件)故障、网络故障或者实例故障造成的。在节点发生故障后,恢复需要发生在硬件/操作系统级,也需要发生在Oracle内部实例级。如果只有实例发生故障,就不需要硬件/操作系统级修复。

(1)节点(构件)故障和集群重组CM(连接管理器)。

可以通过定期在节点之间交换“心跳”消息来确保集群中的每个节点仍处于工作状态。如果发生心跳消息连续超时,那么就可检测到节点故障。连续超时意味着节点实际上已停止工作,而不是因为忙碌而无法响应心跳消息。一旦检测到节点故障,其连接就被标记为断开,需要重组集群以排除发生故障的节点。完成重组后,只有正常的节点处于当前的集群配置中。当故障节点被修复/替换后,CM会检测到新的节点。这时,需要再一次重组集群以插入新的节点。

(2)重建DLM数据库。

在集群重组时,必须重建DLM锁数据库。LM负责初始化重建过程。DLM数据库主要存放于每个实例的Cache中。一个或多个实例故障会引起一部分数据库丢失。幸存的实例可以帮助重新构造丢失的信息。

初始时,所有锁活动会被冻结,任何实例都不能获得新的锁。所有持久的PCM会变成无效并被释放,其中包括属于故障实例申请到的锁。

接下来,每个幸存的实例重新获取它的所有局部锁。属于远程进程的非局部锁被丢弃。DLM目录树被清空,并且基于新锁结构重建。

(3)实例修复。

实例修复类似于在非OPS配置启动故障修复的情况。唯一不同点在于,一个实例修复是由另一个(幸存)实例执行的。实例修复包含两个主要操作:恢复Cache一致性(即Cache修复)和恢复事务状态(即事务修复)。基本上,这包含将“脏”缓冲区写到磁盘上,即将所有提交的事务刷新到数据文件中,将没提交的事务除去。所有连接到故障实例的用户/应用进程需要切换到幸存实例(自动进行或重新建立连接)。终端用户/应用程序会看到与实例故障相关的错误消息。当一个幸存的实例试图锁住由故障实例中的(死)事务锁住的记录/关系时,或者当它试图在缓冲资源上获取已由(死)事务锁住的PCM锁时,就会通知它:已经发生节点故障。在重建DLM数据库期间,这些PCM锁就被声明为是不可靠的。检测到故障节点之上的SMON进程负责在故障节点上执行实例修复。检测到实例故障所需的时间主要依赖于不同节点间数据共享的程度。在任何情况下,SMON定期(每5分钟)唤醒并且进行多种一致性检查,其中之一就是检查实例故障(例如死亡的重做线程)。一旦SMON被激活,就初始化Cache和事务修复以清除属于故障实例的资源,并且使数据库处于一致的状态。

在Cache修复的过程中,要检查所有PCM锁的状态。(在DLM数据库重建过程中)所有被标记为不可靠的PCM锁都对应某些数据块。有一些锁模式的优先级低于并行读模式,这样可能是被故障实例进行过写操作。现在,写操作可能不会完全成功。相应地,修复从故障实例的重做线程的最后一个检查点对应的数据块开始。在实例向前滚动时,所有不可靠的锁被标记为无效并且被清除。通过警告日志的实例修复消息,可以找到Cache修复的证据。

当Cache修复完成后,所有属于故障实例的“脏”缓冲区被应用到相应的数据文件中。这包括完全提交的写操作和未提交的写操作。在事务修复过程中,所有未提交的写操作都会被回滚(undo),返回到一致状态。

2.检错和纠错

Oracle的并行Cache管理(PCM)算法重点强调数据访问过程中维护节点之间的联系。当一个节点需要更新某些数据块时,属于该节点的服务器进程就会将数据块读入自己的本地缓冲之中(假定这些数据块当前不在这个节点和其他节点的缓冲之中)。服务器进程会给后台LCKn进程发送消息,以获取数据块缓冲区对应的锁。封锁会持续下去,即使更新操作和随后的提交操作已经完成,节点仍然拥有锁并且数据块仍在该节点的本地缓冲之中。直到另外的节点通过DLM对这些数据块发出了请求,这些锁才会被释放。策略是,即使会增加内部节点间的流量,也要将数据块保留在本地缓冲区中,这主要是基于如下假设:节点重新使用最近访问过的数据块的概率大于另外节点使用这些数据块的概率,特别是当应用程序被很好地划分并且分布在不同的节点之上时更是如此。不过,有些节点访问这些相同数据块的概率也很大,尽管没有节点重用这些数据块的概率大。当另外一个节点需要对这些相同的数据块进行写操作时,该节点会向DLM提交一个请求,由DLM协调访问远程缓冲中的这些数据块。拥有这些数据块的节点被告知,远程节点希望访问这些数据块,DLM锁被释放,这些数据块被DBWR[13]刷新,写回磁盘。然后,DLM通告远程节点,远程节点之上的服务器进程将这些数据块读入自己的本地缓冲之中。