【锁】Latch、lock、 pin的区别
我之前写过的几篇锁的文章:
【锁】Oracle锁系列: http://blog.itpub.net/26736162/viewspace-2128896/
【锁】Oracle死锁(DeadLock)的分类及其模拟:http://blog.itpub.net/26736162/viewspace-2127247/
【故障处理】队列等待之TX - allocate ITL entry引起的死锁处理: http://blog.itpub.net/26736162/viewspace-2124771/
Latch是Oracle提供的轻量级锁,它用于快速,短时间的锁定资源,防止多个并发进程同时修改访问某个共享资源,它只工作在内存中,我们可以不大准确的说,内存中资源的锁叫latch,数据库对象(表,索引等)的锁叫Lock。
比如数据缓存中的某个块要被读取,我们会获得这个块的latch,这个过程叫做pin,另外一个进程恰好要修改这个块,他也要pin这个块,此时他必须等待,当前
一个进程释放latch后才能pin住,然后修改,如果多个进程同时请求的话,他们之间将出现竞争,没有一个入队机制,一旦前面进程释放latch,后面的进程就蜂
拥而上,没有先来后到的概念,这个和Lock是有本质区别的,这一切都发生的非常快,因为Latch的特点是快而短暂,当然这个只是大致过程。
先来看下Latch和Lock的区别
1。 Latch是对内存数据结构提供互斥访问的一种机制,而Lock是以不同的模式来套取共享资源对象,各个模式间存在着兼容或排斥,从这点看出,Latch 的访问
,包括查询也是互斥的,任何时候,只能有一个进程能pin住内存的某一块,幸好这个过程是相当的短暂,否则系统性能将没的保障,现在从9I开始,允许多个进
程同时查询相同的内存块,但性能并没有想象中的好。
2。 Latch只作用于内存中,他只能被当前实例访问,而Lock作用于数据库对象,在RAC体系中实例间允许Lock检测与访问
3。 Latch是瞬间的占用,释放,Lock的释放需要等到事务正确的结束,他占用的时间长短由事务大小决定
4。 Latch是非入队的,而Lock是入队的
5。 Latch不存在死锁,而Lock中存在(死锁在Oracle中是非常少见的)
看看下面这个例子,你会感觉到Latch的存在
CREATE TABLE MYTEST AS SELECT OBJECT_NAME FROM USER_OBJECTS WHERE ROWNUM=4;
SET TIMING ON
DECLARE lv_name VARCHAR2(25):='';
BEGIN
FOR i IN 1 .. 100000LOOP
SELECT OBJECT_NAME INTO lv_name FROM MYTEST WHERE ROWNUM=1;
END LOOP;
END;
/
PL/SQL procedure successfully completed
Executedin 3.359 seconds
这个进程不断的访问表上的同一个数据块,他先会物理读取数据块到数据缓冲区,然后在内存中不断的获取这个块的latch,现在只有单个进程,运行的还好,10
万次用了3秒多,但当我拉出4个窗口同时并发的运行这个语句时,问题就出现了,多个进程PIN同一个数据块,每个大概花了15秒,并且看到他们一个一个的结束
,到最后只剩一个时一闪就过去了,因为没人和他抢了,这个实验展现了Latch竞争的现象,对于9I提出的查询可以共享Latch在此我表示了质疑。
现在来看看进程获取Latch的详细过程,任何时候,只有一个进程可以访问内存中的某一个块(9I提出的Latch共享我不想考虑),如果进程因为别的进程正占用
块而无法获得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-休眠。。。占用,这里有人会问为什么要SPIN,为什么不直接休眠等待?这里要明
白休眠意味着什么,他意味着暂时的放弃CPU,进行上下文切换(context switch),这样CPU要保存当前进程运行时的一些状态信息,比如堆栈,信号量等数据
结构,然后引入后续进程的状态信息,处理完后再切换回原来的进程状态,这个过程如果频繁的发生在一个高事务,高并发进程的处理系统里面,将是个很昂贵
的资源消耗,所以他选择了spin,让进程继续占有CPU,运行一些空指令,之后继续请求,继续spin,直到达到_spin_count值,这时会放弃CPU,进行短暂的休眠
,再继续刚才的动作,Oracle软件就是这么设计的,世界大师们的杰作,自然有他的道理,我就不在这上面再费文字了。
系统发生关于Latch的等待是没发避免的,因为这是Oracle的运作机制,当你看到很高的Latch get时并不意味着你的系统需要调整,有时候很高的get值背后只有
很短的等待时间,我们调整的对象应该以消耗的时间来圈定,而不是看到一个很高的获取次数值,当然,获取值异常的高出别的等待时间几十万倍时我们还是要
关心的,Oracle关于Latch的等待非常繁多,主要的包括share pool,library cache,cache buffer chains,buffer busy wait,每一个的调整几乎都可以写几
页纸,以后慢慢完成吧。
-----------------------------------------------------------------------------------
Oracle使用两种数据结构来进行shared pool的并发控制:lock 和 pin.
Lock比pin具有更高的级别.
Lock在handle上获得,在pin一个对象之前,必须首先获得该handle的锁定.
锁定主要有三种模式: Null,share,Exclusive.
在读取访问对象时,通常需要获取Null(空)模式以及share(共享)模式的锁定.
在修改对象时,需要获得Exclusive(排他)锁定.
在锁定了Library Cache对象以后,一个进程在访问之前必须pin该对象.
同样pin有三种模式,Null,shared和exclusive.
只读模式时获得共享pin,修改模式获得排他pin.
通常我们访问、执行过程、Package时获得的都是共享pin,如果排他pin被持有,那么数据库此时就要产生等待.
------------------------------------------------------------------------
library cache lock和library cache pin都是我们关心的.接下来我们就研究一下这几个等待事件.
(一).LIBRARY CACHE PIN等待事件
Oracle文档上这样介绍这个等待事件:
"library cache pin" 是用来管理library cache的并发访问的,pin一个object会引起相应的heap被
载入内存中(如果此前没有被加载),Pins可以在三个模式下获得:NULL,SHARE,EXCLUSIVE,可以认为pin是一种特定
形式的锁.
当Library Cache Pin等待事件出现时,通常说明该Pin被其他用户已非兼容模式持有.
"library cache pin"的等待时间为3秒钟,其中有1秒钟用于PMON后台进程,即在取得pin之前最多等待3秒钟,否则就超时.
"library cache pin"的参数如下,有用的主要是P1和P2:
P1 - KGL Handle address.
P2 - Pin address
P3 - Encoded Mode & Namespace
"LIBRARY CACHE PIN"通常是发生在编译或重新编译PL/SQL,VIEW,TYPES等object时.编译通常都是显性的,
如安装应用程序,升级,安装补丁程序等,另外,"ALTER","GRANT","REVOKE"等操作也会使object变得无效,
可以通过object的"LAST_DDL"观察这些变化.
当object变得无效时,Oracle 会在第一次访问此object时试图去重新编译它,如果此时其他session已经把此object pin
到library cache中,就会出现问题,特别时当有大量的活动session并且存在较复杂的dependence时.在某种情况下,重新
编译object可能会花几个小时时间,从而阻塞其它试图去访问此object的进程.
------------------------------------------------------------------------------------------------------------
Latch及latch冲突
引言
Oracle Rdbms应用了各种不同类型的锁定机制,latch即是其中的一种,本文将集中介绍latch(闩)的概念,理解latch的实现方法并说明引起latch冲突的原因。
什么是latch
Latch是用于保护SGA区中共享数据结构的一种串行化锁定机制。Latch的实现是与操作系统相关的,尤其和一个进程是否需要等待一个latch、需要等待多长时间有关。
Latch是一种能够极快地被获取和释放的锁,它通常用于保护描述buffer cache中block的数据结构。与每个latch相联系的还有一个清除过程,当持有latch的进程成为死进程时,该清除过程就会被调用。Latch还具有相关级别,用于防止死锁,一旦一个进程在某个级别上得到一个latch,它就不可能再获得等同或低于该级别的latch。
Latch与Enqueue(队列)
Enqueue是Oracle使用的另一种锁定机制,它更加复杂,允许几个并发进程不同程度地共享某些资源。任何可被并发使用的对象均可使用enqueue加以保护。一个典型的例子是表的锁定,我们允许在一个表上有不同级别的共享。与latch不同之处在于,enqueue是使用操作系统特定的锁定机制,一个enqueue允许用户在锁上存贮一个标记,来表明请求锁的模式。操作系统lock manager跟踪所有被锁定的资源,如果某个进程不能获取它所请求的那种锁,操作系统就把请求进程置于一个等待队列中,该队列按FIFO原则调度,而在latches中是没有象enqueue中排序的等待队列,latch等待进程要么使用定时器来唤醒和重试,要么spin(只用于多处理器情况下)。
何时需要latch
当一个进程准备访问SGA中的数据结构时,它就需要获得一个latch。当进程获得latch后,它将一直持有该latch直到它不再使用此数据结构,这时latch才会被释放。可通过latch名称来区分它所保护的不同数据结构。
Oracle使用元指令对latch进行操作, 当所需的latch已被其他进程持有时,执行指令进程将停止执行部分指令,直到该latch被释放为止。从根本上讲,latch防止并发访问共享数据结构,由于设置和释放latch的指令是不可分割的,操作系统就可以保证只有一个进程获得latch,又由于这只是单条指令,所以执行速度很快。latch被持有的时间是很短,而且提供了当持有者不正常中断时的清除机制,该清除工作是由Oracle后台进程PMON来完成的。
什么导致latch冲突
Latch保护SGA中的数据结构被多个用户同时访问,如果一个进程不能立即得到所需latch,它就必须等待,这就导致了CPU的额外负担和系统的速度降低。额外的CPU使用是进程‘spining’导致的,‘spining’是指进程定时地重复尝试获取latch,在连续两次之间,进程处于休眠状态,在得到latch之前,spining过程将重复进行下去。
如何标识内部latch的冲突
Server manager monitor是一个相当有用的来监视latch等待、请求和冲突的工具。也可查询相关的数据字典表:v$latch, v$latchholder, v$latchname。
v$latch表的每一行包括了对不同类型latch的统计,每一列反映了不同类型的latch请求的活动情况。不同类型的latch请求之间的区别在于,当latch不可立即获得时,请求进程是否继续进行。按此分类,latch请求的类型可分为两类:willing-to-wait和immediate。
Willing-to-wait : 是指如果所请求的latch不能立即得到,请求进程将等待一很短的时间后再次发出请求。进程一直重复此过程直到得到latch。
Immediate:是指如果所请求的latch不能立即得到,请求进程就不再等待,而是继续执行下去。
在v$latch中的以下字段反映了Willing-to-wait请求:
GETS---成功地以Willing-to-wait请求类型请求一个latch的次数。
MISSES---初始以Willing-to-wait请求类型请求一个latch不成功的次数。
SLEEPS---初始以Willing-to-wait请求类型请求一个latch不成功后,进程等待获取latch的次数。
在v$latch中的以下字段反映了Immediate类请求:
IMMEDIATE_GETS---以Immediate请求类型成功地获得一个latch的次数。
IMMEDIATE_MISSES---以Immediate请求类型请求一个latch不成功的次数。
我们可以通过对v$latch, v$latchholder, v$latchname的查询获得有关latch信息,例如:
/* 已知一个latch地址,找到latch名字 */
col name for a40
select a.name from v$latchname a, v$latch b
where b.addr = '&addr'
and b.latch#=a.latch#;
/* 显示系统范围内的latch统计 */
column name format A32 truncate heading "LATCH NAME"
column pid heading "HOLDER PID"
select c.name,a.addr,a.gets,a.misses,a.sleeps,
a.immediate_gets,a.immediate_misses,b.pid
from v$latch a, v$latchholder b, v$latchname c
where a.addr = b.laddr(+)
and a.latch# = c.latch#
order by a.latch#;
/* 由latch名称显示对latch的统计 */
select c.name,a.addr,a.gets,a.misses,a.sleeps,
a.immediate_gets,a.immediate_misses,b.pid
from v$latch a, v$latchholder b, v$latchname c
where a.addr = b.laddr(+) and a.latch# = c.latch#
and c.name like '&latch_name%' order by a.latch#;
latch有40余种,但作为DBA关心的主要应有以下几种:
Cache buffers chains latch: 当用户进程搜索SGA寻找database cache buffers时需要使用此latch。
Cache buffers LRU chain latch: 当用户进程要搜索buffer cache中包括所有 dirty blocks的LRU (least recently used) 链时使用该种latch。
Redo log buffer latch: 这种latch控制redo log buffer中每条redo entries的空间分配。
Row cache objects latch: 当用户进程访问缓存的数据字典数值时,将使用Row cache objects latch。
下面我们将着重介绍一下如何检测和减少redo log buffer latch的冲突。对redo log buffer的访问是由redo log buffer latch来控制的,这种latch有两种类型, redo allocation latch和redo copy latch。
Redo allocation latch控制redo entries在redo log buffer中的空间分配。Oracle的一个用户进程只有得到redo allocation latch后才能为redo entries在redo log buffer中分配空间,又由于一个instance只有一个redo allocation latch,所以一次只有一个用户进程在buffer中分配空间。当用户进程获得latch后,首先为redo entry分配空间,然后进程继续持有latch并拷贝entry到buffer中,这种拷贝称为“在redo allocation latch上的拷贝”(copying on the redo allocation latch),拷贝完毕后,用户进程释放该latch。
一个“在redo allocation latch上的拷贝”的redo entry的最大值是由初始化参数LOG_SMALL_ENTRY_MAX_SIZE定义的,根据操作系统的不同而不同。
Redo Copy Latch只应用于多CPU的系统。在多CPU的instance中,如果一个redo entry太大,超过了LOG_SMALL_ENTRY_MAX_SIZE定义值,则不能进行“在redo allocation latch上的拷贝”, 此时用户进程必须获取redo copy latch。一个instance中可以有多个redo copy latch,其数目由初始参数LOG_SIMULTANEOUS_COPIES决定,缺省值为CPU数目。
在单CPU情况下,不存在redo copy latch,所有的redo entry无论大小, 都进行“在redo allocation latch上的拷贝”。
对redo log buffer的过多访问将导致redo log buffer latch的冲突,latch冲突将降低系统性能,我们可通过如下查询来检测这种latch冲突:
col name for a40
SELECT ln.name,gets,misses,immediate_gets,immediate_misses
FROM v$latch l,v$latchname ln
WHERE ln.name IN('redo allocation','redo copy') AND ln.latch#=l.latch#
/
若misses与gets的比例超过1%或immediate_misses与(immediate_gets+immediate_misses)比例超过1%时,应考虑采取措施减少latch的冲突。
大多数的redo log buffer latch冲突是在多个CPU情况下,两个或多个Oracle进程试图同时得到相同的latch发生的。由于一个instance只有一个redo allocation latch,为减少redo allocation latch的冲突,应减少单个进程持有latch的时间,这可以通过减小初始参数LOG_SMALL_ENTRY_MAX_SIZE以减小redo entry的数目和大小来实现。如果观察到有redo copy latch冲突,可以通过增大LOG_SIMULTANEOUS_COPIES 初始参数来加大latch数目,其缺省值为CPU数目,最大可增大到CPU数目的两倍。
Latches and Internal Locks (摘自 Oracle Concepts)
Latches and internal locks protect internal database and memory structures. Both are inaccessible to users, because users have no need to control over their occurrence or duration.
Latches are simple, low-level serialization mechanisms to protect shared data structures in the system global area (SGA). For example, latches protect the list of users currently accessing the database and protect the data structures describing the blocks in the buffer cache. A server or background process acquires a latch for a very short time while manipulating or looking at one of these structures. The implementation of latches is operating system dependent, particularly in regard to whether and how long a process will wait for a latch.
(最重要的是:latch是保护SGA中的共享的结构,而这种结构显然是描述内存块的组织方式的,而最常见的结构显然就是各种lists/buckets。)
Internal locks are higher-level, more complex mechanisms than latches and serve a variety of purposes.
These locks are of very short duration and are held on entries in dictionary caches while the entries are being modified or used. They guarantee that statements being parsed do not see inconsistent object definitions.
Dictionary cache locks can be shared or exclusive. Shared locks are released when the parse is complete. Exclusive locks are released when the DDL operation is complete.
These locks protect various files. For example, one lock protects the control file so that only one process at a time can change it. Another lock coordinates the use and archiving of the redo log files. Datafiles are locked to ensure that multiple instances mount a database in shared mode or that one instance mounts it in exclusive mode. Because file and log locks indicate the status of files, these locks are necessarily held for a long time.
These locks protect tablespaces and rollback segments. For example, all instances accessing a database must agree on whether a tablespace is online or offline. Rollback segments are locked so that only one instance can write to a segment.
摘自:http://www.itpub.net/forum.php?mod=viewthread&tid=1320117&extra=&highlight=&page=2
Latches are the more restrictive mechanism, because they do not allow multiple processes to inspect the protected data structure at the same time—they provide for exclusive access only .
Locks allow for better concurrency , because they maybe held in a shared mode when the data structure is simply being inspected.
This is a simplification. The redo copy latches can be shared, but this is hardware dependent.
Another significant difference between locks and latches is request queuing .(是否排队)
Requests for locks are queued if necessary and serviced in order, whereas latches do not support request queuing. (lock会排队,而latch不会排队,所以lock会发生死锁,而latch会有饿死现象。)
If a request to get a latch fails because the latch is busy, the process just continues to retry until it succeeds. So latch requests are not necessarily serviced in order.
Because a latch can only be held by one process at a time , and because there is no inherent concept of queuing, the latch data structure itself is very simple —essentially j ust a single location in memory representing the state of the latch .
And because the latch data structure is so simple, the functions to get and release a latch have very little work to do. By contrast, the data structures for locks are much more sophisticated because of their support for queuing and concurrency .So the functions to get, convert, and release locks have correspondingly more work to do.
Of course, it is necessary for Oracle to ensure that only one process at a time can modify the latch and lock data structures themselves.
For latches this is easy. Because each latch is just a single location in memory, Oracle is able to use the TEST AND SET, LOAD AND CLEAR, or COMPARE AND SWAP instructions of the underlying hardware's instruction set for its latch get operations. Because these are simple machine instructions that are guaranteed to be atomic , no other locking mechanism is needed . This simplicity makes latch getsvery efficient .
Oracle's lock data structures, on the other hand, have several parts, and therefore cannot be modified atomically . For this reason, Oracle actually protects operations on locks with latches . (因为lock不能被原子性地修改,所以在修改lock时,实际上是利用了latch来保证唯一性的修改的。) The type of latch used varies depending on the type of lock. For example, the cache buffer locks are indirectly protected by the cache buffers chains latches , and the row cache enqueue locks are protected by the row cache objects latch .
总结一下:
Oracle中lock和latch的区别如下:
1)latch是十分轻量级的,而lock是复杂的结构;
2)latch是排他性的访问,没有排队机制,存在饿死现象;而lock允许并发,有排队机制,存在死锁现象;
3)latch是修改是原子性的,而lock的修改时要latch保护的;
4)latch只用于SGA内存中的 structures ;
About Me
...............................................................................................................................
● 本文整理自网络
● 本文在itpub(http://blog.itpub.net/26736162)、博客园(http://www.cnblogs.com/lhrbest)和个人微信公众号(xiaomaimiaolhr)上有同步更新
● 本文itpub地址:http://blog.itpub.net/26736162/abstract/1/
● 本文博客园地址:http://www.cnblogs.com/lhrbest
● 本文pdf版及小麦苗云盘地址:http://blog.itpub.net/26736162/viewspace-1624453/
● 数据库笔试面试题库及解答:http://blog.itpub.net/26736162/viewspace-2134706/
● QQ群:230161599 微信群:私聊
● 联系我请加QQ好友(646634621),注明添加缘由
● 于 2017-07-01 09:00 ~ 2017-07-31 22:00 在魔都完成
● 文章内容来源于小麦苗的学习笔记,部分整理自网络,若有侵权或不当之处还请谅解
● 版权所有,欢迎分享本文,转载请保留出处
...............................................................................................................................
拿起手机使用微信客户端扫描下边的左边图片来关注小麦苗的微信公众号:xiaomaimiaolhr,扫描右边的二维码加入小麦苗的QQ群,学习最实用的数据库技术。