星期四, 五月 31, 2007

总结和复习Oracle Lock contention

仅以本文来总结和复习Oracle Lock contention,并结合实际工作中的经验,让自己对Oracle的lock contention有一个更清楚的认识。
Data dictionary locks保护在数据字典中的数据对象定义,保证数据字典的完整性,提供数据字典的一致性view。Data dictionary locks分成row cache locks、library cache locks和library cache pins(很少会发生)。
Data dictionary rows被存储在row cache中,作为shared pool的一部分。用来减少对sytem表空间的物理I/O。cache rows也作为一种resource structure,lock structure 被动态分配在shared pool中。Row cache lock在RAC环境中比较常见。Library cache locks也叫breakable pase locks。
DDL locks保证在语句解析和执行时数据对象定义的完整性,DMl locks保证事务的一致性transactional consistency。包括table locks(object definition consistency)和row locks(consistency of the data itself)。
在解析一个语句时,每个游标维持管理一系列table lock structures。在第一次游标执行时,一个函数可以被执行得到所有的table locks。这些lock在事务结束或者终止时,自动释放。一个coversation history table的存在而致使DML table lock可以被回退。DML_Locks参数控制table locks的数量。Free lists被dml lock allocation latch所维持。被使用的结构在v$locked_object中可以查询。为了设定dml table locks的数量,可以参考v$resource_limit。如果要使dml locks失效,可以用dml_locks to zero或者alter table × disable table locks来完成。
为了保证数据本身的完整性,Oracle server通过使用row levels和transaction locks来完成。Row levels是通过每个行头的锁位the lock byte in each data row header和在数据块或者索引块中的ITLs事务列表interested transaction lists来完成。行级别的锁如下图所示:
ITL是一种列表数据结构,列表中的每个节点记录了ITL slot信息和被锁定行的rowid,列表的最初长度由INITRANS确定,可动态扩展到最大至MAXTRANS设定的值,但扩展时有一前提就是块中要有足够的空间,如果块中没有足够的空间生成ITL slot,即使当前的slot书远未达到MAXTRANS值,也不可能在进行扩展。因此ITL是一种块级的队列,它的数量表示了该块的并发程度,如果ITL slot不够用,就会产生ITL waits,INITRANS和MAXTRANS在建表示使用存储参数指定。
Transaction identifiers(XID)是事务在系统中的唯一标识。在数据块的事务列表ITLs中使用。XID由Rollback/undo segment number、transaction table slot number和sequence number or wrap#组成,简称usn#+slot#+wrap#。

Buffer locks是用来保护buffer cache中的blocks的一致性。Buffer header充当resource structure,session使用buffer handles来访问buffers,而buffer handles就是其中的lock structures。Buffer busy waits event由三个参数来定位,p1(absolute file number)、p2(block number)和p3(reason code)。
为了达到减少buffer busy waits on data blocks,我们可以减少行密度(改变pctfree/pctused、initrans和alter table * minimize records_per_block命令或者改变db_block_size)和避免“right-hand ”indexes。
Undo segment contention在采用了automatic undo managed segment后,这个情况得到了很好的解决。一般结果这个问题级别上都是增加undo segments。或者利用参数transactions_per_rollback_segment。
Index block contention和data block contention相似。一般表现为index blocks split和bitmap index updates。你可以通过设定event 10224:”index block split /delete trace”去跟踪分析,通常发生在高的I/O的index data files上。
Free list contention一般发生在RAC的环境上,但是利用freelist groups的技术和cach fusion to transfer read-consistent block image from one instance to another,这个情况已经比较的少见。即使在single-instance environment,多free list groups也是对性能有帮助的。在locally managed tablespaces 中使用auto segment space managed (ASSM) segment,已经不需要specify the pctused,freelists and freelist groups parameters。解决free list contention的步鄹大概如下:
1、确定FILE,BLOCK and ID。
SQL> select event,p1 "file", p2 "block",p3 "ID"
from v$session_wait
where event='buffer busy waits';
2、identify the segment,using file and block。
SQL> select segment_name,segment_type
from dab_extents
where file_id=
and between block_id and block_id+blocks -1;
3、get free lists for segment
SQL> select segment_name,freelists
From dba_segments
Where segment_name =
And segment_type= ;
4、recreate the freelist
SQL>alter table storage (freelists );

Wait event:write complete waits暗示DBWn写的比较慢,可以通过RAID0+1 not RAID5、异步I/O or 多个wriiters和增加disk spindles的数量来完成。
ORA-1575的出现表明在space management(ST)上存在等待。可以利用locally managed tablespace、use temporary tablesapce、increase sort_area_size和设定pctincrease为0来削除。
Dba_free_space_coalesced是辨别SMON正在coalescing。也可以查询dba_free_space,这个数据字典是依据fet$(只显示字典管理的表空间)。SMON 的作用大概如下:
1、 merging or coalescing free extents(每5分钟)
2、 cleaning up temporary segments(每2小时)
3、 maintaining flashbacku scn to time mapping(每5分钟)
4、 cleaning up non existing objects in OBJ$(每12小时)
5、 cleaning up IND$(每小时)
6、 shrink undo segments(每12小时)
7、 transaction recovery on startup
8、 transaction rollback(when posted by pmon)
可以通过本地管理表空间和设定pctincrease to zero,使合并进程失效。当然也可以利用event=”10269 trace name context forever ,level 10”。利用alter tablespace coalesce;来手动合并空闲空间。这个事件不应该成为问题。
Temporary segment cleanup事件不应该成为问题。可以利用在临时表空间中排序和不要随便的终止一个进程而达到。你也可以利用”event=10061 trace name context forever ,level 10”来完成disable。

总结和复习Oracle Enqueue

仅以本文来总结和复习Oracle Enqueue,并结合实际工作中的经验,让自己对Oracle的Enqueue有一个更清楚的认识。
首先我们要搞清楚什么了Enqueue,enqueue可以做名词,也可以做动词来解释。做名词时,指的的是一种锁的类型,比如Tx enqueue。做动词时,则是指将锁请求放入到请求队列的操作。我们知道,lock是一种需要排队的锁实现机制,这和latch是不一样的,latch是一种轻量级的锁,是不需要排队得。Enqueue就是lock的排队机制的实现。lock是用来实现对于共享资源的并发访问的。如果两个session请求的lock是兼容的,则可以同时锁定资源,如果两个session请求的lock是不兼容的,则其中一个session必须等待另外一个session释放其持有的lock后,才能获得对共享资源的锁定。这时,等待的session的lock请求就需要进入到一个队列当中,这就是enqueue等待。
Oracle server使用不同类型的锁去控制用户之间的并发访问。利用不同的被锁资源,可以将oracle Locks划分成为以下几个类别:
1、 DDL or data dictionary locks
2、 DML or data locks
3、 Internal locks and latches
4、 Distribute locks(ensure the data and other resources distributed among the instance of RAC)
5、 Global cache recources(RAC only)
Enqueues是一个用户序列化访问共用资源的一个本地锁(Enqueues are a locking mechanism for managing access to shared resources)。Enqueues可以生存范围在本实例,也可以在RAC中的,可以有global enqueues。比如Space management enqueues(ST)就是。Enqueues有三种接口:获得,转换或者释放。如果一个enqueues不可用,那么客户层有三种方式来处理,wait indefinitely、wait timeout和nowait。每个Enqueue都有唯一的标识名,就像lock和recource的名一样。Enqueue的标识名遵循以下模式:,其中Type是一个有两个字符的字符串,如TM,ID1和ID2是4个字节的正数。这三个值都可以在v$lock中查到。

