等待事件 Latch Free(闩锁释放)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/leo__1990/article/details/90437256

   Latch Free通常被称为闩锁释放,这个名称常常引起误解,实际上我们应该在前面加上一个“等待”(wait), 当数据库出现这个等待时,说明有进程正在等待某个Latch被释放,也就是waiting latch free。

 

   Latch是一种低级排队(串行)机制,用于保护SGA中共享内存结构。Latch就像是一种快速被获取和释放的内存锁,
用于防止共享内存结构被多个用户同时访问。其实不必把Latch想得过于复杂,Latch通常就是操作系统利用内存中的某个区域,
通过设置变量为0或非0,来表示Latch是否已经被取得,大多数操作系统,是使用TEST AND SET的方式来完成Latch检查或持有的。
   为了快速地获得一个直观认识,以下示例展现的了Latch的获取与释放过程。Latch在内存中的位置及名称可以通过下面的语句查询获得:

SQL> set lines 300
SQL> col ksmfsadr for a30
SQL> col ksmfsnam for a30
SQL> col ksmfstyp for a30
SQL> col kslldnam for a30
SQL> select k.ksmfsadr,ksmfsnam,ksmfstyp,ksmfssiz,kslldnam,kslldlvl
      from x$ksmfsv k,x$kslld a
      where k.ksmfsnam = 'ksqeql_' and kslldnam = 'enqueues';  2    3  

KSMFSADR		       KSMFSNAM 		      KSMFSTYP			       KSMFSSIZ KSLLDNAM			 KSLLDLVL
------------------------------ ------------------------------ ------------------------------ ---------- ------------------------------ ----------
000000006000D390	       ksqeql_			      ksllt				    160 enqueues				5

得到这些信息之后,可以通过Latch的地址信息手工对Latch进行模拟的持有或释放,注意获取Latch使用了kslgetl过程,
释放Latch使用了kslfre,也就是Latch Free过程,如下所示: 

SQL> select to_number('000000006000D390','XXXXXXXXXXXXXXXX') from dual;

TO_NUMBER('000000006000D390','XXXXXXXXXXXXXXXX')
------------------------------------------------
				      1610666896
                              
SQL> oradebug setmypid
Statement processed.
SQL> oradebug call kslgetl 1610666896 1
Function returned 1
SQL> oradebug call kslfre 1610666896
Function returned 0

在这个Latch的短时持有前后,观察这个Latch的等待时间,可以发现Latch等待,如下所示,
这就是Latch、Latch Get和Latch Free的一个直观案例。  

 
SQL> select name,wait_time from v$latch where name = 'enqueues'; NAME WAIT_TIME ---------------------------------------------------------------------------------------- enqueues 0

在数据库内部,Oracle通过v$latch视图记录不同类型Latch的统计数据,按获取和等待方式不同进行分类,
Latch请求的类型可以分为willing-to-wait和immediate两类。
·willing-to-wait:是指如果所请求的Latch不能立即得到,请求进程将等待一段很短的时间后再次发出请求。进程一直重复此过程直到得到Latch。
·immediate:是指如果所请求的Latch不能立即得到,请求进程就不再等待,而是继续执行下去。
在v$latch中以下字段记录了willing-to-wait请求。
· GET:成功地以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不成功的次数。

Oracle的Latch机制是竞争,其处理类似于网络里的CSMA/CD,所有用户进程争夺Latch,对于愿意等待类型(willing-to-wait)的Latch,如果一个进程在第一次尝试中没有获得Latch开始自旋(spin),如果经过_spin_count次争夺不能获得Latch,然后该进程转入睡眠状态,持续一段指定长度的时间,然后再次醒来,按顺序重复以前的步骤。这一过程可以下图来说明:

用户进程争夺Latch的过程

SPIN的次数受隐含参数_spin_count影响,该参数的缺省值为2000。以下数据取自Oracle 11gR2 + Linux环境: 

SQL>  select * from v$version where rownum < 2;

BANNER
----------------------------------------------------------------------------------------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Productio

该系统存在1颗CPU:


