深入理解Oracle中的latch
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入理解Oracle中的latch相关的知识,希望对你有一定的参考价值。
深入理解Oracle中的latch
串行化 概述
串行化 - 数据库系统本身是一个多用户并发处理系统,在同一个时间点上,可能会有多个用户同时操作数据库, 多个用户同时在相同的物理位置上写数据时,不能发生互相覆盖的情况,这叫做串行化,串行化会降低系统的并发性,但这对于保护数据结构不被破坏来说则是必需的。在Oracle数据库中,通过闩锁(latch)和锁定(lock)来解决这两个问题。
闩锁和锁定既有相同点又有不同点。相同点在于它们都是用于实现串行化的资源。而不同点则在于闩锁(Latch)是一个低级别、轻量级的锁,获得和释放的速度很快,以类似于信号灯的方式实现。而锁定(Lock)则可能持续的时间很长,通过使用队列,按照先进先出的方式实现。也可以简单地理解为闩锁是微观领域的,而锁定则是宏观领域的。
注意 :latch是用于保护SGA区中共享数据结构的一种串行化锁定机制。它不仅仅用于buffer cache, 还用于shared pool以及log buffer等。
闩锁(latch)概述
Oracle数据库使用闩锁(latch)来管理SGA内存的分配和释放.Latch是用于保护SGA区中共享数据结构的一种串行化锁定机制。Latch的实现是与操作系统相关的,尤其和一个进程是否需要等待一个latch、需要等待多长时间有关。
Latch是一种能够极快地被获取和释放的锁,它通常用于保护描述buffer cache中block的数据结构。与每个latch相联系的还有一个清除过程,当持有latch的进程成为死进程时,该清除过程就会被调用。Latch还具有相关级别,用于防止死锁,一旦一个进程在某个级别上得到一个latch,它就不可能再获得等同或低于该级别的latch。
Latch 不会造成阻塞,只会导致等待。 阻塞是一种系统设计上的问题,等待是一种系统资源争用的问题。
SPIN与休眠
SPIN
在performance tuning的sg上tuning contention章里看到的,原文是这样的:Latch behavior differs on single and multiple CPU servers. On a single CPU server, a process requesting an in-use latch will release the CPU and sleep before trying the latch again. On multiple CPU servers, a process requesting an in-use latch will “spin” on the CPU a specific number of times before releasing the CPU and trying again. The number of spins the process will use is OS specific.
spin 就是一个进程独占cpu time,直到运行的结束。这个期间其他进程不能获得这个cpu的运行时间。对于单CPU来说没有spin概念。
比如数据缓存中的某个块要被读取,我们会获得这个块的 latch,这个过程叫做spin,另外一个进程恰好要修改这个块,他也要spin这个块,此时他必须等待,当前一个进程释放latch后才能spin住,然后修改,如果多个进程同时请求的话,他们之间将出现竞争,没有一个入队机制,一旦前面进程释放所定,后面的进程就蜂拥而上,没有先来后到的概念,并且这一切都发生的非常快,因为Latch的特点是快而短暂。
休眠
休眠意味着暂时的放弃CPU,进行上下文切换(context switch),这样CPU要保存当前进程运行时的一些状态信息,比如堆栈,信号量等数据结构,然后引入后续进程的状态信息,处理完后再切换回原来的进程状态,这个过程如果频繁的发生在一个高事务,高并发进程的处理系统里面,将是个很昂贵的资源消耗,所以Oracle选择了spin,让进程继续占有CPU,运行一些空指令,之后继续请求,继续spin,直到达到_spin_count值,这时会放弃CPU,进行短暂的休眠,再继续刚才的动作。初始状态下,一个进程会睡眠0.01秒。然后醒过来,并再次尝试获得latch。 进程一旦进入睡眠状态,则会抛出一个对应的等待事件,并记录在视图v$session_wait里,说明当前该进程正在等待的latch的类型等信息。
Latch的种类
愿意等待(Willing-To-Wait)
大部分的latch都属于这种类型(Willing-To-Wait)。这种类型的latch都是通过Test-And-Set的方式来实现的。
任何时候,只有一个进程可以访问内存中的某一个数据块,如果进程因为别的进程正占用块而无法获得Latch时,他会对CPU进行一次spin(旋转),时间非常的短暂,spin过后继续获取,不成功仍然spin,直到spin次数到达阀值限制(这个由隐含参数_spin_count指定),此时进程会停止spin,进行短期的休眠,休眠过后会继续刚才的动作,直到获取块上的Latch为止。进程休眠的时间也是存在算法的,他会随着spin次数而递增,以厘秒为单位,如1,1,2,2,4,4,8,8,。。。休眠的阀值限制由隐含参数_max_exponential_sleep控制,默认是2秒,如果当前进程已经占用了别的Latch,则他的休眠时间不会太长(过长会引起别的进程的Latch等待),此时的休眠最大时间有隐含参数_max_sleep_holding_latch决定,默认是4厘秒。这种时间限制的休眠又称为短期等待。
另外一种情况是长期等待锁存器(Latch Wait Posting),此时等待进程请求Latch不成功,进入休眠,他会向锁存器等待链表(Latch Wait List)压入一条信号,表示获取Latch的请求,当占用进程释放Latch时会检查Latch Wait List,向请求的进程传递一个信号,激活休眠的进程。Latch Wait List是在SGA区维护的一个进程列表,他也需要Latch来保证其正常运行,默认情况下share pool latch和library cache latch是采用这个机制。
如果将隐含参数_latch_wait_posting设置为2,则所有Latch都采用这种等待方式,使用这种方式能够比较精确的唤醒某个等待的进程,但维护Latch Wait List需要系统资源,并且对Latch Wait List上Latch的竞争也可能出现瓶颈。
如果一个进程请求,旋转,休眠Latch用了很长时间,他会通知PMON进程,查看Latch的占用进程是否已经意外终止或死亡,如果是则PMON会清除释放占用的Latch资源。
总之, Latch获取的流程:请求-SPIN-休眠-请求-SPIN-休眠 ... ... 占用。
不等待(No-Wait)
这种类型的latch比较少,对于这种类型的latch来说,都会有很多个可用的latch。当一个进程请求其中的一个latch时,会以no-wait模式开始请求。如果所请求的latch不可用,则进程不会等待,而是立刻请求另外一个latch。只有当所有的latch都不能获得时,才会进入等待。
latch的获取过程可以用下图来概括
Latch和Lock的区别
Latch是对内存数据结构提供互斥访问的一种机制,而Lock是以不同的模式来套取共享资源对象,各个模式间存在着兼容或排斥,从这点看出,Latch 的访问,包括查询也是互斥的,任何时候,只能有一个进程能pin住内存的某一块,幸好这个过程是相当的短暂,否则系统性能将没的保障
Latch只作用于内存中,他只能被当前实例访问,而Lock作用于数据库对象,在RAC体系中实例间允许Lock检测与访问
Latch是瞬间的占用,释放,Lock的释放需要等到事务正确的结束,他占用的时间长短由事务大小决定
Latch是非入队的,而Lock是入队的
Latch不存在死锁,而Lock中存在。
Latch的cleanup
在latch的使用过程中,可能会出现一些异常,而导致有些latch被异常占有得不到释放,这样就会有问题了,别的进程过来请求不到。出现这样的异常pmon进程会跟进处理,对于其处理的流程来说,最重要的莫过于将没有提交的事物回滚,那么就需要latch支持恢复,那么latch在开始操作前会先写一些信息去latch的恢复区。Pmon 3秒钟会自动运行一下,但是这也是很长的一段时间了,所以在进程在请求一个latch失败多次之后,会post pmon进程去check一下占有这个latch的process是不是正常。
Latch的level
Latch的级别分为0~14,共15个级别,0级最低,14最高。如果两个latch之间有联系,只能请求level更高的latch。原因如下:
如果a进程占有一个level 为5的latch,它去请求一个level为3的latch,而进程b,占有这个level为3的latch,又去请求那个level 为5的latch,这样会有什么问题呢?因为它是可以去spin的,又是可以去sleep的,sleep之后还是继续重复,那就永远没有完没有了了。所以呢,level的request是有level顺序的,不能随便的请求,只能由低级的latch去请求高级的latch。
如果经常a一定要申请进程b的latch的话,只能放弃原有latch level5为的latch重新对b进程的latch进行申请。
Latch资源争用
如果latch资源被争用,通常都会表现为CPU资源使用过高。
而反过来说,如果我们发现CPU资源很紧张,利用率总是在90%以上,甚至总是在100%,其主要原因有以下几点。
1、SQL语句 如果没有使用绑定变量,很容易造成频繁读写shared pool里的内存块,如果存在大量的SQL被反复分析,就会造成很大的Latch争用和长时间的等待, 从而导致与解析SQL相关的共享池中的Latch争用 。与 shared pool共享池相关的latch有Library Cache Latch 和Shared Pool Latch。如果数据库出现了上述latch的争用,则有必要检查下是否有正确使用绑定变量
2、 访问频率非常高的数据块被称为热快(Hot Block),当很多用户一起去访问某几个数据块时,就会导致 数据缓冲池Latch 争用,最常见的latch争用有 :buffer busy waits和cache buffer chain
Cache buffer chian:
当一个会话需要去访问一个内存块时,它首先要去一个像链表一样的结构中去搜索这个数据块是否在内存中,当会话访问这个链表的时候需要获得一个Latch,如果获取失败,将会产生Latch cache buffer chain 等待,导致这个等待的原因是访问相同的数据块的会话太多或者这个列表太长(如果读到内存中的数据太多,需要管理数据块的hash列表就会很长,这样会话扫描列表的时间就会增加,持有chache buffer chain latch的时间就会变长,其他会话获得这个Latch的机会就会降低,等待就会增加)。
Buffer busy waits:
当一个会话需要访问一个数据块,而这个数据块正在被另一个用户从磁盘读取到内存中或者这个数据块正在被另一个会话修改时,当前的会话就需要等待,就会产生一个buffer busy waits等待。
产生这些Latch争用的直接原因是太多的会话去访问相同的数据块导致热快问题,造成热快的原因可能是数据库设置导致或者重复执行的SQL 频繁访问一些相同的数据块导致。热块产生的原因不尽相同,按照数据块的类型,可以分成以下几种热块类型,不同热块类型处理的方式都是不同的:表数据块、索引数据块、索引根数据块和文件头数据块。
3、另外也有一些latch等待与bug有关,应当关注Metalink相关bug的公布及补丁的发布。为何latch的争用会引起CPU使用率较高呢?
其实很容易理解,比如进程A持有latch,此时进程B也需要持有相关latch,但是没有获得,这时候进程B就需要进行spin,如果类似进程B的进程较多的话,对CPU进行spin的进程就会较多,表现也就是CPU利用率非常高,但是吞吐量却很低,典型的“出工不出活”
本文出自 “linux相关技术” 博客,谢绝转载!
以上是关于深入理解Oracle中的latch的主要内容,如果未能解决你的问题,请参考以下文章