ITPub博客

首页 > 数据库 > 数据库开发技术 > 高级OWI之Latch(闩锁)

高级OWI之Latch(闩锁)

原创 数据库开发技术 作者:lukeunique 时间:2017-08-06 19:29:00 0 删除 编辑

前言

最近在读韩国的Oracle ACE赵东郁(Dion Cho)的《高级OWI与Oracle性能调整》一书,书中介绍了Oracle等待事件以及调优相关内容,虽然是基于10g和以前版本写的,但其知识的深度和系统化程度,对最新12c版本依然有非常高的参考价值。 
我将在以后的一系列文章中介绍阅读该书过程中的所知、所得并适当地结合最新版本内容进行延伸。

本文主要介绍高级OWI基础的Latch(闩锁)相关内容,关于Enqueue(排队)的内容可参考前一篇文章:

高级OWI之Enqueue(排队)

Latch概要

关于Latch的概念,我们可以通过下面官方在线文档的描述有一个总体的印象:

Database Concepts 12.2

http://t.cn/R9bWL4H

Latches

A latch is a simple, low-level serialization mechanism that coordinates multiuser access to shared data structures, objects, and files.


Latches protect shared memory resources from corruption when accessed by multiple processes. 

Specifically, latches protect data structures from the following situations:


Concurrent modification by multiple sessions

Being read by one session while being modified by another session

Deallocation (aging out) of memory while being accessed


Typically, a single latch protects multiple objects in the SGA.

...

Unlike enqueue latches such as row locks, latches do not permit sessions to queue. 

...

Typically, an Oracle process acquires a latch for an extremely short time while manipulating or looking at a data structure. 

...

An increase in latching means a decrease in concurrency. 


通过上面的描述,我们可以知道Latch和ENQUEUE类似,也是用于保护多个进程(会话)对特定共享资源的访问;只不过Latch保护资源是SGA中的共享数据结构和共享内存的分配;另外Latch还有以下的特点:

・高速并且低Cost

・获得过程是原子性(atomic)的操作,通过OS的test-and-set、compare-and-swap等命令实现;相对于Enqueue的获取过程(检索资源构造体、分配锁、链接锁资源等),Latch的获得不需要其他机制来保护。

・获取Latch时没有排队机制(注:9i以后的版本中,很多Latch已经实现了和ENQUEUE一样的排队机制,保证FIFO。)


Latch的分类

根据一个实例中存在的相同类型Latch的个数,可以分为独立Latch (solitary latch)和父/子 Latch(Family latch)。

・独立Latch(solitary latch)是指在一个实例中只存在一个的Latch。

・父/子Latch(Family latch)是指包括有一个父latch 和多个(>=1)属于父Latch的子Latch的组合,父/子Latch的名称相同。


例如,我们在Enqueue工作机制中介绍的保护共通空闲列表的Latch:enqueue,在整个实例中只有一个,所以它是一个独立Latch;而保护相关Hash Buckets的Latch:enqueue hash chain,虽然名字都叫Latch:enqueue hash chain(同一个父Latch),但是却会有保护不同的Hash Buckets的多个子Latch。

之所以有时定义多个子latch,是为了减少对同一latch的竞争。例如当不同进程访问不同Buckets时,由多个子latch保护时完全可以互不干扰;如果只有一个Latch保护所有的Buckets时,就会发生竞争。

随着数据库版本的不同独立Latch和父/子Latch(Family latch)并不是一定的,也有可能旧的版本上独立Latch,在新版本会变成父/子Latch类型,例如latch:shared pool。

Latch工作机制

Latch的等级(Level)

对于Latch,没有像Enqueue一样的死锁检出机制,但是Latch通过基于Latch等级(Level)的获取顺序机制来防止死锁的发生。

Oracle对每一个Latch预先赋予一个等级,并且子Latch和父Latch具有相同的等级。 
对于各个Latch的等级可以通过查询V$LATCH的LEVEL#列来获得:

例(12.2.0.1):

SQL> col NAME format a30

SQL> set pagesize 2000

SQL> select NAME,LEVEL#,LATCH# from V$LATCH order by LEVEL#;


NAME                               LEVEL#     LATCH#

--------------------------------  ---------- ----------

STREAMS: txn btree                      0        679

... 

resmgr:resource group CPU method       15        563

PDB Hash Table Latch                   16        892


896 rows selected.


通过上面输出,我们可以看到在12.2环境中一共有896种Latch,并且等级可以分为0~16. 
通常来讲,拥有一个以上Latch的进程,只能获得比最后一次获得的Latch等级更高的Latch。


Latch的模式(MODE)

Latch基本上使用独占(Exclusive)模式,即大多数Latch都只有持有和不持有两种状态;但是少部分Latch如’cache buffers chains’ latch在某些场景下可能是共享(Shared)模式的。

另外,大多数的latch和一般Enqueue一样也拥有等待队列和持有队列,不过Latch的排队机制相对简单,这里暂不作详述。

Latch的获取(Acquisition)

Latch的获取(Acquisition)一般有no-wait 和willing-to-wait两种模式。

