全面解析oracle中的锁机制4

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 7、enqueue: 什么是enqueue enqueue可以做名词,也可以做动词来解释。 做名词时,指的的是一种锁的类型,比如Tx enqueue。 做动词时,则是指将锁请求放入到请求队列的操作。

7、enqueue:

什么是enqueue

enqueue可以做名词,也可以做动词来解释。

做名词时,指的的是一种锁的类型,比如Tx enqueue。

做动词时,则是指将锁请求放入到请求队列的操作。

我们知道,lock是一种需要排队的锁实现机制,这和latch是不一样的,latch是一种轻量级的锁,是不需要排队得。Enqueue就是lock的排队机制的实现。

lock是用来实现对于共享资源的并发访问的。如果两个session请求的lock是兼容的,则可以同时锁定资源,如果两个session请求的lock是不兼容的,则其中一个session必须等待另外一个session释放其持有的lock后,才能获得对共享资源的锁定。这时,等待的session的lock请求就需要进入到一个队列当中,这就是enqueue等待。


Enqueue的模式

enqueue(lock)一共有六种模式:
1 NULL 
2 SS
3 SX
4 S
5 SSX
6 X


什么是enqueue resource

Lock有三种可能的状态:已获得转换或者等待。对于某一个lock,可能一些session已经获得该lock,某些session请求转换,也有某些session在请求持有但无法成功而导致等待。所以,对于一个lock,需要三个队列来描述这些session的状态。这个三个队列,分别称为Owner,waiter和convert队列,由一个结构来管理,就是enqueue resource。

enqueue是有名字的,其名字就是对应的lock的类型加上ID1,ID2参数构成,形如<TYPE-ID1-ID2>。Enqueue resource的结构,其头部是该enqueue的名字,然后就是指向三个队列的指针。

通过v$resource视图可以查看当前系统中的enqueue。

由于系统中有很多类型的lock同时存在,那么enqueue resource结构实际上是一个数组,其长度由隐含参数_enqueue_resources控制,也就是说,该参数控制了系统中可同时存在的lock的数量。如果超过,则会报以下错误:
ORA-00052: "maximum number of enqueue resources exceeded"

通过v$resource_limit视图可以查看系统中各种资源的利用情况。


什么是enqueue lock

enqueue lock就是lock本身。oracle使用了和enqueue reouserce分离的另外一个数组来管理enqueue lock,这个数组的长度由隐含参数_enqueue_locks控制。

通过视图v$enqueue_lock可以查看该数组中的具体内容。


什么是enqueue hash

通过上面关于enqueue resource的描述,我们可以知道,oracle查找一个lock时,需要先在enqueue resource数上查找到该lock的位置。

如果每次都在数组上顺序查找,显然效率较低。我们知道hash是一种高效的查找算法,所以oracle对于enqueue resource的查找也采用了hash方式,引入了一个hash数组,其大小由隐含参数_enqueue_hash控制。

通过对enqueue的名字<TYPE-ID1-ID2>进行hash计算,得到的结果就是某个enqueue resource在hash数组中的位置,也就是定位到了具体的hash bucket。如果多个enqueue resource的hash值相同,则在同一个bucket中形成一个链表。

相应的,为了保护这个hash数组,需要引入一个latch:enqueue hash chain。该latch有若干个子latch,由隐含参数_enqueue_hash_chain_latches控制


什么是enqueue freelist

同样的,对于enqueue resource数组中的空闲位置,需要通过一个freelist列表来管理,这样每次在请求新的位置时,不至于要扫描整个数组。enqueue freelist由enqueues latch的保护。

实际上,enqueue resource的Hash管理方式,和buffer cache/library cache的管理方式非常的相像。如果想更深入的了解enqueue hash,resource和lock,可以dump出具体的结果看看:

alter session set events ’immediate trace name enqueues level 3’;


8、latch:

Oracle数据库使用闩锁来管理内存的分配和释放。假设,某个用户进程(假设其为A)发出一条update语句,要去更新58号数据块里的某条记录。则该用户进程对应的服务器进程在写内存的时候,找到58号数据块,并往里写内容。A在写58号数据块的过程中,这时,另一个用户进程B发出insert语句,要将某个新的记录插入到58号数据块里。如果没有一定的保护机制,A正要写入的空间可能会被B抢先写入,或者相反,B正要写入的空间也可能会被A抢先写入。不管哪个用户先抢先写入,造成的结果就是,58号数据块里的数据都混乱了,因为这时,A和B之间的数据互相交织在一起了。

因此,必须使用latch对此进行保护。简单来说,任何进程要写数据块时,都必须先获得latch,在写入过程中,一直持有该latch,写完以后,释放该latch。对于上面的例子来说,当A在写入58号数据块时,先获得latch,然后开始写。而当A正在写入的过程中,B也要写58号数据块。这时B在尝试获得latch时,发现该latch正被其他用户(也就是A)持有,因此B进入等待状态。直到A写完数据块并释放latch以后,B才能获得latch,获得latch以后,才能在58号数据块里写入数据。


