RAC的消息传递

Oracle Cache Fusion使用消息传递实现系统的锁定功能。消息传递用于实例内通信(在同一节点上的同一实例的进程之间)也用于实例间通信(在其他节点上的进程之间)。

假设现在实例R需要来自H实例的块,并且资源锁由M实例管理。

请求者实例R向主节点M发送消息。这是一条关键消息,因此使用直接发送。传输协议返回确认(未示出)。

主节点M发送命令以将资源转发到保持实例H.这也是直接发送。

保持实例H将资源发送到请求实例R.这是一个内存复制(memcpy)消息,资源被接收到其目标内存中。

请求者实例R向主节点M发送对资源消息的确认。该消息对于响应并不重要,因此它被发送Deferred;



消息分类

为了传达锁请求的状态,GES使用两种类型的申请消息acquisition AST(AST)和Blocking AST阻塞消息。

AST由LMD或LMS提供给已提交锁定请求的进程。当进程请求锁定资源时,GES发送acquisition AST以通知当前拥有该资源上不兼容锁模式的进程。收到通知后,锁的所有者可以放弃它们以允许请求者访问。LMS向拥有锁并且与转换锁请求有冲突的进程发送BAST。

当获得锁定时,发送acquisition AST以告知请求者它现在拥有锁。要确定请求者是否已发送blocking AST或阻止程序(或锁的所有者)是否已发送acquisition AST,可以查询视图GV$LOCK_ELEMENT或X$LE并检查指定列MODE_HELD, RELEASING, or ACQUIRING are non-zero。

消息缓冲区

任何发送方或接收方在发送或接收消息之前都会分配消息缓冲区。消息缓冲区一般有两种类型:KJCCMSG_T_REGULAR和  KJCCMSG_T_BATCH。

KJCCMSG_T_BATCH主要用于reconfiguration或remastering,或者在缓存融合中的数据块被传送之后。此外正常情况下Oracle默认有三种消息池:

• REGULAR:初始缓存数 =进程数* 2 + 2 * 10 + 10 + 20

• BATCH:初始缓存数  =进程数* 2 + 2 * 10 + 10 + 20

• RESERVE:初始缓存数 = min(2 *进程数,1000)

注意:

如果REGULAR池耗尽,则从共享池申请更多的内存。

消息缓冲区队列

多个队列持有的消息缓冲区都是来自SGA消息池(如REGULAR,BATCH和RESERVE池)。这样设计的目的是为了方便恢复消息缓冲区。

每个进程都有OutstandingQueue,FreeMsgQueue和PendingSendQueue。每个实例都有SendQueue和MsgPool。此外Oracle设计了一个阈值可以触发进程开始将可用的可用消息缓冲区缓存释放回共享消息池。



消息死锁

在Cache Fusion过程中消息传递也可能出现死锁情况。如果进程A正在等待发送消息以获取锁定,并且还有另一个进程B等待进程A持有的锁定。这个时候其实进程A将不会checkBAST,因此进程A不会看到它正在阻止其他进程。如果许多进程试图发送消息并且没有进程正在读取消息以释放消息缓冲区空间,则可能出现死锁情况。

跟接口类似,消息传递协议固定部分端口。消息通常少于128个字节,消息缓冲区的数量通常取决于锁或资源的数量。基本上锁或资源越多,流量越高。在Oracle8中,消息缓冲区的数量取决于资源的数量; 在Oracle7中,数量取决于锁的数量。

消息流量控制器(TRFC)

为了防止过多的申请消息导致资源持有者发送的申请无法被处理引起的消息死锁。Oracle引入了消息流量控制器(TRFC),它用于控制发送方发送请求的频率,在网络拥塞的情况下使发送方的请求暂停或者排队等待发送。用这种方式来控制集群中所有节点之间的DLM流量。而整个流量控制器的核心就是“Tickets”。

消息流量控制器 Tickets

Oracle RAC使用流量控制来确保远程接收端(LMD或LMS)具有恰当充足的buffer的来处理新消息。为了防止接收端用完网络缓冲区空间,发送端会使用latch进行控制,这样发送端的新请求会在进行等待排队。而我们的 “Tickets”用于确定接收端网络缓冲区的可用空间。

所有发送端想要发送消息前需要请求ticket池获得tickets,然后才能开始自己的发送任务。并且消息序列号会附加到发送节点和接收节点的发送的每条消息。根据远程接收端反馈的消息,接收端(LMS或LMD)将使用过的ticket释放回池中。

可用Tickets的最大数量是通过基于网络发送缓冲区大小的函数计算得出的。

假设现在没有可用的ticket,那么发送端就会缓存该消息,LMD或LMS发送关于tickes可用性的消息。节点依赖于从远程节点返回的消息以释放tickes以供重用。在大多数情况下,这是有效的,因为大多数客户端请求最终会ACK或ND。但是,在一些非常具体和罕见的情况下,这可能也会出现问题。例如,如果应用程序在短时间内进行大量异步阻塞转换请求,则会出现请求在一段时间内没有回复的情况。要强制远程节点的消息回复,则需要请向远程节点发送一个空的请求,强制让远程节点发回一个空的ACK。因此,如果可用ticket下降得太多,则需要远程节点发送空请求。



假设开始时,可用票证的数量为500.发送一条消息将消耗一张ticket。每个节点均会为每个通信伙伴维护多个计数器。

AvailBuf:可用于接收新消息的缓冲区数。

RecMsg:收到的消息数量,这里的消息类型并包括TEST,NULL-REQ或NULL-ACK。

AvailMsg:收到的消息数(所有类型)


伪代码:


if AvailBuf >= AvailMsg (if there are sufficient buffers) then AckTickets = AvailMsg
else if RecMsg == AvailMsg (no NULL-REQUEST yet)
then AckTickets = AvailBuf
else if AvailMsg - RecMsg > AvailBuf (too many NULL-REQUEST)
then AckTickets = 0
else AckTickets = AvailBuf – (AvailMsg - RecMsg)
Node 2 sends ACK tickets to node 1 to replenish the number of available tickets and decrement AvailMsg, RecMsg, and AvailBuf with ACK tickets.
For more details, refer to kjcts_sndmsg, kjctr_updatetkt, kjctr_collecttkt, and kjctcnrs (null request sent).


节点2向节点1发送ACK tickets以补充可用tickets的数量并减少AvailMsg,RecMsg和AvailBuf。


消息流控制统计信息

一般情况下消息流控制统计信息可以使用视图V$SYSSTAT和V$DLM_MISC(本地实例消息的统计信息)

• gcs messages sent:发送的PCM消息数

• ges messages sent:发送的非PCM消息数






沃趣科技,让客户用上更好的数据库技术!