SQL> select type,id1,id2 from v$lock where rownum<3;

TY ID1 ID2
-- ---------- ----------
MR 201 0
MR 28 0

enqueue(lock)一共有六种模式: NULL、在共享模式下锁行SS(Row Share)、在专有模式下锁行SX(Row Exclusive)、在共享模式下锁整个表S(Share)、在共享模式下锁表,但有一行是专有模式SSX(Share Row Exclusive)、在专有模式下锁整个表X(Exclusive)。Enqueue几个模式间存在兼容性。
Enqueues是被session所获取,转换和释放,而不是进程。Session可以在processes间迁移,而拥有enqueue的session也可以在processes间迁移。迁移只所以能够容易的实现,主要是借助了状态对象(state objects)。对于每个enqueue,都有自己的锁结构或者资源结构(resource structure),在这个锁结构中维持着owner list、waiter list和converter list。锁和资源表分配在SGA中,资源表的行数由参数enqueue_resources所控制。具体可以通过v$resource来查询。而在enqueue lock表中的行数由_enqueue_locks参数所控制,可以查询v$enqueue_lock而得到具体的信息。Resource and lock structures如下:


Enqueue可能是管理enqueue或者客户端enqueue。主要差别在于锁数据结构的位置。Client enqueue将锁结构数据放在自己的state object中,而managed enqueue是由kernel来分配和控制的。Client enqueues包括DML enqueue(TM)、Transaction enqueu(TX)和User Supplied(UL)。Managed enqueues包括CF(Controlfile Transaction)、PF(password file)、DM(Database Mount)、SQ(Sequence Number enqueue)、JQ(Job queue)、SS(Sort segment)、MR(Media recovery)和ST(Space management transaction)。
即使进程失败,锁结构也可以借助PMON进程从state object中而得到恢复。这就意味着你可以通过system state dump观察其中的详细信息。不同的enqueue类型而言,state objects信息能在enqueue state object 或者client state object中发现。所有的资源结构都是资源表resource table的一部分。为了在资源表中发现资源结构,一个hash算法被使用。资源名resource name被hash成一个索引,然后加入到hash桶中(hash bucket table)。每个hash bucket都有一个hash chain。每个hash chain都被一个或者n个latches所分配。
通过上面关于enqueue resource的描述,我们可以知道,oracle查找一个lock时,需要先在enqueue resource数上查找到该lock的位置。如果每次都在数组上顺序查找,显然效率较低。我们知道hash是一种高效的查找算法,所以oracle对于enqueue resource的查找也采用了hash方式,引入了一个hash数组,其大小由隐含参数_enqueue_hash控制。通过对enqueue的名字进行hash计算,得到的结果就是某个enqueue resource在hash数组中的位置,也就是定位到了具体的hash bucket。如果多个enqueue resource的hash值相同,则在同一个bucket中形成一个链表。相应的,为了保护这个hash数组,需要引入一个latch:enqueue hash chain。该latch有若干个子latch,由隐含参数_enqueue_hash_chain_latches控制。Hasing和Latching的关系如下:

同样的,对于enqueue resource数组中的空闲位置,需要通过一个freelist列表来管理,这样每次在请求新的位置时,不至于要扫描整个数组。enqueue freelist由enqueues latch的保护。实际上,enqueue resource的Hash管理方式,和buffer cache/library cache的管理方式非常的相像。
下面在具体说说几个和enqueue相关的参数。
1、enqueue_resources:enqueue的数据,默认值由数据库数据文件数量、sessions和DML_locks来决定。Oracle server会自动从shared pool中分配,如果指定的数量不够用。
2、 managed enqueue lock structure被参数_enqueue_locks所控制。这个值是由session数量、files、query slaves、lock processes和instance间的信息所计算而得。你可以通过select * from v$resource_limit来查询相关的信息。
3、 hash bucket的数量由单数_enqueue_hash所规定。相关数值的计算方法和enqueue_resource的计算方法相当。
4、 _enqueue_hash_chain_latches,控制hash chain latches的数量。缺省等同于cpu_count。
当一个session没有拥有lock时而想得到lock时,当然,这个session也不存在waiter lists和converter lists中。否则,这个session将在wait queue中等待。要想获得一个lock,步鄹大概如下:
1、 使用hash function,决定那个linked list有需要的resource。
2、 得到相应的enqueue hash chain latch。
3、 定位resource,如果没有free resource structure,把lock放在linked list中。
4、 得到enqueue latch。
5、 获得a free lock structure。
6、 Population it with the correct information for the resource requested
7、 Link the lock structure to the resource structure
8、 Release enqueue latch
9、 Release enqueue hash chain latch
Lock conversersion只有在要求的mode和已经占有者的模式是compatible和subset的情况下发生。Lock release的步鄹如下:
1、 use hash function to determine the linked list
2、 get enqueue hash chain latch
3、 locate the resource
4、 get enqueue latch
5、 unlink lock resource from the resource
6、 link the lock resource to the lock freelist
7、 release enqueue latch
8、 post the next converter or waiter(if only)
9、 possibly unlink the resource structure from the hash chain ,and link it to he resource free list
10、release enqueue hash chain latch
如下用一个图表表示一个enqueue的operations。
Enqueue waits tunning主要是reduce the number of requests and reduce the amount of time the enqueue。
可以使用x$ksgst这个试图得到各个类型lock的gets 和waits。
可以通过v$lock查询系统所有的lock structure,其中的type,id1和id2和v$resource相匹配,Lmode表示lock mode held;Request表示lock mode requested;ADDR:表示address of lock state object;kaddr表示address of lock 。
V$resource中包含系统中被locked的resource structure。其中addr是address of resource object。每行中的数据对应一行或者多行v$lock。
v$locked_object中包含系统中所有在objects上的对象,如TM locks。
使用catblock.sql脚本可以生成一系列数据库字典,如dba_locks、dba_dml_locks、dba_ddl_locks、dba_waiters和dba_blockers。利用utllockt.sql可以生成一个lock tree。

Oracle Latch internals随笔四

确定系统中的常量sql语句(literal sql),它们往往都是可以使用并且应该使用绑定变量的。下面通过查询v$sqlarea视图,列出超过4个执行实例的sql语句的前40个字符,这里假设你的系统中前40个字符相同的语句被认为是没有使用绑定变量的常量sql。很明显,如果使用更长的字符串或者更多的执行实例作为过滤条件,得到的结果sql语句会少很多。然后你可以根据得到的结果,建议程序开发人员对这些常量sql语句尽量使用绑定变量。
SQL>Select hash_value, substr(sql_text,1,80)
from v$sqlarea
where substr(sql_text,1,40)
in (select substr(sql_text,1,40) from v$sqlarea having count(*) > 4 group by substr(sql_text,1,40))
order by sql_text;

