如果经过一个完整的旋转,这个Latch仍然不可以用,那个请求进程就会首先放弃对cpu的请求而去sleep。一个sleep就对应一个Latch free的等待事件。开始,这个sleep时间会是一个厘秒(one centisecond)。这个时间会以双指数的增长方式去增加直到参数_MAX_EXPONENTIAL_SLEEP所规定的,一般是2秒。通常调整_SPIN_COUNT这个值没有什么大的作用,过度的latch竞争通常都是差的程序设计的结果。此外就是我前面提到的_SPIN_COUNT只对多CPU的系统有用。这个参数只会在其他tunning方法已经用完,而又有足够的CPU带宽时,才考虑增加这个值。
通常latch只能被短暂的拥有,成功的spin能够节省CPU时间,当然这个只对多CPU环境有意义。这里有人会问为什么要SPIN,为什么不直接休眠等待?这里要明白休眠意味着什么,他意味着暂时的放弃CPU,进行上下文切换(context switch),这样CPU要保存当前进程运行时的一些状态信息,比如堆栈,信号量等数据结构,然后引入后续进程的状态信息,处理完后再切换回原来的进程状态,这个过程如果频繁的发生在一个高事务,高并发进程的处理系统里面,将是个很昂贵的资源消耗,所以他选择了spin,让进程继续占有CPU,运行一些空指令,之后继续请求,继续spin,直到达到_spin_count值,这时会放弃CPU,进行短暂的休眠,再继续刚才的动作,Oracle软件就是这么设计的。
Latch的获取,可以说遵从下面的规律Fast get –spin—sleep—spin—sleep—spin—sleep--,所以有两种情况,其中一个是Latch能以no-wait(no spin or sleep)的模式去获取。如有很多的redo copy latches,如果一个进程需要这个latch,它首先是以no-wait模式去请求。如果一个进程第一次获取这些子latch中的任何一个失败,它会立即使用no-wait模式询问下一个。只有当采用no-wait模式试图获取所有的子latch都失败以后,才会转而采用willing-to-wait模式。另外一个是借助level rule,每个latch都有自己的level。为了防止死锁,请求者只能请求level比现在拥有者高的latch。如果这个latch的请求是一个低的level,那么其中的一个方法就是释放现在被占有的latch,然后请求者以一个适当的顺序去获取。另外一种就是willing-to-wait模式,大多数latch都是短等待latch,所以,进程请求latch时不会等待太长的时间。Oracle进程请求latch失败而导致进入睡眠状态,每次睡眠时间按双指数队列增长,比如睡眠时间可能像下面的队列一样:1,1,2,2,4,4,8,8,16,16,32,32,64,64(厘秒)……,最长的睡眠时间由隐含参数_max_ exponential_sleep,默认2秒。但是如果一个进程当前已经持有其他的latch,则最长睡眠时间会减少为_max_sleep_holding_latch,默认值4厘秒。这样,如果一个进程已经持有latch,就不允许睡眠太长的时间,否则可能会使其他等待该进程所持有的latch的进程的等待时间过长。
如果请求该latch的进程进入睡眠状态,需要其他进程来唤醒,这会产生一个latch wait posting等待事件,该行为由隐含参数_latch_wait_posting控制。在oracle8i,只有2个长等待latch,_latch_wait_posting参数从oracle9i起已经废弃,使用latch wait posting的latch的统计信息被记录在waiters_woken列中,这个数值就等于唤醒Post的次数。这个只是对于长等待latch而言。这里也要引入一个概念锁存器等待链表latch wait list。Latch的释放机制需要唤醒第一个为次latch而等待进程。比如说library chace、shared pool、library cache load lock。那些为此而等待进程是由一个串连waiter的链表(锁存器等待链表latch wait list)所保护。如果占有latch的进程死了,PMON进程会清理该进程和释放latch。如果这个占有者还活着,那就存在latch争用的情况或者操作系统调度有问题。
----------------------------------------------待续-----------------------------------------------------
星期四, 五月 24, 2007
Oracle Latch internals随笔一
仅以本文来总结和复习Oracle Interals,并结合实际工作中的经验,让自己对Oracle的Latch有一个更清楚的认识。
首先,我们要知道什么是Latch,用Latch的目的是什么。下面我们就来探讨下Latch的相关概念及内部信息。Latch是用来保护内存资源的一个轻量级的锁。主要目的有两点:
1、 串行化访问(To serialize access),保护SGA中的数据结构和共享内存的分配。
2、 串行化执行(To serialize execution),防止同时执行特定重要代码,防止数据结构的损坏.
借用排他性的Latch,进程能够阻止其他进程对有这个Latch保护的数据结构的读和写。由此看出Latch对内存数据结构提供一种互斥访问机制。在没有一致性读机制的情况下,先期读取者会阻止修改者。在没有Shared Latch在相关平台的情况下,先期读取者也会阻止其他访问者。如果Latch的持有者进程意外终止,那么会有一个相关的清除机制会处理这个情况。通常这个工作是有PMON进程来restore和clean up。而其中关于这个Latch的undo information一般典型的存在SGA状态对象(SGA state objects)中。常见的Latch一般有shared pool latch、session allocation latch(负责保护在variable SGA 中的session state object的分配)、cache buffers lru chain latch(负责保护在LRU lists中Buffer headerd 分配和移动)。
Oracle server允许对象同时以共享的模式区使用队列(equeue)。而Latch用来保护大的数据结构或者被高频率访问的结构,由此Latch都是排它性的,并且存在时间很短的特点,对性能和并发用户的可用性的影响降到最低。在请求enqueue时,如果一个进程没有被授权,那一般是因为请求模式和现有的模式不够兼容,O/S就会把请求进程放在一个FIFO模式的等待队列(wait queue)中。而对于Latch的请求,Latch waitesr一直按顺序提交请求。
特殊情况下,Oracle server请求在一个大数据结构(large stucture)上的Latch,在一个相对长的时间内为了安全访问以及锁定小子数据结构(smaller sub-structure)时,需要利用复杂的像enqueues的锁机制。比如,在更新一个row时,Oracle server会得到一个cache buffers chains latch去搜索hash chain,此过程主要是为了在data buffer中找到那个data block。然后pins住这个block,然后释放cache buffers chains latch。然后Oracle server会lock这个数据块中的row,修改行,然后unpins这个block。到目前为止,这个row仍然被lock in exlusive mode至到事务结束。Lock row不会影响block中的其他数据和在cahe中的其他buffers。
虽然Latch的使用是在操作系统级别,但是平常是作为一个内存位(single memory location)去操作。Latch free时为0,Latch not free时为一个非0。这个内存位经常增加到32个字节,为了避免在硬件级别上的Cache line竞争。Latch被设计成一个fast和inexpensive的锁。Latch真实操作依靠于操作系统。对于shared latches不是很广泛的被使用。这种类型的锁主要是用于高级队列代码(Advance Queuing code)。存在一种机制可以让进程什么时候,以如何方式获得Latch,而不发生死锁。
Latch可以是独立Latch(solitary Latch),也可以是Latch集(Latch set)。Latch set有父Latch和多个子Latch组成。独立Latch和父Latch是静态分配的,而子Latch是动态分配的。父Latch和子Latches有相同的名字。父Latch做为控制Latch(master latches)。Latch具有级别的特性(Levels),利用这个优先级可以避免死锁。父Latch在数量上是固定的,应该在相关代码中所定义。从Oracle9R2开始,有了不同类型的父Latch,但每个类型只有一个父latch。子Latch是依据相关参数(比如_CPU_COUNT)设定或者默认值动态分配的。父Latch一般只作为聚合统计之用,但library cache是个例外。如Solitary Latches:shared pool,redo allocation;PAR Latches:cache buffers lru chain、cache buffers chains;PR2 Latches:library cache。当一个进程请求no-wait模式的latch时,该latch的优先级编号必须和它当前已经持有的latch的优先级编号相同。当一个进程请求willing-to-wait模式的latch时,该latch的优先级编号必须比它当前已经持有的latch的优先级编号要大。
Latch是在操作系统中以某种方式来执行。如果一个latch真在被占用,那边requestor spins and tries agin,in a loop up to _SPIN_COUNT number of time。for single CPU systems _SPIN_COUNT=1。如果在一个单cpu的环境下,一个进程持有一个Latch,但它没有释放这个latch,那就没有必要去spin了。否则,当cpu的数量大于1,那么_SPIN_COUNT的默认值是2000。
-------------------------------------------------待续-----------------------------------------------------------------------
首先,我们要知道什么是Latch,用Latch的目的是什么。下面我们就来探讨下Latch的相关概念及内部信息。Latch是用来保护内存资源的一个轻量级的锁。主要目的有两点:
1、 串行化访问(To serialize access),保护SGA中的数据结构和共享内存的分配。
2、 串行化执行(To serialize execution),防止同时执行特定重要代码,防止数据结构的损坏.
借用排他性的Latch,进程能够阻止其他进程对有这个Latch保护的数据结构的读和写。由此看出Latch对内存数据结构提供一种互斥访问机制。在没有一致性读机制的情况下,先期读取者会阻止修改者。在没有Shared Latch在相关平台的情况下,先期读取者也会阻止其他访问者。如果Latch的持有者进程意外终止,那么会有一个相关的清除机制会处理这个情况。通常这个工作是有PMON进程来restore和clean up。而其中关于这个Latch的undo information一般典型的存在SGA状态对象(SGA state objects)中。常见的Latch一般有shared pool latch、session allocation latch(负责保护在variable SGA 中的session state object的分配)、cache buffers lru chain latch(负责保护在LRU lists中Buffer headerd 分配和移动)。
Oracle server允许对象同时以共享的模式区使用队列(equeue)。而Latch用来保护大的数据结构或者被高频率访问的结构,由此Latch都是排它性的,并且存在时间很短的特点,对性能和并发用户的可用性的影响降到最低。在请求enqueue时,如果一个进程没有被授权,那一般是因为请求模式和现有的模式不够兼容,O/S就会把请求进程放在一个FIFO模式的等待队列(wait queue)中。而对于Latch的请求,Latch waitesr一直按顺序提交请求。
特殊情况下,Oracle server请求在一个大数据结构(large stucture)上的Latch,在一个相对长的时间内为了安全访问以及锁定小子数据结构(smaller sub-structure)时,需要利用复杂的像enqueues的锁机制。比如,在更新一个row时,Oracle server会得到一个cache buffers chains latch去搜索hash chain,此过程主要是为了在data buffer中找到那个data block。然后pins住这个block,然后释放cache buffers chains latch。然后Oracle server会lock这个数据块中的row,修改行,然后unpins这个block。到目前为止,这个row仍然被lock in exlusive mode至到事务结束。Lock row不会影响block中的其他数据和在cahe中的其他buffers。
虽然Latch的使用是在操作系统级别,但是平常是作为一个内存位(single memory location)去操作。Latch free时为0,Latch not free时为一个非0。这个内存位经常增加到32个字节,为了避免在硬件级别上的Cache line竞争。Latch被设计成一个fast和inexpensive的锁。Latch真实操作依靠于操作系统。对于shared latches不是很广泛的被使用。这种类型的锁主要是用于高级队列代码(Advance Queuing code)。存在一种机制可以让进程什么时候,以如何方式获得Latch,而不发生死锁。
Latch可以是独立Latch(solitary Latch),也可以是Latch集(Latch set)。Latch set有父Latch和多个子Latch组成。独立Latch和父Latch是静态分配的,而子Latch是动态分配的。父Latch和子Latches有相同的名字。父Latch做为控制Latch(master latches)。Latch具有级别的特性(Levels),利用这个优先级可以避免死锁。父Latch在数量上是固定的,应该在相关代码中所定义。从Oracle9R2开始,有了不同类型的父Latch,但每个类型只有一个父latch。子Latch是依据相关参数(比如_CPU_COUNT)设定或者默认值动态分配的。父Latch一般只作为聚合统计之用,但library cache是个例外。如Solitary Latches:shared pool,redo allocation;PAR Latches:cache buffers lru chain、cache buffers chains;PR2 Latches:library cache。当一个进程请求no-wait模式的latch时,该latch的优先级编号必须和它当前已经持有的latch的优先级编号相同。当一个进程请求willing-to-wait模式的latch时,该latch的优先级编号必须比它当前已经持有的latch的优先级编号要大。
Latch是在操作系统中以某种方式来执行。如果一个latch真在被占用,那边requestor spins and tries agin,in a loop up to _SPIN_COUNT number of time。for single CPU systems _SPIN_COUNT=1。如果在一个单cpu的环境下,一个进程持有一个Latch,但它没有释放这个latch,那就没有必要去spin了。否则,当cpu的数量大于1,那么_SPIN_COUNT的默认值是2000。
-------------------------------------------------待续-----------------------------------------------------------------------
订阅:
评论 (Atom)