这里只是以写数据块为例来说明为何要使用latch。而事实上,latch不仅仅用于写数据块,比如对于shared pool来说,其内存单位就不是数据块了。latch也不仅仅用于写操作,只要涉及内存地址的读和写,都需要通过获得latch来实现串行化,一次只能有一个服务器进程在读或者写内存地址。


Oracle在实例管理中,不管是buffer cache、shared pool还是log buffer,都引入了各种各样的latch。实现latch时,实际是由操作系统的旗语(semaphore:也叫信号量)来完成的。为了便于理解,可以把它们想象为,通过某个变量值的变化而实现的。变量值为0则说明latch当前没有被其他进程获取,否则如果为非0值,则说明它已经被其他进程所获取了。Oracle在设计latch的时候将其定义为轻量级锁,因此它的操作非常快,以微秒(microsecond,也就是百万分之一秒)来计算。。闩只保持很短的时间,而且提供了一种清理机制,万一某个闩持有者在持有闩时异常地“死掉了”,就能执行清理。这个清理过程由PMON 执行。


latch分为两种类型:

愿意等待(Willing-To-Wait):

大部分的latch都属于这种类型。这种类型的latch都是通过Test-And-Set的方式来实现的。也就是说,如果当前进程不能获得latch的时候,会绕着CPU旋转,而不放弃CPU。这也就是所谓的SPIN CPU,实际就是执行一段空循环,类似执行下面一段代码(其中的N由Oracle内部来控制):