如果你的系统中存在大量的常量sql语句,当你将它们改为充分使用绑定变量后,对shared pool latch和library cache latch的争用将会显著减少。更改sql语句,使用绑定变量,这通常需要修改应用程序。另外一个不需要改动应用的方法是,修改初始化参数cursor_sharing,将其值改为similar而不是force,这个参数允许系统对一些只有常量值不一样的sql语句共享游标,以减少latch争用、内存占用和硬分析。
注意:在oracle8i早期版本中,使用cursor_sharing可能导致bug。在使用了物化视图的环境中,请慎用该参数,否则可能导致长久的library cache pin等待。另外,使用cursor_sharing = force可能导致优化器生成错误的执行计划。这或多或少的会对系统性能造成影响。从oracle9i起,优化器可以通过窥视pga中的信息来进行变量绑定,以此生成合适的执行计划,该特性可以通过隐含参数_optim_peek_user_binds来开启,并且该特性只对那些需要硬分析的sql语句有效,这意味着会基于绑定变量的第一个值来生成执行计划。
当一个新的sql语句到达时,oracle首先在库缓存中检查是否已经有相同的语句存在。如果已经存在,则可以花费较小的代价执行该语句,这就是所谓的软分析。硬分析通常意味着较坏的性能,而软分析过多也不是什么好事。在软分析期间,需要持有library cache latch,并且oracle依然需要对语句进行语法和语义检查,除非该语句已经在会话的游标缓存中。你可以通过设置参数session_cached_cursors来减少library cache latch的持有时间。但是,减少软分析的最佳方法还是优化应用程序。最好是分析一次,执行多次(很像java的宣传口号),而不要分析一次,执行一次。你可以通过v$sqlarea的parse_calls列来查找分析过多的sql语句。
过大的共享池也可能引起Shared pool latch争用。从oracle9i起,由于引入了多个子共享池的特性,过大的共享池不再是一种坏事。在9i之前,过大的共享池通常会引起shared pool latch争用。共享池中可用内存分成不同的内存块(chunk),不同大小范围的块由不同的可用列表(freelist)来管理。在共享池中分配空间时,需要扫描可用列表,扫描期间,需要持有shared pool latch。过大的共享池会使得可用列表过长,从而使得shared pool latch的持有时间变长。在高并发环境中,latch持有时间过长就可能造成latch争用(表现为较高的sleeps和misses值),尤其是大量使用常量sql的系统,对这样的系统,不要一味想着加大共享池,更重要的是想一想你为什么会需要保存这么多不能共享的语句到共享池中。
通过alter session set events ’immediate trace name heapdump level 2’可以转存共享池信息,从中可以看到共享池的可用列表信息。在生成的跟踪文件中查找bucket,你可以发现内存块(chunk)分配到不同的bucket上。另外,你也可以通过下面的方法生成一个查询来列出共享池的可用内存管理信息。该查询只要生成一次,就可以在生成该跟踪文件的数据库中重复使用,但不要在其他不同版本的数据库中使用,否则可能得到错误的结果。该查询在oracle10gR1中不可用,因为它限制了case分支数不能超过128(具体信息参考oracle metalink 编号#131557.1和bug号#3503496),或者你可以通过使用decode和sign函数来完成该功能。
SQL> oradebug setmypid
Statement processed.
SQL> oradebug dump heapdump 2
Statement processed.
SQL> oradebug tracefile_name
/u01/oracle/admin/gzwebdb/udump/gzwebdb_ora_10065.trc
SQL>

如果你发现数据库的共享池可用列表过长,并且系统中使用了常量sql,你或许应该考虑减少shared_pool_size。这会降低系统中对shared pool latch的争用。但要注意共享池不能太小,否则可能导致ora-04031错误。另外,通过使用dbms_shared_pool.keep将常用对象钉在内存中也是个好主意,v$db_object_cache中保存了钉在内存中的对象的信息。
语句版本数过多也可能引起Library cache latch争用。对于字符完全一致但是由于引用不同的对象而不能共享的sql语句,oracle使用多个子游标来指向该语句的不同版本。例如,系统中有三个名叫customer的表,但是属于不同的模式。则对于语句select * from customer,不同的模式执行该语句,语句字符上完全一样,其hash值完全一样,但是该语句无法共享,因为它引用的对象不同。所以会生成该语句的不同子版本。当一个sql语句有多个子版本时,oracle需要比较该语句的所有存在的子版本,在此期间需要持有library cache latch,这样可能导致library cache latch争用。解决这种情况也很简单,在系统中,尽量不要使用相同的对象名。下面的查询列出了v$sqlarea中子版本超过20的所有sql语句:
SQL>Select version_count, sql_text from v$sqlarea where version_count > 20 order by version_count, hash_value;
注意:在oracle8i中,语句的版本过多,可能导致和sql执行监控相关的bug(参考oracle metalink 编号#62143.1)。这个bug会导致sql无法共享。可以通过将隐含参数_sqlexec_progression_cost设置为0来禁用sql执行监控特性,该参数同时会禁止v$session_longops中的数据。Oracle提供了视图v$sql_shared_cursor,其中可以看到为什么无法共享一个已经存在子游标。每个列都限制了游标无法共享的一个原因。
下面来介绍下Cache buffers lru chain latch。除了hash chain,缓冲头同样组成一个列表,这个列表指向其他的列表比如lru,lruw和ckpt-q。Lru和lruw列表并不是什么新东西,他们是数据缓冲区中最早的两个链表。Lru列表包含了不同状态的缓存块,而lruw就是俗称的“脏表”,只包含脏数据块。Lru和lruw列表是互斥的,他们合称一个工作集(a working set)。每个工作集由一个cache buffers lru chain latch保护。换句话说,数据缓冲区中工作集的个数是由cache buffers lru chain latch的个数决定的。通过内部视图x$kcbwds (kernel cache buffer working sets descriptors)可以知道工作集的个数。我们注意到x$kcbwds 的set_latc的值就是v$latch_children的addr列。
SQL> Select set_id, set_latch
from x$kcbwds
order by set_id;

一般来讲,当进程需要查找可用的缓存空间时,需要访问lru列表。后台进程DBWn则会将lruw列表中的干净块移到lru列表中,也会将lru中的脏块移到lruw列表中。在一个工作集中进行以上的任何操作都需要先获得cache buffers lru chain latch。
各个数据缓冲区中(包括不同块大小的缓冲区,keep池和recycle池),每个缓冲区至少需要有一个cache buffers lru chain latch,而一个DBWn进程可能需要多个latch。否则,一个工作集就可能变得很长。在oracle9i和oracle10g中,cache buffers lru chain latch的个数默认是cpu个数的4倍,如果,db_writer_processes大于4,则等于cpu的个数乘以db_writer_processes。可以通过隐含参数_db_block_lru_latches来调节cache buffers lru chain latch的个数。Cache buffers lru cahin latch的争用,主要表现为由于低效的sql语句导致数据缓冲区过度活跃。全表扫描和对某些选择性较差的大索引的反复扫描是造成cache buffers lru cahin latch争用的主要原因。解决办法是,查找latch free等待事件中关于cache buffers lru chain latch相关的sql语句(在oracle10g中,已经变成一个独立的cache buffers lru chain等待事件),优化这些sql,降低其物理读和逻辑读。
下面来关注Row cache objects latch。Row cache objects latch用来保护数据字典缓冲区(row cache的名字主要是因为其中的信息是按行存储的,而不是按块存储)。进程在装载、引用或者清除数据字典缓冲区中的对象时必须获得该latch。在oracle8i之前,这是一个独立latch。从oracle9i起,由于引入了多个子共享池的新特性,存在多个row cache objects子latch。Oracle10g中,该latch也有了一个独立的等待事件:row cache objects。
从oracle7.0起,数据字典缓冲成为了共享池的一部分。而在7.0之前,每个数据字典对象都是由独立的dc_*初始化参数控制。Oracle7.0的这个改变也意味着,不能再直接的调整数据字典缓冲,而只能通过调整shared_pool_size来间接的调整。V$rowcache视图包含了每个数据字典对象的统计信息。你可以通过下面的查询发现最热的数据字典对象。对数据字典缓冲区的调节手段是有限的。最好的办法是降低对前面的查询结果中一些热点数据字典对象的访问。举个例子,如果对某些sequence访问频繁,可以将考虑将这些sequnce缓存在内存中。包含多个基表连接或者基于视图的视图可能导致该latch争用。一般的解决办法是增加shared_pool_size的值。
SQL>Select cache#, type, parameter, gets, getmisses, modifications mod
from v$rowcache
where gets > 0
order by gets;

Oracle Latch internals随笔三

要分析一个latcha free事件,其中一个办法就是检查statspack report。首先我们应该看wait events waited fro by the foreground processes。例如:

Wait Events for DB: GDDB1 Instance: gddb1 Snaps: 127 -128
-> s - second
-> cs - centisecond - 100th of a second
-> ms - millisecond - 1000th of a second
-> us - microsecond - 1000000th of a second
-> ordered by wait time desc, waits desc (idle events last)
Avg
Total Wait wait Waits
Event Waits Timeouts Time (s) (ms) /txn
---------------------------- ------------ ---------- ---------- ------ --------
latch free 97 14 73 749 0.0
log file sync 7,458 16 29 4 0.6
db file parallel write 863 0 22 26 0.1
log file parallel write 7,456 7,433 9 1 0.6
control file parallel write 1,484 0 6 4 0.1
db file sequential read 865 0 4 5 0.1
ARCH wait on SENDREQ 100 0 3 29 0.0
async disk IO 106 0 0 2 0.0
SQL*Net more data to client 19,083 0 0 0 1.5
direct path write 56 0 0 3 0.0
log file sequential read 66 0 0 2 0.0
direct path write (lob) 1,888 0 0 0 0.2
control file sequential read 4,365 0 0 0 0.3
direct path read (lob) 5,637 0 0 0 0.5
buffer busy waits 18 0 0 1 0.0
db file scattered read 3 0 0 2 0.0
enqueue 1 0 0 6 0.0
log file single write 4 0 0 0 0.0
direct path read 56 0 0 0 0.0
LGWR wait for redo copy 1 0 0 0 0.0
SQL*Net message from client 322,043 0 43,011 134 25.8
PX Idle Wait 4,320 4,320 8,603 1991 0.3
SQL*Net message to client 322,044 0 0 0 25.8
SQL*Net more data from clien 4,371 0 0 0 0.3

然后观察Latch Activity部分。这里主要描述那些特定的事件为瓶颈。Pct Misseses对于willing-to-wait和no-wait latches应该接近为0.0。
Latch Activity for DB: GDDB1 Instance: gddb1 Snaps: 127 -128
->"Get Requests", "Pct Get Miss" and "Avg Slps/Miss" are statistics for
willing-to-wait latch get requests
->"NoWait Requests", "Pct NoWait Miss" are for no-wait latch get requests
->"Pct Misses" for both should be very close to 0.0
Pct Avg Wait Pct
Get Get Slps Time NoWait NoWait
Latch Requests Miss /Miss (s) Requests Miss
------------------------ -------------- ------ ------ ------ ------------ ------
session timer 736 0.0 0 0
shared pool 774,157 0.0 0.0 0 0
sim partition latch 0 0 31 0.0
simulator hash latch 42,279 0.0 0 0
simulator lru latch 178 0.0 0 309 0.0
sort extent pool 43 0.0 0 0
transaction allocation 642 0.0 0 0
transaction branch alloc 35 0.0 0 0
undo global data 28,014 0.0 0.0 0 0
user lock 186 0.0 0 0

接下来看看Latch sleep breakdown statspack section report部分。主要报告那些latch被服务器进程spinning和sleeping。这个部分是用Misses来排序的,但我们主要关注sleeps的统计信息。
Latch Sleep breakdown for DB: GDDB1 Instance: gddb1 Snaps: 127 -128
-> ordered by misses desc

Get Spin &
Latch Name Requests Misses Sleeps Sleeps 1->4
-------------------------- -------------- ----------- ----------- ------------
library cache 1,042,559 506 64 443/62/1/0/0
shared pool 774,157 384 16 368/16/0/0/0
cache buffers chains 1,731,469 44 14 0/0/0/0/0
redo allocation 137,179 21 3 18/3/0/0/0

下面用这个例子说明如果跟踪到当cache buffers chains sleeps显著时,出现的所谓“热点块”(hot blocks)。
1、创建两个临时表,用来装载sleeps统计信息。
SQL> create table sleep_buf_chains_a as
2 select addr,child#,sleeps
3 from v$latch_children
4 where name='cache buffers chains';

Table created.
等待20秒后,在创建一个临时表。
SQL> create table sleep_buf_chains_b as
2 select addr,child#,sleeps
3 from v$latch_children
4 where name='cache buffers chains';
2、Join两个表,两个表最近的sleeps的差异,然后在排序。最后两行数据应该是所谓的热点数据块。
SQL> select a.addr,a.child#,
2 (b.sleeps-a.sleeps) sleeps
3 from sleep_buf_chains_a a,sleep_buf_chains_b b
4 where a.addr=b.addr
5 and sleeps >0
6 order by sleeps;
例如得到如下数据:
Addr chile sleeps
901135FC 1871 178
900BF5FC 335 179
9010AD7C 1715 208
901064DC 1632 215
9010615C 1628 294

3、使用x$bh试图得到实际的热点块。
Select hladdr,tch,ts#,file#,dbablk, class,
Decode(state, 2,'shared current',
3, 'cr version',
1, 'exclusive current',0)
From x$bh
Where hladdr in('9010AD7C','901064DC','010615C') and tch >100
Order by tch,hladdr,dbablk;

HLADDR TCH TS# FILE# DBABLK CLASS ECODE(STATE,2,'S
-------- ---------- ---------- ---------- ---------- ---------- -----------------
9010AD7C 129 11 17 6800 1 shared current
9010AD7C 137 1 2 9 17 0
9010AD7C 193 7 7 20721 1 shared current
9010AD7C 350 7 7 10481 1 shared current
9010AD7C 403 14 25 61469 9 0
9010AD7C 459 10 14 6960 1 shared current
901064DC 973 14 22 18538 1 exclusive current
9010AD7C 2543 14 22 18621 1 exclusive current

8 rows selected.
4、依据上步中查到的file_id和block id,查询dba_extents得到实际的相应的对象。查询dba_segment可以得到freelist的数量,增加这个数值,可以减少相应的数据块竞争。
SQL> col SEGMENT_NAME format a25
SQL> select segment_name,segment_type,owner,tablespace_name
from dba_extents
where file_id=22
and 18621 between block_id and (block_id +(blocks-1));

SEGMENT_NAME SEGMENT_TYPE OWNER TABLESPACE_NAME
------------------------- ------------------ ------------------------------
SYS_IL0000006840C00003$$ LOBINDEX MAILCONTENT MAILCONTENT

SQL> select segment_name,segment_type,owner,tablespace_name
from dba_extents
where file_id=7
and 20721 between block_id and (block_id +(blocks-1));

SEGMENT_NAME SEGMENT_TYPE OWNER TABLESPACE_NAME
------------------------- ------------------ ------------------------------
PK_EMAILID_MAILID INDEX MTAMANAGER MTAINDEX

使用v$session_event和V$system_event试图可以得到一个累计统计信息,而v$session_wait可以道道实时的等待信息,其中P1为Latch地址(latch address),P2为Latch号(latch number)。还有一些有用的试图v$latch_misses、v$latch、v$latch_parent、v$latch_children、v$latchholden和v$latch_misses。如:
SQL> select distinct l.name "latch" from v$session_wait s, v$latch l
where s.p2=l.latch#
and s.event='latch free'
and s.wait_time=0;
一些需要特别注意的latches,比如cache buffers chains、row cache objects、redo copy、library cache、shared pool、cache buffers LRU chain和redo allocation。
当latch在系统范围内的等待时间比较显著时,你可以通过v$latch中的sleeps列来发现争用显著的latch。
SQL>Select name, gets, misses, immediate_gets, immediate_misses, sleeps
from v$latch
order by sleeps desc;

shared pool 2516471776 2851975 0 0 127747
cache buffers chains 12028546317 222992 77269891 78814 31983
library cache 2739913072 1780652 89077598 325519 19093

对于不同的latch,其产生的原因以及可采取的对策都有所不同。详细的说明所有的latch可以写成一本书了。这里我们只选择最常见的五个latch加以说明:shared pool, library cache, cache buffers chains, cache buffers lru chain和row cache objects。
Shared pool 和 library cache latch的争用,有可能是由于硬分析造成。Oracle的共享池由不同的结构组成。主要包括:数据字典缓存,sql区和库缓存。通过v$sgastat你可以查看其他一些结构。Shared pool latch主要用来保护共享池的内存结构,当分配或者释放共享池内存时需要先获得该latch。例如,为一个新的sql语句或pl/sql过程、函数、包,触发器等分配空间(硬解析)时,或者为换出、清除某些内存块,以便为新的对象腾出足够的空间时,都需要获取shared pool latch。
在oracle9i之前,共享池内存结构由一个独立shared pool latch保护,从9i开始,则有最多7个子latch可以用于共享池的保护。这也是为什么oracle9i可以将共享池分成多个子共享池的原因(服务器至少需要4颗cpu,并且shared_pool_size大于250m才能使用多个子共享池的特性)。子共享池的个数可以通过隐含参数_kghdsidx_count手动调节,该参数同时会指定合适的shared pool子latch的个数。如果你手动增加子共享池的个数,你应该同时增加shared_pool_size的值,因为每个子共享池都有自己的结构,lru列表和shared pool latch。否则,实例启动时可能会遇到以下错误:
Ora-04031: unable to allocate 32 bytes of shared memory ("shared pool","unknown object","sga heap(5,0)","fixed allocation callback").
下面的统计信息是从一个4颗cpu,shared_pool_size为256m的oracle9i数据库中读取的。由_kghdsidx_count参数可知共享池被分成2个子池,通过x$kghlu(kernel generic heap lru)可以知道lru列表也有2个。v$latch_children视图显示了7个子latch中的2个已经被使用。
SQL>Select a.ksppinm, b.ksppstvl
from x$ksppi a, x$ksppsv b
where a.indx = b.indx
and a.ksppinm = '_kghdsidx_count';
通过以下语句可以查处LRU列表。
SQL> select addr, kghluidx, kghlufsh, kghluops, kghlurcr, kghlutrn, kghlumxa from x$kghlu;

ADDR KGHLUIDX KGHLUFSH KGHLUOPS KGHLURCR KGHLUTRN KGHLUMXA
-------- ---------- ---------- ---------- ---------- ---------- ----------
B79E8450 2 40452680 565459699 26231 69949 2147483647
B79E745C 1 48896624 531238837 20427 60700 2147483647


Shared pool和library cache latch争用通常是由于硬分析引起。硬分析需要分配新的游标,或者将已经换出的游标重新执行。硬分析过多说明sql语句没有充分绑定变量。硬分析是代价十分昂贵的操作,在分析期间需要一直持有ibrary cache latch。通过下列查询可以发现系统中是否存在大量硬分析。软分析数则可以用总分析数减去硬分析数获得。
SQL>Select a.*, sysdate-b.startup_time days_old
from v$sysstat a, v$instance b
where a.name like 'parse%';
STATISTIC# NAME CLASS VALUE DAYS_OLD
---------- ------------------------- ---------- ---------- ----------
230 parse time cpu 64 4146221 177.90375
231 parse time elapsed 64 4595596 177.90375
232 parse count (total) 64 152359500 177.90375
233 parse count (hard) 64 29918794 177.90375
234 parse count (failures) 64 369 177.90375

备注:分析失败可能是由于“ora-00942: table or view does not exist”错误或者共享内存不足。

查看当前会话是否有大量硬分析的语句。
SQL> Select a.sid, c.username, b.name, a.value,
round((sysdate - c.logon_time)*24) hours_connected
from v$sesstat a, v$statname b, v$session c
where c.sid = a.sid
and a.statistic# = b.statistic#
and a.value > 0
and b.name = 'parse count (hard)'
order by a.value;

SID USERNAME NAME VALUE HOURS_CONNECTED
---------- --------------- ------------------------- ---------- ---------------
45 GZYW parse count (hard) 12 4
30 GZYW parse count (hard) 16 4
82 MTAMANAGER parse count (hard) 36 4
16 parse count (hard) 112 4270
32 MAILCONTENT parse count (hard) 137 1
85 MAILCONTENT parse count (hard) 292 0
61 MAILCONTENT parse count (hard) 354 1
72 MAILCONTENT parse count (hard) 472 0
46 MAILCONTENT parse count (hard) 504 0
24 MAILCONTENT parse count (hard) 625 0
31 MAILCONTENT parse count (hard) 668 0

SID USERNAME NAME VALUE HOURS_CONNECTED
---------- --------------- ------------------------- ---------- ---------------
75 MAILCONTENT1 parse count (hard) 1271 0
15 parse count (hard) 4149 4270

在oracle10g中,通过v$sess_time_model视图中对硬分析和失败分析的时间统计信息,可以知道硬分析的来源。

星期四, 五月 24, 2007

Oracle Latch internals随笔二

如果经过一个完整的旋转,这个Latch仍然不可以用,那个请求进程就会首先放弃对cpu的请求而去sleep。一个sleep就对应一个Latch free的等待事件。开始,这个sleep时间会是一个厘秒(one centisecond)。这个时间会以双指数的增长方式去增加直到参数_MAX_EXPONENTIAL_SLEEP所规定的,一般是2秒。通常调整_SPIN_COUNT这个值没有什么大的作用,过度的latch竞争通常都是差的程序设计的结果。此外就是我前面提到的_SPIN_COUNT只对多CPU的系统有用。这个参数只会在其他tunning方法已经用完,而又有足够的CPU带宽时,才考虑增加这个值。
通常latch只能被短暂的拥有,成功的spin能够节省CPU时间,当然这个只对多CPU环境有意义。这里有人会问为什么要SPIN,为什么不直接休眠等待?这里要明白休眠意味着什么,他意味着暂时的放弃CPU,进行上下文切换(context switch),这样CPU要保存当前进程运行时的一些状态信息,比如堆栈,信号量等数据结构,然后引入后续进程的状态信息,处理完后再切换回原来的进程状态,这个过程如果频繁的发生在一个高事务,高并发进程的处理系统里面,将是个很昂贵的资源消耗,所以他选择了spin,让进程继续占有CPU,运行一些空指令,之后继续请求,继续spin,直到达到_spin_count值,这时会放弃CPU,进行短暂的休眠,再继续刚才的动作,Oracle软件就是这么设计的。
Latch的获取,可以说遵从下面的规律Fast get –spin—sleep—spin—sleep—spin—sleep--,所以有两种情况,其中一个是Latch能以no-wait(no spin or sleep)的模式去获取。如有很多的redo copy latches,如果一个进程需要这个latch,它首先是以no-wait模式去请求。如果一个进程第一次获取这些子latch中的任何一个失败,它会立即使用no-wait模式询问下一个。只有当采用no-wait模式试图获取所有的子latch都失败以后,才会转而采用willing-to-wait模式。另外一个是借助level rule,每个latch都有自己的level。为了防止死锁,请求者只能请求level比现在拥有者高的latch。如果这个latch的请求是一个低的level,那么其中的一个方法就是释放现在被占有的latch,然后请求者以一个适当的顺序去获取。另外一种就是willing-to-wait模式,大多数latch都是短等待latch,所以,进程请求latch时不会等待太长的时间。Oracle进程请求latch失败而导致进入睡眠状态,每次睡眠时间按双指数队列增长,比如睡眠时间可能像下面的队列一样:1,1,2,2,4,4,8,8,16,16,32,32,64,64(厘秒)……,最长的睡眠时间由隐含参数_max_ exponential_sleep,默认2秒。但是如果一个进程当前已经持有其他的latch,则最长睡眠时间会减少为_max_sleep_holding_latch,默认值4厘秒。这样,如果一个进程已经持有latch,就不允许睡眠太长的时间,否则可能会使其他等待该进程所持有的latch的进程的等待时间过长。
如果请求该latch的进程进入睡眠状态,需要其他进程来唤醒,这会产生一个latch wait posting等待事件,该行为由隐含参数_latch_wait_posting控制。在oracle8i,只有2个长等待latch,_latch_wait_posting参数从oracle9i起已经废弃,使用latch wait posting的latch的统计信息被记录在waiters_woken列中,这个数值就等于唤醒Post的次数。这个只是对于长等待latch而言。这里也要引入一个概念锁存器等待链表latch wait list。Latch的释放机制需要唤醒第一个为次latch而等待进程。比如说library chace、shared pool、library cache load lock。那些为此而等待进程是由一个串连waiter的链表(锁存器等待链表latch wait list)所保护。如果占有latch的进程死了,PMON进程会清理该进程和释放latch。如果这个占有者还活着,那就存在latch争用的情况或者操作系统调度有问题。

----------------------------------------------待续-----------------------------------------------------

Oracle Latch internals随笔一

仅以本文来总结和复习Oracle Interals,并结合实际工作中的经验,让自己对Oracle的Latch有一个更清楚的认识。
首先,我们要知道什么是Latch,用Latch的目的是什么。下面我们就来探讨下Latch的相关概念及内部信息。Latch是用来保护内存资源的一个轻量级的锁。主要目的有两点:
1、 串行化访问(To serialize access),保护SGA中的数据结构和共享内存的分配。
2、 串行化执行(To serialize execution),防止同时执行特定重要代码,防止数据结构的损坏.
借用排他性的Latch,进程能够阻止其他进程对有这个Latch保护的数据结构的读和写。由此看出Latch对内存数据结构提供一种互斥访问机制。在没有一致性读机制的情况下,先期读取者会阻止修改者。在没有Shared Latch在相关平台的情况下,先期读取者也会阻止其他访问者。如果Latch的持有者进程意外终止,那么会有一个相关的清除机制会处理这个情况。通常这个工作是有PMON进程来restore和clean up。而其中关于这个Latch的undo information一般典型的存在SGA状态对象(SGA state objects)中。常见的Latch一般有shared pool latch、session allocation latch(负责保护在variable SGA 中的session state object的分配)、cache buffers lru chain latch(负责保护在LRU lists中Buffer headerd 分配和移动)。
Oracle server允许对象同时以共享的模式区使用队列(equeue)。而Latch用来保护大的数据结构或者被高频率访问的结构,由此Latch都是排它性的,并且存在时间很短的特点,对性能和并发用户的可用性的影响降到最低。在请求enqueue时,如果一个进程没有被授权,那一般是因为请求模式和现有的模式不够兼容,O/S就会把请求进程放在一个FIFO模式的等待队列(wait queue)中。而对于Latch的请求,Latch waitesr一直按顺序提交请求。
特殊情况下,Oracle server请求在一个大数据结构(large stucture)上的Latch,在一个相对长的时间内为了安全访问以及锁定小子数据结构(smaller sub-structure)时,需要利用复杂的像enqueues的锁机制。比如,在更新一个row时,Oracle server会得到一个cache buffers chains latch去搜索hash chain,此过程主要是为了在data buffer中找到那个data block。然后pins住这个block,然后释放cache buffers chains latch。然后Oracle server会lock这个数据块中的row,修改行,然后unpins这个block。到目前为止,这个row仍然被lock in exlusive mode至到事务结束。Lock row不会影响block中的其他数据和在cahe中的其他buffers。
虽然Latch的使用是在操作系统级别,但是平常是作为一个内存位(single memory location)去操作。Latch free时为0,Latch not free时为一个非0。这个内存位经常增加到32个字节,为了避免在硬件级别上的Cache line竞争。Latch被设计成一个fast和inexpensive的锁。Latch真实操作依靠于操作系统。对于shared latches不是很广泛的被使用。这种类型的锁主要是用于高级队列代码(Advance Queuing code)。存在一种机制可以让进程什么时候,以如何方式获得Latch,而不发生死锁。
Latch可以是独立Latch(solitary Latch),也可以是Latch集(Latch set)。Latch set有父Latch和多个子Latch组成。独立Latch和父Latch是静态分配的,而子Latch是动态分配的。父Latch和子Latches有相同的名字。父Latch做为控制Latch(master latches)。Latch具有级别的特性(Levels),利用这个优先级可以避免死锁。父Latch在数量上是固定的,应该在相关代码中所定义。从Oracle9R2开始,有了不同类型的父Latch,但每个类型只有一个父latch。子Latch是依据相关参数(比如_CPU_COUNT)设定或者默认值动态分配的。父Latch一般只作为聚合统计之用,但library cache是个例外。如Solitary Latches:shared pool,redo allocation;PAR Latches:cache buffers lru chain、cache buffers chains;PR2 Latches:library cache。当一个进程请求no-wait模式的latch时,该latch的优先级编号必须和它当前已经持有的latch的优先级编号相同。当一个进程请求willing-to-wait模式的latch时,该latch的优先级编号必须比它当前已经持有的latch的优先级编号要大。
Latch是在操作系统中以某种方式来执行。如果一个latch真在被占用,那边requestor spins and tries agin,in a loop up to _SPIN_COUNT number of time。for single CPU systems _SPIN_COUNT=1。如果在一个单cpu的环境下,一个进程持有一个Latch,但它没有释放这个latch,那就没有必要去spin了。否则,当cpu的数量大于1,那么_SPIN_COUNT的默认值是2000。

-------------------------------------------------待续-----------------------------------------------------------------------

星期三, 五月 16, 2007

spfile参数文件的搜索顺序及随笔

spfile参数文件的搜索顺序
$ORACLE_HOME/dbs
1、spfile$ORACLE_SID.ora
2、spfile.ora
3、init$ORACLE_SID.ora
可以在数据库shutdown时,也可以创建和修改spfile。
spfile是一个二进制文件,也可以用Rman进行备份。
可以使用pfile文件,在pfile文件中使用spfile标签联到相应的spfile文件。
判断是否使用了spfile参数,可以使用show parameter spfile
从rman备份集中恢复spfile 和controlfile。
restore spfile to '' from autobackup;
restore controlfile to '' from autobackup;


共享服务器和专用服务方面随笔

共享服务器就是一个链接池机制。MTS模式与专用服务器模式之间一个最大的区别是:连接到数据库的客户端进程决不能和共享服务器直接对话,而专用服务器可以,不能与共享服务器对话是因为进程实际上是共享的。为了共享进程,就产生了一组分配器的进程dispatcher。客户端首先发送一个请求,服务器端的dispatcher收到请求,dispatcher首先把请求放在SGA中的请求队列,一个可以提供服务的共享服务器将请求取出,并且处理它。然后将结果放到响应队列中,并且随后由dispatcher选择。除非系统是超负荷的,或者为了特定需要而使用MTS,否则专用数据库是合适的。如果要使用专用服务器进行部署,那么相关的开发和测试都应该在共享服务上进行。

如果已经在应用程序中使用了连接池的概念。并且已经合适的定义了连接池的大小。那么MTS的应用将会得到抑制。

星期二, 五月 15, 2007

oerr的使用方法

[oracle@odex1 ~]$ oerr
Usage: oerr facility error

Facility is identified by the prefix string in the error message.
For example, if you get ORA-7300, "ora" is the facility and "7300"
is the error. So you should type "oerr ora 7300".

If you get LCD-111, type "oerr lcd 111", and so on.
[oracle@odex1 ~]$ which oerr
/u01/oracle/ora920/bin/oerr
[oracle@odex1 ~]$ oerr ora 6000
06000, 00000, "NETASY: port open failure"
// *Cause: Autologin unable to open port
// *Action: Check log file for OS-specific error code
[oracle@odex1 ~]$ oerr ora 600
00600, 00000, "internal error code, arguments: [%s], [%s], [%s], [%s], [%s], [%s], [%s], [%s]"
// *Cause: This is the generic internal error number for Oracle program
// exceptions. This indicates that a process has encountered an
// exceptional condition.
// *Action: Report as a bug - the first argument is the internal error number
[oracle@odex1 ~]$

[oracle@odex1 ~]$ oerr ora 1102
01102, 00000, "cannot mount database in EXCLUSIVE mode"
// *Cause: Some other instance has the database mounted exclusive or shared.
// *Action: Shutdown other instance or mount in a compatible mode.
[oracle@odex1 ~]$

DB_NAME、INSTANCE_NAME、ORACLE_SID、ERVICE_NAME、DB_DOMAIN、GLOBAL_DB_NAME概念

数据库名(DB_NAME):是区分数据的内部标识,在数据库多处保存,并且控制文件中保存是二进制的,所以很难改变其名字。在pfile/spfile中的db_name。数据库名主要用于内部标记。在控制文件、数据文件、日志文件和数据库备份与恢复时都要用数据库名。如alter database时都是使用该数值查看: show parameter db_name 或者查v$database视图。并且DB_NAME必须是一个不超过8个字符的文本串.在数据库创建过程中,db_name被记录在数据文件,日志文件和控制文件中。如果数据库实例启动过程中参数文件中的db_name和控制文件中的数据库名称不一致,则数据库不能启动。
实例名实例名(Instance_name):用于和操作系统间联系(对外连接使用),一个数据库可以有多个实例(如RAC)。要和一个数据库服务器相连,必须知道其实例名,光知道数据库名是没用的。在spfile/pfile中有instance_name参数,其实一般设置与数据库名称是相同的。instance_name最多应该支持21个字符。
INSTANCE_NAME与ORALCE_SID区别:都是指数据库实例名,但ORACLE_SID是操作系统的环境变量设置,用于和操作系统交互,其取值必须与INSTANCE_NAME相同,而INSTANCE_NAME可在参数文件中查到。
一个实例可以mount并打开任何数据库,但是同一时间一个实例只能打开一个数据库。一个数据库可以被一个或多个实例所mount并打开(在OPS/RAC环境下,一个数据库可以被多个实例所打开)。
数据库域名:类似网络域名的概念,(所以一个数据库名db_name在不同的域里可以相同)在安装时确定(全局数据库名中填写),定义规则也相似于网络定义。参数文件中db_domain就是数据库域名。全局数据库名:=db_name+db_domain。
数据库服务名(SERVICE_NAMES);这可不是你在客户端配置的网络服务的概念,这是数据库本身的概念,定义为=全局数据库名。从oracle9i版本开始,引入了一个新的参数,即数据库服务名。参数名是SERVICE_NAME。如果数据库有域名,则数据库服务名就是全局数据库名;否则,数据库服务名与数据库名相同。查询数据库服务名select value from v$parameter where name = 'service_name';或者show parameter service_name

星期五, 五月 11, 2007

ORA-01093:验证和解决过程

在将备用数据库从只读模式转换到管理恢复模式时,出现如下错误
[oracle@casdbbak ~]$ sqlplus /nolog
SQL*Plus: Release 9.2.0.4.0 - Production on Thu May 10 18:03:57 2007
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
SQL> conn / as sysdba;
Connected.
SQL> alter database recover managed standby database disconnect from session;
alter database recover managed standby database disconnect from session
*
ERROR at line 1:
ORA-01093: ALTER DATABASE CLOSE only permitted with no sessions connected
通过检查oracle alert文件,发现Active process 20009正在连接到备用数据库上,验证方式如下
Thu May 10 18:04:08 2007
alter database recover managed standby database disconnect from session
Thu May 10 18:04:08 2007
Active process 20009 user 'oracle' program 'oracle@casdbbak (TNS V1-V3)'
CLOSE: 1 or more sessions failed to shutdown.
Active process 20009 user 'oracle' program 'oracle@casdbbak (TNS V1-V3)'
CLOSE: Active sessions prevent database close operation
CLOSE: Error 1093 during database close
ORA-1093 signalled during: alter database recover managed standby database d...
SQL> host
[oracle@casdbbak ~]$ ps -ef
oracle 20009 20006 0 16:55 ? 00:00:00 oraclegdcas (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))

星期三, 五月 09, 2007

梳理知识点,使知识条理话

在接下来的日子,想通过以点带面的方式,整理下Oracle的相关知识点,并且延伸到操作系统、脚步的编写、存储系统、San的存储架构的一些知识点。其后会以文档的形式来发布,结合自己实际的工作经验,借助别人的思路来完成。比如在数据库方面会有RAC、Dataguard、Rman等方面的专题文章;在操作系统方面会有Redhat Linux方面的一些常用命令以及Shell Scripts的编写;在San方面会介绍一些自己接触到的存储以及它们的使用情况。

Crontab脚本连续数日没有执行的解决

在检查备份日志的工程中,发现rmanbk.sh 数日都没有执行,
(1)、看脚本的权限正确
[oracle@gzdbbak worksh]$
ll -l rmanbk.sh -rwxr-xr-x 1 oracle dba 938 Apr 23 14:34 rmanbk.sh
(2)、crontab设置也没有问题
[oracle@gzdb logs]$ crontab -l#
0 3 * * * /home/oracle/worksh/rmanbk.sh >> /home/oracle/logs/rmanbk.log 2>&1
(3)、/var/log/messages中抛出信息
May 3 03:00:01 casdb crond[25048]: Authentication token is no longer valid; new one required.
经过分析,原来系统管理员设置了Oracle账户密码过期的策略,所以才导致Crontab不能够正常执行。让系统管理员重新设置了Oracle账户密码后,crontab脚本就执行没有问题。

星期二, 五月 01, 2007

Brocade SilkWorm4100 光纤通道交换机Zone管理实录

在主机使用存储的过程中,一般都会遇到在光纤通道交换机上创建Zone,避免数据流之间的干扰,尤其在作Oracle Rac中肯定要这样做,不然会有一些意想不到的问题,我就遇到过这样的情况。
Zone的创建
1、创建ZONE
zonecreate"H60_1_6920A_31","1,1;1,8"
2、创建cfg配置文件
cfgadd"sw4100cfg","H60_1_6920A_31"
3、激活配置文件
cfgenable"sw4100cfg"
cfgsave

Zone的删除
(1).zonedelete “H41_1_6920B_31”
(2) cfgremove “sw4100cfg”,” H41_1_6920B_31”
(3) cfgenable “sw4100cfg”
(4) cfgsave

在Redhat上如何应用存储Sun6920

1、在Linux主机上初次识别或增删存储卷在正常情况下需重启主机,但也可以通过删除和重新加载HBA模块来进行。
在HBA卡未在使用时可直接删除和重新加载,若是新增或删除原有的卷就需把当前正在使用的卷(文件系统)停止相关应用和umount后才能操作。具体步骤如下:
1) lsmod 显示当前的系统模块,找出HBA对应的模块
2) rmmod qla2300 删除HBA模块
3) rmmod qla2xxx 删除HBA主模块
4) lsmod 察看要删除的模块是否已删除
5) modprobe qla2300重新加载HBA模块(系统会自动加载相应得qla2xxx模块)
6) lsmod 再次查看HBA模块是否已重新加载起来
7) sfdisk 用系统命令看是否有新的sdx 设备增加,可同时显示容量进行判断
8) scsi_id -g –s /block/sdx 用系统命令察看sdx 设备的WWN号,可与上述的存储与主机对应表中找出对应得卷
9) 在判断出sdx设备对应关系后即可对新增的盘(卷)进行使用,如建立文件系统、配置MDADM多路访问等。