SQL>  show parameter cpu_count

NAME				     TYPE		    VALUE
------------------------------------ ---------------------- ------------------------------
cpu_count			     integer		    1

_spin_count的缺省值即为2000:
从以上过程可以看到,在spin的过程中,进程会一直持有CPU,spin的机制是假设Latch可以被快速释放(正常情况下,Latch的持有时间是微秒级,相对spin机制如果直接采用Sleep方式引起的上下文切换会相当昂贵,所以Oracle针对Latch引入了spin算法),
如果其他CPU上的其他进程释放了Latch,SPIN进程就可以立即获得这个Latch。如果系统只有单CPU,那就谈不上SPIN了。另一方面也可以看到,
Latch竞争是非常昂贵的,可能导致严重的CPU耗用,所以Latch竞争在任何时候都应该引起充分的重视。经过spin后成功获得Latch的次数
被记录在v$latch.spin_gets字段。通过下图来说明一下Latch竞争的情况。

继续来具体看一下willing-to-wait和immediate两类Latch的大致数量,以下查询来自Oracle 11gR2(同以上数据库):
SQL> select count(*) from v$latch;

  COUNT(*)
----------
       582

SQL>  select count(*) from v$latch where IMMEDIATE_GETS + IMMEDIATE_MISSES > 0;

  COUNT(*)
----------
	35

SQL> select count(*) from v$latch where IMMEDIATE_GETS + IMMEDIATE_MISSES = 0;

  COUNT(*)
----------
       547

可以看到willing-to-wait类型的等待事件占了绝大部分,immediate类型的仅为少数:
SQL> col name for a40 
SQL> select name,immediate_gets,immediate_misses,spin_gets
	     from v$latch
         where immediate_gets + immediate_misses > 0
         order by immediate_gets desc;  2    3    4  

NAME					 IMMEDIATE_GETS IMMEDIATE_MISSES  SPIN_GETS
---------------------------------------- -------------- ---------------- ----------
hash table column usage latch			 402521 	       0	  0
cache buffers chains				 138457 	       0	  0
enqueue freelist latch				  78516 	       0	  0
simulator lru latch				  72942 	       0	  0
redo copy					  67698 	     124	  0
redo allocation 				  67698 	       0	  0
cache buffers lru chain 			  20530 	       0	  0
row cache objects				  13868 	       4	  0
checkpoint queue latch				   2863 	       0	  0
post/wait queue 				   2483 	       0	  0
active service list				   2426 	       0	  0

NAME					 IMMEDIATE_GETS IMMEDIATE_MISSES  SPIN_GETS
---------------------------------------- -------------- ---------------- ----------
space background task latch			   2392 	       0	  0
write info latch				   1515 	       0	  0
cache table scan latch				   1353 	       0	  0
In memory undo latch				   1337 	       0	  0
Memory Management Latch 			   1297 	       0	  0
SQL memory manager latch			   1272 	       0	  0
KTF sga latch					   1264 	       0	  0
longop free list parent 			    261 	       0	  0
object queue header heap			    230 	       0	  0
resmgr:active threads				    192 	       0	  0
MQL Tracking Latch				     77 	       0	  0

NAME					 IMMEDIATE_GETS IMMEDIATE_MISSES  SPIN_GETS
---------------------------------------- -------------- ---------------- ----------
process allocation				     75 	       0	  0
job workq parent latch				     11 	       0	  0
resmgr:schema config				      9 	       0	  0
active checkpoint queue latch			      2 	       0	  0
job_queue_processes free list latch		      2 	       0	  0
rules engine evaluation context statisti	      2 	       0	  0
cs

JS mem alloc latch				      2 	       0	  0
hash table modification latch			      2 	       0	  0
multiblock read objects 			      2 	       0	  0

NAME					 IMMEDIATE_GETS IMMEDIATE_MISSES  SPIN_GETS
---------------------------------------- -------------- ---------------- ----------
SGA IO buffer pool latch			      1 	       0	  0
alert log latch 				      1 	       0	  0
kmcpvec latch					      1 	       0	  0
shared server configuration			      1 	       0	  0