loopITPUB个人空间E\Mu_$aNn
exit when i>= NITPUB个人空间	@'J~T#`4@'M
i := i+1;
P \n
n[U;G{W/?0null;ITPUB个人空间3Qm7_P%D)_!a~
end loop;

进程之所以不释放CPU而是绕着CPU旋转,是由于latch操作本身是一个很快速的动作,因此可能等一会就能获得latch了。当进程一旦获得CPU,但是获得不了latch时,如果这时候立刻放弃CPU,那么需要进行上下文切换,下次再次尝试获得latch时,又要进行上下文切换,可能反而要消耗更多的时间。因此,进程在不能获得latch的时候,会执行上面这段代码,绕着CPU转一会,然后再次尝试获得latch,如果仍然不能获得,则再次旋转CPU。当反复旋转CPU并尝试获得latch的的次数超过某个上限(该上限由隐藏参数控制)时,这时进程会释放CPU,并进入睡眠(Sleep)状态。进程一旦进入睡眠状态,则会抛出一个对应的等待事件,并记录在视图v$session_wait里,说明当前该进程正在等待的latch的类型等信息。初始状态下,一个进程会睡眠0.01秒。然后醒过来,并再次尝试获得latch。如果旋转CPU的次数达到上限以后,仍然不能获得latch,则再次进入睡眠,这时会睡眠两倍的时间,依此类推,直到达到睡眠的最大值:0.2秒。

这是在数据库服务器具有多个CPU时的情形,如果只有一个CPU,就不存在旋转CPU的情况,一旦获得不了latch,就进入睡眠。


总的来说,当进程尝试获取Willing-To-Wait类型的latch时,如果失败,则进程会一直尝试对latch的获取,不断循环,直到获得latch为止,或者是达到所指定的上限值为止。当达到上限值时,进程进入睡眠。


不等待(No-Wait):

这种类型的latch比较少,对于这种类型的latch来说,都会有很多个可用的latch。当一个进程请求其中的一个latch时,会以no-wait模式开始请求。如果所请求的latch不可用,则进程不会等待,而是立刻请求另外一个latch。只有当所有的latch都不能获得时,才会进入等待。

从另外一个角度来说,latch分为单个latch(Solitary latch,比如shared pool latch以及redo allocation latch等)和latch组(比如library cache latch、cache buffers lru chain latch以及cache buffers chains latch等)。latch组包括父latch和子latch。单个latch和父latch都是定义在数据库软件代码里的,而且都是静态分配的。对于每种类型的latch,只有一个父latch。而子latch则根据参数或默认值而动态设定,而且子latch的访问独立于父latch。通常来说,父latch只用于汇总显示报表的目的。


如果latch资源被争用,通常都会表现为CPU资源使用过高。而反过来说,如果我们发现CPU资源很紧张,利用率总是在90%以上,甚至总是在100%,其主要原因有以下几点:


SQL语句没有使用绑定变量。如果没有使用绑定变量,或者书写SQL时随意性过大,比如大小写混用等。则Oracle对每一条SQL语句都要进行解析,也就是要非常频繁地读写shared pool里的内存块,从而导致与解析SQL相关的latch争用。

 执行SQL语句时,扫描的数据块过多,或者说SQL语句写的比较低效,导致要扫描很多的数据块才能返回所要的记录。因为在查找、扫描数据块的过程中,进程也要获得latch,直到找到数据块为止。


为何一旦latch资源发生争用,就会导致CPU繁忙呢?可以想象一下,假设某个进程(A)执行一条SQL语句需要访问10000个数据块,那么该进程在扫描数据块的过程中,一直持有latch。而另一个进程B也要执行SQL,但是由于A持有了latch,导致B无法获得,于是旋转一会CPU,再去获得latch,直到进入睡眠才释放CPU。接下来C进程也要执行SQL,同样的,由于A持有了latch,导致C无法获得,于是也旋转一会CPU,再去获得latch,直到进入睡眠才释放CPU。如果类似B和C的进程很多的话,那我们会发现,CPU总是在被旋转,也就是在做空的循环,而无法做其他的事情。因此,体现出CPU的使用率过高。


要解决latch的争用,关键在于共享SQL语句(比如使用绑定变量、规范SQL的书写等)以及优化SQL语句,使其搜索以及扫描的数据块的个数下降到最低。

关于latch的详解:http://blog.csdn.net/changyanmanman/article/details/7706540

相关文章
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
71 2
|
2月前
|
存储 缓存 算法
分布式锁服务深度解析:以Apache Flink的Checkpointing机制为例
【10月更文挑战第7天】在分布式系统中,多个进程或节点可能需要同时访问和操作共享资源。为了确保数据的一致性和系统的稳定性,我们需要一种机制来协调这些进程或节点的访问,避免并发冲突和竞态条件。分布式锁服务正是为此而生的一种解决方案。它通过在网络环境中实现锁机制,确保同一时间只有一个进程或节点能够访问和操作共享资源。
89 3
|
17天前
|
PHP 开发者 UED
PHP中的异常处理机制解析####
本文深入探讨了PHP中的异常处理机制,通过实例解析try-catch语句的用法,并对比传统错误处理方式,揭示其在提升代码健壮性与可维护性方面的优势。文章还简要介绍了自定义异常类的创建及其应用场景,为开发者提供实用的技术参考。 ####
|
21天前
|
存储 缓存 监控
后端开发中的缓存机制:深度解析与最佳实践####
本文深入探讨了后端开发中不可或缺的一环——缓存机制,旨在为读者提供一份详尽的指南,涵盖缓存的基本原理、常见类型(如内存缓存、磁盘缓存、分布式缓存等)、主流技术选型(Redis、Memcached、Ehcache等),以及在实际项目中如何根据业务需求设计并实施高效的缓存策略。不同于常规摘要的概述性质,本摘要直接点明文章将围绕“深度解析”与“最佳实践”两大核心展开,既适合初学者构建基础认知框架,也为有经验的开发者提供优化建议与实战技巧。 ####
|
20天前
|
缓存 NoSQL Java
千万级电商线上无阻塞双buffer缓冲优化ID生成机制深度解析
【11月更文挑战第30天】在千万级电商系统中,ID生成机制是核心基础设施之一。一个高效、可靠的ID生成系统对于保障系统的稳定性和性能至关重要。本文将深入探讨一种在千万级电商线上广泛应用的ID生成机制——无阻塞双buffer缓冲优化方案。本文从概述、功能点、背景、业务点、底层原理等多个维度进行解析,并通过Java语言实现多个示例,指出各自实践的优缺点。希望给需要的同学提供一些参考。
42 7
|
20天前
|
Java 数据库连接 开发者
Java中的异常处理机制:深入解析与最佳实践####
本文旨在为Java开发者提供一份关于异常处理机制的全面指南,从基础概念到高级技巧,涵盖try-catch结构、自定义异常、异常链分析以及最佳实践策略。不同于传统的摘要概述,本文将以一个实际项目案例为线索,逐步揭示如何高效地管理运行时错误,提升代码的健壮性和可维护性。通过对比常见误区与优化方案,读者将获得编写更加健壮Java应用程序的实用知识。 --- ####
|
25天前
|
Java 开发者 Spring
深入解析:Spring AOP的底层实现机制
在现代软件开发中,Spring框架的AOP(面向切面编程)功能因其能够有效分离横切关注点(如日志记录、事务管理等)而备受青睐。本文将深入探讨Spring AOP的底层原理,揭示其如何通过动态代理技术实现方法的增强。
52 8
|
29天前
|
Java 测试技术 API
Java 反射机制:深入解析与应用实践
《Java反射机制:深入解析与应用实践》全面解析Java反射API,探讨其内部运作原理、应用场景及最佳实践,帮助开发者掌握利用反射增强程序灵活性与可扩展性的技巧。
79 4
|
1月前
|
存储 消息中间件 算法
深入探索操作系统的心脏——内核机制解析
本文旨在揭示操作系统核心——内核的工作原理,通过剖析其关键组件与机制,为读者提供一个清晰的内核结构图景。不同于常规摘要的概述性内容,本文摘要将直接聚焦于内核的核心概念、主要功能以及其在系统管理中扮演的角色,旨在激发读者对操作系统深层次运作原理的兴趣与理解。
|
1月前
|
负载均衡 Oracle 网络协议
Oracle中TAF与SCANIP全面解析
通过本文的解析,读者可以清晰地理解Oracle中TAF与SCAN IP的概念、工作原理及其在实际应用中的优势和局限性。TAF通过自动故障转移提升了会话的高可用性,而SCAN则通过简化客户端连接和负载均衡提升了集群的可管理性和扩展性。这两种技术在现代企业数据库架构中扮演着重要角色,能够显著提高系统的稳定性和可用性。
59 6

推荐镜像

更多
下一篇
DataWorks