2、配置多路访问
每台数据主机都安装有2块HBA卡,为达到同时识别存储的盘和通道故障冗余,需安装配置多路软件来管理。
mdadm是linux内部提供的用来管理多路径存储环境下的功能,该功能用来将主机到存储之间的多路径进行识别,同时提供多通道之间的通道故障切换功能。
具体实现MDADM的配置如下:
1) lssd 用系统命令来查看2张HBA卡上的卷信息
sda 0,0,0,0 SUN SE6920 0202 2231-0001-5d04-d300
sdb 0,0,1,0 SUN SE6920 0202 2231-0001-5d05-5c00
sdc 0,0,2,0 SUN StorEdge 3511 413C 2160-00c0-ff89-23b9
sdd 1,0,0,0 SUN SE6920 0202 2241-0001-5d04-d300
sde 1,0,1,0 SUN SE6920 0202 2241-0001-5d05-5c00
sdf 1,0,2,0 SUN StorEdge 3511 413C 2560-00c0-ffc9-23b9

2)如上显示当前系统通过HBA卡识别到6个盘,由于是2张HBA卡同时识别到相同的存储卷,所以实际只有3个盘。由上显示的第2列HBA卡通道ID号可以分别出前三行是第1张光纤卡开头是“0”,后三行是另一张光纤卡卡头是“1”。再从最后一列的存储节点WWN号可以判断出sdx设备的对应关系,如sda和sdd的设备都是“2231-0001-5d04-d300”,就是6920A的节点WWN。由此可以判断出6个设备在2张光纤卡中的对应关系。
sda、sdd对应6920A
sdb、sde对应6920B
sdc、sdf对应3511