35 rows selected.

         需要注意的是,immediate类型的Latch通常是因为存在多个可用Latch,最常见的如redo copy latch,当process想要取得redo copy latch时,它首先要求其中一个Latch,如果可以取得就持有该Latch,如果不能获取,它会立刻转向要求另一个redo copy latch,只有所有redo copy latch都无法取得时,才会sleep与wait。

   immediate的另外一种原因是每个Latch都有level的概念(level=1 - 14),当一个process需要取得一组Latches时,为避免死锁,取得Latches有一定的顺序,即process新请求的Latch的level,应该大于process目前所握有的Latch的level。所以如果process要求的新Latch的level小于目前所持有的Latch的level,正常情况下,Oracle要求process先释放目前所持有的所有Latch,再依次取得这些Latch。为节省时间,Oracle允许进程以no-wait方式要求较低level的Latch,如果成功取得,既可以避免deadlcok又可以节省时间。

在Oracle 10g之前,Latch Free同Enqueue一样,是一个汇总等待。从Oracle 10g开始,这个等待被分解,现在可以更直接地通过会话等待得知具体的Latch发生在哪些资源上: 

SQL> select name,wait_class
         from v$event_name
         where name like '%latch%';  2    3  

NAME					 WAIT_CLASS
---------------------------------------- --------------------------------------------------------------------------------------------------------------------------------
latch: cache buffers chains		 Concurrency
latch: redo writing			 Configuration
latch: redo copy			 Configuration
latch: Undo Hint Latch			 Concurrency
latch: In memory undo latch		 Concurrency
latch: MQL Tracking Latch		 Concurrency
latch: row cache objects		 Concurrency
latch: shared pool			 Concurrency
latch free				 Other
latch activity				 Other
wait list latch activity		 Other

NAME					 WAIT_CLASS
---------------------------------------- --------------------------------------------------------------------------------------------------------------------------------
wait list latch free			 Other
latch: call allocation			 Other
latch: session allocation		 Other
latch: messages 			 Other
latch: enqueue hash chains		 Other
latch: active service list		 Other
latch: ges resource hash list		 Other
ges2 proc latch in rm latch get 1	 Other
ges2 proc latch in rm latch get 2	 Other
gcs retry nowait latch get		 Other
gcs remastering wait for read latch	 Other

NAME					 WAIT_CLASS
---------------------------------------- --------------------------------------------------------------------------------------------------------------------------------
latch: gcs resource hash		 Other
latch: cache buffers lru chain		 Other
latch: checkpoint queue latch		 Other
latch: cache buffer handles		 Other
buffer latch				 Other
latch: object queue header operation	 Other
latch: redo allocation			 Other
latch: gc element			 Other
latch: undo global data 		 Other
latch: Change Notification Hash table la Other
tch

NAME					 WAIT_CLASS
---------------------------------------- --------------------------------------------------------------------------------------------------------------------------------

latch: change notification client cache  Other
latch

latch: lob segment hash table latch	 Other
latch: lob segment query latch		 Other
latch: lob segment dispenser latch	 Other
waiting to get CAS latch		 Other
waiting to get RM CAS latch		 Other
latch: virtual circuit queues		 Other
PX qref latch				 Other

NAME					 WAIT_CLASS
---------------------------------------- --------------------------------------------------------------------------------------------------------------------------------
latch: parallel query alloc buffer	 Other
latch: PX hash array latch		 Other
latch: WCR: sync			 Other
latch: WCR: processes HT		 Other

44 rows selected.

最常见的Latch集中于Buffer Cache的竞争和Shared Pool的竞争。和Buffer Cache相关的主要Latch竞争

有cache buffers chains和cache buffers lru chain,和Shared Pool相关的主要Latch竞争有Shared Pool Latch和Library Cache Latch等。

Buffer Cache的Latch竞争经常是由于热点块竞争引起;
Shared Pool的Latch竞争通常是由于SQL的量硬解析引起。

猜你喜欢

转载自blog.csdn.net/leo__1990/article/details/90437256