在no-wait模式下,某进程对于某Latch的获得只会尝试一次,一般不管是否成功都会迅速地返回结果给进程。

在willing-to-wait模式下,某进程如果由于其他进程持有相同Latch等原因而导致不能获得Latch时,会进行SPIN操作,即不释放CPU资源而不断地尝试去重新获得Latch,直到等到获取到Latch为止,这就好像是要进某房间进不去时而不断地再敲门一样; 
当然这个循环也不是无限次的,否则可能导致由于SPIN而引起的CPU过高而使资源耗尽;获取Latch SPIN的循环上限次数由隐含参数_spin_count来控制;如果达到了循环上限次数(_spin_count)还没有获得Latch,该进程则会释放CPU资源而进入睡眠(Sleep状态)。

※关于隐含参数_spin_count:

只有一个CPU的系统,默认_spin_count=1;
CPU数>1的系统,_spin_count=2000;


也许有人会好奇,为什么在willing-to-wait模式下获取Latch失败后不马上进入睡眠而要进行自旋(SPIN)?SPIN会不会更消耗CPU?

其实这主要基于两方面的考虑:1.因为Latch的获取和释放都是轻量级操作,所以通常情况下其他进程可能会很快释放Latch。2.如果进程进入睡眠,在OS层会发生Context Swithing,可能消耗比自旋(SPIN)更多的CPU;这就像是你拿了一堆文件去某会议室而没有应答时,你选择不断地敲门,还是选择把文件放回座位休息一会再去敲门一样,有时把文件放回座位可能更消耗体力。

no-wait模式


一般以no-wait模式获取Latch的场景主要包括以下2种情况:

1.获取父/子Latch(Family latch)中的子latch有多个候选时。

如果在多个子latch中只要获得其中一个就能够满足进程需要的情况下(如Latch:redo copy、Latch:cache buffers lru chain),Oracle会尝试以no-wait模式依次对各个子Latch进行获取尝试,只要要一次成功即可; 
如果通过这种方法一个子Latch都没有成功获取的话,进程则会再尝试以willing-to-wait模式获取Latch。

2.获取比当前拥有Latch等级(Level)低或相同Latch时

根据前面的介绍我们知道为了防止死锁的发生,通常来讲,拥有一个以上Latch的进程,只能获得比最后一次获得的Latch等级更高的Latch。 
如果想获得比比当前拥有Latch等级(Level)低或相同Latch时,需要先把已经获得的等级(Level)较高的Latch先释放掉。为了能够节约释放latch的时间,Oracle会尝试以no-wait模式获得Latch,如果获取失败,则会释放已经持有的、比请求的Latch等级高的Latch,然后按照正常的基于Latch等级(Level)的获取顺序进行willing-to-wait模式获取Latch。

一个简要的no-wait获取流程可以参考下图:


willing-to-wait模式

如前面所述在willing-to-wait模式下,某进程如果由于其他进程持有相同Latch等原因而导致不能获得Latch时,在多CPU情况下会发生自旋(SPIN)操作,如果达到了循环上限次数(_spin_count)还没有获得Latch,该进程则会释放CPU资源而进入睡眠(Sleep状态)。(注:系统只有一个CPU的情况下不会发生SPIN)

对于睡眠唤醒条件,主要有2种:

1.自身的超时机制(exponential backoff方式)


当进程睡眠时间超时时,会自己醒来,让后重新尝试获取Latch。

关于睡眠超时时间由一个称为指数退让算法(exponential backoff Sleep)决定,睡眠时间会从1/100秒开始,进程每一次进入睡眠后睡眠的超时时间将加倍。即一个进程进入睡眠次数越多,睡眠时间就越长。


2.依赖其他进程唤醒(wait/post方式)


在进程睡眠时,会把自己登记到latch的等待列表上;持有Latch的进程在释放Latch时会通知latch的等待列表上排在最前面的进程。


一个简要的willing-to-wait获取流程可以参考下图:

其他

9i版本开始基本所有的Latch都使用wait/post方式。

比较特殊的是latch :process allocation,是在进程建立前需要获得的Latch,所以无法使用wait/post方式。

对于PMON进程,由于其需要检测已获得Latch但异常结束的进程并进行清除操作(CleanUP),所以也使用exponential backoff方式。

MORE…

也许很多人知道有个俄国人叫Andrey Nikolaev对Latch和Mutex等研究的非常深,有兴趣的可以参考~~

Latch, mutex and beyond
https://andreynikolaev.wordpress.com/
Latch internals  (注意下面2个链接的PDF较大)
http://t.cn/R9bWQjB
andrey_nikolaev_latch_internals_2012_for_ruoug.pdf

New features of Latches and Mutexes in Oracle 12c.
http://t.cn/R9bjH6q
latches_and_mutexes_in_oracle_12c.pdf


TeacherWhat:

用碎片化的时间,一点一滴地学习一套系统化的知识。



原文作者:SQL和数据库技术;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2017-07-21

  • 博文量
    107
  • 访问量
    63607