3)还可以进一步确认盘的对应关系,确保无误:
#scsi_id -g –s /block/sda
3600015D00004D3000000000000000795
#scsi_id -g –s /block/sdd
3600015D00004D3000000000000000795
同样对sdb、sde和sdc、sdf操作
可以看出sda、sdd的卷WWN是相同的,此时的对应关系可确保无误了。


4)建立MDADM设备,系统初期在/dev目录下已存在md0-md19共20个MDAMD设备名,是一个系统连接影射关系,可用于建立软RAID和多路经使用,可根据主机的盘数和习惯规则选择使用。如对sda、sdd两路相同的卷创建md1,操作如下:
#mdadm -C /dev/md1 -l multipath -n2 /dev/sda /dev/sdd
Md1已创建
创建情况可通过#mdadm –D /d/ev/md1察看
/dev/md1:
Version : 00.90.01
Creation Time : Fri Feb 17 12:20:41 2006
Raid Level : multipath
Array Size : 209715136 (199.100 GiB 214.75 GB)
Raid Devices : 2
Total Devices : 2
Preferred Minor : 1
Persistence : Superblock is persistent

Update Time : Tue Feb 21 08:58:32 2006
State : clean, degraded
Active Devices : 1
Working Devices : 1
Failed Devices : 1
Spare Devices : 0

Number Major Minor RaidDevice State
1 8 48 1 active sync /dev/sda
2 8 0 -1 active sync /dev/sdd
UUID : 9db29812:14b701fb:68862181:0c9e5950
Events : 0.7
可以看到两路设备都已是活动状态。

5)MDADM当前只有一路是同数据通路活动的,当主路出现故障时会自动切换到另一路上。如发生主路HBA卡故障、一台存储交换机故障、或存储一个端口控制器故障时,主/备路会变成faulty,若是主路,此时便会切到备路上去。
可用# mdadm –D /d/ev/md1察看
/dev/md1:
Version : 00.90.01
Creation Time : Fri Feb 17 12:20:41 2006
Raid Level : multipath
Array Size : 209715136 (199.100 GiB 214.75 GB)
Raid Devices : 2
Total Devices : 2
Preferred Minor : 1
Persistence : Superblock is persistent

Update Time : Tue Feb 21 08:58:32 2006
State : clean, degraded
Active Devices : 1
Working Devices : 1
Failed Devices : 1
Spare Devices : 0

Number Major Minor RaidDevice State
0 0 0 -1 removed
1 8 48 1 active sync /dev/sdd
2 8 0 -1 faulty /dev/sda
UUID : 9db29812:14b701fb:68862181:0c9e5950
Events : 0.7
看到当前sda已发生故障,sdd为通讯路经

6)当故障修复后,MDADM不会自动failback,需手工加载恢复通路,如将修复后的sda重新加载回来如下:
#mdadm /dev/md1 –r /dev/sda –a /dev/sda
再用# mdadm –D /d/ev/md1察看状态是否恢复正常。

7)如需删除一个不再使用或暂时不适用的md设备,可以通过mdadm –S /d/ev/mdx来停止相应的md设备。如设备当前正被加载使用中,则需先停止