存档

文章标签 ‘ORACLE’

Cache和Buffer是两个不同的概念,简单的说,Cache是加速“读”,而buffer是缓冲“写”,前者解决读的问题,保存从磁盘上读出的数据,后者是解决写的问题,保存即将要写入到磁盘上的数据。在很多情况下,这两个名词并没有严格区分,常常把读写混合类型称为buffer cache,本文后续的论述中,统一称为cache。
Oracle中的log buffer是解决redo写入的问题,而data buffer cache则解决data block的读写问题。对于Oracle来说,如果IO没有在SGA中命中,都会发生物理IO,Oracle并不关心底层存储的类型,可能是一套存储系统,可能是本地磁盘,可能是RAID 10,也可能是RAID 5,可能是文件系统,也可能是裸设备,或是ASM。总之,Oracle把底层的存储系统称为存储子系统。
在存储系统中,cache几乎无处不在(在后面的论述中,我们统称为cache),文件系统有cache,存储有cache,RAID控制器上有cache,磁盘上也有cache。为了提高性能,Oracle的一个写操作,很有可能写在存储的cache上就返回了,如果这时存储系统发生问题,Oracle如何来保证数据一致性的问题。
Oracle数据库最重要的特性是:Write ahead logging,在data block在写入前,必须保证首先写入redo log,在事务commit时,同时必须保证redo log被写入。Oracle为了保证数据的一致性,对于redo log采用了direct IO,Direct IO会跳过了OS上文件系统的cache这一层。但是,OS管不了存储这一层,虽然跳过了文件系统的cache,但是依然可能写在存储的cache上。
一般的存储都有cache,为了提高性能,写操作在cache上完成就返回给OS了,我们称这种写操作为write back,为了保证掉电时cache中的内容不会丢失,存储都有电池保护,这些电池可以供存储在掉电后工作一定时间,保证cache中的数据被刷入磁盘,不会丢失。不同于UPS,电池能够支撑的时间很短,一般都在30分钟以内,只要保证cache中的数据被写入就可以了。存储可以关闭写cache,这时所有的写操作必须写入到磁盘才返回,我们称这种写操作为write throuogh,当存储发现某些部件不正常时,存储会自动关闭写cache,这时写性能会下降。
RAID卡上也有cache,一般是256M,同样是通过电池来保护的,不同于存储的是,这个电池并不保证数据可以被写入到磁盘上,而是为cache供电以保护数据不丢失,一般可以支撑几天的时间。还有些RAID卡上有flash cache,掉电后可以将cache中的内容写入到flash cache中,保证数据不丢失。如果你的数据库没有存储,而是放在普通PC机的本地硬盘之上的,一定要确认主机中的RAID卡是否有电池,很多硬件提供商默认是不配置电池的。当然,RAID卡上的cache同样可以选择关闭。
磁盘上的cache,一般是16M-64M,很多存储厂商都明确表示,存储中磁盘的cache是禁用的,这也是可以理解的,为了保证数据可靠性,而存储本身又提供了非常大的cache,相比较而言,磁盘上的cache就不再那么重要。SCSI指令中有一个FUA(Force Unit Access)的参数,设置这个参数时,写操作必须在磁盘上完成才可以返回,相当于禁用了磁盘的写cache。虽然没有查证到资料,但是我个人认为一旦磁盘被接入到RAID控制器中,写cache就会被禁用,这也是为了数据可靠性的考虑,我相信存储厂商应该会考虑这个问题。
至此,我们可以看到Oracle的一个物理IO是经历了一系列的cache之后,最终被写入到磁盘上。cache虽然可以提高性能,但是也要考虑掉电保护的问题。关于数据的一致性,是由Oracle数据库,操作系统和存储子系统共同来保证的。
–EOF–

8 28th, 2010 | Filed under 大话技术
标签: , ,

Oracle中undo的作用主要有两个:第一是回滚事务,第二是产生一致性读。同时也衍生出了一些新的 功能,比如Flashback query。传统的undo是通过undo segment来管理的,我们看下面的示例:

事务开始,必须首先在data block中分配ITL,ITL中记录了事务ID(XID),XID由三部分内容组成:XIDUSN(回滚段号),XIDSLOT(回滚段槽 号),XIDSQN(序列号),在Undo segment header中有一个事务表,记录该回滚段上的事务信息,每个事务都会占据了一个回滚槽,XID对应一个UBA(undo block address),表示该事务回滚信息的开始位置。 在上面的例子中,事务分别在T1,T2,T3时间执行了三个操作,更新了三个block中的数据,在每个data block中都存在一个ITL,指向undo segment header中的事务表。undo信息分别存放在三个undo block中,undo信息是一个链表结构,而undo segment header中的uba则指向了最后一个undo block,这也是回滚的起始位置。如果事务需要回滚,只需要在undo segment header中的事务表中找到事务回滚的起始位置,然后通过undo链表,就可以依次回滚整个事务。
细心的DBA一定会发现,在每个data block的ITL中也有一个UBA,实际上这个UBA是指向了该block对应的undo信息的起始位置,这个UBA主要的作用是提供一致性读,因为一 致性读需要通过undo信息来构造一个CR block,通过这个UBA就可以直接定位到block的回滚信息的起始位置,而不再需要通过undo segment header中的事务表。
在传统的undo管理模式中,Oracle对于undo和data block是一视同仁的,他们都需要首先读入到data buffer中进行修改,并都会产生redo信息,修改的过程大致是:产生undo的redo,更改undo block,产生data的redo,修改data block。总之redo必须要先于数据被记录下来。当数据库发生crash,可以通过redo日志,恢复data和undo block,然后再通过undo信息去回滚未提交的事务,保证数据的一致性,所以说instance recovery的过程是先前滚,再回滚的过程。
传统的undo管理有弊端,第一是undo信息如果不在data buffer中,必须首先从外部文件中读入;第二是undo的所有变化也必须同时记录redo,在事务提交时被写入到redo log中。Oracle提出了In-Memory UNDO的新特性,将undo信息都存放在内存结构中,缓解传统undo管理中带来的开销。
IMU在shared pool中分配一片内存空间(IMU pool),每个新的事务都会分配一个IMU buffer,它相当于一片事物私有的undo buffer,用来记录undo的信息。Data block中记录了IMU node的起始位置,通过IMU buffer中的信息就可以完成一致读,从而大大提升了效率。(这里要澄清一点,我在dump data block时,并没有发现指向IMU node的具体信息)。

在IMU模式下,undo信息依然会被写入到redo中,理解这点很重要!因为Instance recovery需要undo的信息去回滚未提交的事物,使数据库处于一致状态,如果redo中没有undo变化的信息,那么一旦发生Instance crash,数据库将有可能处于一个不一致的状态。
事务开始依旧会在data block中的分配ITL,并且它依然会指向undo segment header的事物表,但是undo block中的信息并不需要马上写入,这时undo信息是记录在IMU Buffer中的,这时也不会产生undo block的redo信息。在以下两种情况时,undo buffer中的信息会被写入到undo block中:1.IMU buffer空间不足;2.LGWR将redo信息被写入到redo [...]

8 2nd, 2010 | Filed under 大话技术
标签: ,

Library cache是Shared pool的一部分,它几乎是Oracle内存结构中最复杂的一部分,主要存放shared curosr(SQL)和PLSQL对象(function,procedure,trigger)的信息,以及这些对象所依赖的table,index,view等对象的信息。
Library cache需要解决三个问题:
1.快速定位的问题:Library cache中对象众多,Oracle如何管理这些对象,以便服务进程可以迅速找到他们需要的信息。比如某个服务进程需要迅速定位某个SQL是否存在于Library cache中。
2.关系依赖的问题:Library cache中的对象存在复杂的依赖关系,当某个objec失效时,可以迅速将依赖其的对象也置为失效状态。比如某个表发生了结构变化,依赖其的SQL语句需要重新解析。
3.并发控制的问题:Library cache中必须有一个并发控制的机构,比如锁机制,来管理大量共享对象的并发访问和修改的问题,比如某个SQL在重新编译的同时,其所依赖的对象不能被修改。
Library cache结构:

Oracle利用hash table结构来解决library cache中快速定位的问题,hash table就是很多hash bucket组成的数组:

原理与buffer cache中定位block的方式相同,将对象信息(比如SQL)hash定位到某个hash bucket中,然后顺序扫描bucket中的 List,实现快速定位对象的目的。
Library cache handle是对象的一个指针,其中的namespace属性表示其指向的对象的类型:比如CRSR(Cursor),TABL(Table),INDX(Index) ,PROD(Procedure),TRIG(Trigger)等等。
LCO(Library cache object)是handel指向的对象,包含了以下几个部分的内容:
1.dependency table:
指向本对象所依赖的对象,比如:select * from emp这个cursor的对象,依赖emp这个表,这里指向了emp这个表的handle。
2.child table:
指向本对象的子对象,比如某个游标的子游标。子游标是指SQL文本相同,但是SQL的实际含义不同的情况,比如执行的用户不同,执行计划不同,执行的环境不同等等,我们一般称之为SQL的不同版本。一个SQL至少包含一个父游标和一个子游标。
3.authorization table:
对象的授权信息。
4.type
Library cache object的type,包括:shared cursor,index,table,cluster,view,synonym,sequence,procedure,function,package,table body,package body,trigger等等。
5.data blocks
data block是一个指针,指向了data heap,即存放真实数据的地方,主要包括:diana tree, p-code, source code, shared cursor context area等等,如下图:

Library cache对象依赖关系:
对象依赖关系是利用LCO中的dependency table来完成的,我们设想以下的情况,用来说明对象间的依赖关系:
两个共享游标:
SQL1: select * from emp;
SQL2: select * from emp和select a.name [...]

7 4th, 2010 | Filed under 大话技术
标签: , , , ,

我们都知道Latch是Oracle用来在内存中做串行控制的机构,从10g R2开始,Oracle引入了一个新的技术-Mutex。Mutex并不是Oracle的发明,而是系统提供的一个底层调用,Oracle只是利用它实现串行控制的功能,并替换部分Latch。
Mutex中有两个变量:分别是Holider identifer和Reference count,Holider identifer记录持有mutex的SID,而Reference count是一个计数,记录了当前正在以share方式访问mutex的数量,每当session以share方式持有mutex时,计数会加1,而释放时会减1。如果Reference count大于零,则表示该内存结构正在被Oracle pin住。
我们看一段伪代码,演示mutex的申请过程:
Function Mutex_get(mutex_name)
{
if mutex.holder:=SID
case mode:
‘exclusive’:
if mutex.ref_count=0
return TRUE
else
mutex.holder.clear;
[...]

6 17th, 2010 | Filed under 大话技术
标签: ,

最近一直在思考一个问题:如何为一个数据库建立性能模型?作为一名DBA来说,我们面临的一个巨大挑战是:如何保证数据库的性能可以满足快速变化的应用的需求,如何在数据量和访问量持续增长的情况下,保证应用的响应时间和数据库的负载处在合理的水平下。我们可能会经常面对以下的问题:某个SQL每秒要执行100次,响应时间是多少?某个应用发布后,对数据库的影响如何?所以,评估应用对数据库所产生的影响,优化应用并预测风险,保证数据库的可用性和稳定性,这是应用DBA真正有价值的地方。
响应时间为中心:
如果要选择一个评价系统优劣的性能指标,毫无疑问应该是响应时间。响应时间是客户体验的第一要素,所有的优化都应该为降低响应时间而努力。对于数据库系统也是如此,我们优化系统,优化SQL,最终目标都是为了降低响应时间,单位时间内可以处理更多的请求。
数据库时间模型:
响应时间一般分为服务时间(Service time)和等待时间(Wait time),服务时间指进程占用CPU的时间,包括前台进程(Server process)和后台进程(Backgroud process),我们一般只关注前台进程占用的CPU time。等待时间包括很多类型,一般最常见的是IO等待和并发等待,IO等待包括sequential read,scattered read和log file sync等等,而并发等待主要是latch和enqueue。SQL execute elapsed time指用户进程执行SQL的响应时间,包含CPU time和wait time。
以下是Oracle数据库的时间模型:

在Oracle系统中,我们可以利用AWR或Statspack报告,看到数据库的时间信息:

Statistic Name
Time (s)
% of DB Time

sql execute elapsed time
3,062.17
91.52

DB CPU
2,842.08
84.95

parse time elapsed
25.87
0.77

PL/SQL execution elapsed time
11.75
0.35

sequence load elapsed time
7.55
0.23

hard parse elapsed time
5.06
0.15

connection management call elapsed time
3.13
0.09

hard parse (sharing criteria) elapsed time
0.04
0.00

repeated bind elapsed time
0.01
0.00

PL/SQL compilation elapsed time
0.00
0.00

DB time
3,345.74

background elapsed time
204.91

background cpu [...]

6 16th, 2010 | Filed under 大话技术
标签:

建立数据库性能模型,这是我最近一直在思考的一个问题。这个命题还是非常有意义的,因为我们在很多情况下都需要对数据库做性能评估,容量规划和风险预测。很多DBA的优化经验都局限在一个很小的数据库技术领域内,而对整个系统的性能容量并不十分了解。我希望能够给大家一些简单的模型和经验数据,帮助大家对系统的整体性能有一个更深层次的了解。
这篇PPT可能还达不到模型的理论高度,甚至很多数据还不是十分准确,只是我个人思考的一个结果,希望能抛砖引玉,大家一起思考和进步。
PPT:Oracle数据库性能模型
–EOF–

6 13th, 2010 | Filed under 大话技术
标签:

之前,我对Sequential和Scattered的理解是Oracle读取IO的顺序不同,今天又讨论起这个问题,另外一种解释是两者在内存中的保存方式有差异,Sequential read在内存中是连续的,而Scattered read是离散的。以下解释来自于Oracle文档:
Scattered read:
This event signifies that the user process is reading buffers into the SGA buffer cache and is waiting for a physical I/O call to return. A db file scattered read issues a scatter-read to read the data into multiple discontinuous memory locations. A scattered read is usually a multiblock [...]

6 3rd, 2010 | Filed under 大话技术
标签:

最近整理了一些关于数据库架构方面的技术专题,并整理成为PPT,准备拿出来和大家一起分享。
为什么要这么做,并不是要为了证明我自己,更不是为了其他什么目的。因为最近一直有一种强烈的执着,想要做成一些事情,在这之前,必须找到很多志同道合的人一起来努力,所以需要先布道。我并不是为了分享而分享,而是希望这些东西能够改变大家对现在一些架构的理解,真正了解我们现在面对的问题和未来的挑战。
蔡学镛说:大多數的工程師並不是「做了五年的系統開發」,而是「做了一年的系統開發,然後重複五次」。我不希望我和周围的同事们都是如此,所以我分享,帮助别人,也帮助我自己。
PPT:数据库高可用架构

5 27th, 2010 | Filed under 大话技术

分布式系统的hash策略,决定了数据的分布。传统的方式采用mod n的算法,非常简单,但是一旦节点发生变化,所有的数据都需要重组,代价非常大。一致性哈希(Consistent hash)很好的解决了这个问题,当节点发生变化时,只会影响到部分数据,而且永远可以找到一个提供服务的节点。
对于数据库Sharding的架构,Consistent hash并不十分适合,我们采用了一种新的hash策略,我将其称之为“Virtual Partition Hash”策略。
为了解决节点数量变化时,全部数据需要重组的问题,我们采用了预分区的策略,将整个系统分为很多个Virtual Partition,每个物理节点由多个Virtual Partition组成。比如整个系统分为128个VP,共有8个物理的服务器,每个服务器包含16个VP的数据,只要整个系统的物理节点小于128个,增加节点只需要移动部分VP就可以了,避免了数据重组的问题。另外,为了提高可用性,每个物理节点都有一套备机,如果节点失效则切换至备用节点。
新增一个物理节点:

只需要移动部分VP至新节点,不需要数据重组。

Virtual partition hash策略非常简单,实现也很容易,实际上它是Consistent hash策略的一个简化版本,Oracle hash分区也是类似的做法,尽可能的减少数据重组的代价,可以参考我以前的文章《Oracle hash分区的秘密》。
这个策略的另外一个好处是非常灵活,可以根据服务器压力的情况,通过移动VP的来达到负载均衡的目的。利用MySQL数据库复制的特性,移动VP是非常容易的,而且配合我们的分布式数据库架构,可以做到对应用透明。
这个方案的缺点是:每个节点都准备一台备机,硬件资源比较浪费。但是如果可以和读写分离架构配合起来,备机可以承担部分读的服务,那么这个缺点就不存在了。
“Simple but Incomplete Solutions Win!”
—EOF—

5 26th, 2010 | Filed under 大话技术

本篇文章不得以任何形式转载或发表。

这不是一篇关于Oracle和MySQL技术比较的文章,而是我对Oracle和MySQL甚至 NoSQL产品选择上的一些想法。
我们过去和现在使用了大量的Oracle数据库,几乎我们所有的数据都存放在Oracle数据库里面,我们有高端的小型机,大型存储和全国最牛的DBA团队。这些都让我们引以为傲。
随着业务不断增长,数据量和计算量越来越庞大,我们发现小型机都无法满足我们的需求,除了Oracle我们别无选择,我们被“绑架”了,被IBM,EMC,Oracle绑架了,我们辛辛苦苦赚的血汗钱都交给他们了。
2009年开始,我们引入了MySQL数据库,采用sharding技术,利用PC服务器搭建高可用的数据库集群,极大的降低了我们的成本,并提供了充足的扩展能力,让业务有更大的发展空间。
最近,我们遇到了一些困惑:应用如何选择Oracle还是MySQL?从Oracle迁移到MySQL的意义是什么?Oracle收购SUN之后,MySQL何去何从?
我们的目标不是要用MySQL数据库替代所有的Oracle,事实上,这不现实也不是我们的目标,目前很多应用都依赖于Oracle数据库的特性,相当长的一段时间内,Oracle依然是我们的首选。但是,这并不意味着Oracle是我们唯一的选择,我们选择MySQL和PC服务器来搭建大规模数据库集群,最终的目标是要证明我们具备更换数据库的能力,具备用廉价设备替换小型机的能力,能够用我们自己的软件搭建高可用可扩展的架构。所以说,MySQL只是一个数据库而已,如果某天Oracle将MySQL收费,我们可以换成其他的数据库(比如 PostgreSQL)。我们正在做的事,其中的价值并不能简单的用节省 Oracle license的费用来评估。
阿里巴巴正在研发云计算系统,同样要证明阿里巴巴具备这种能力,这是每一个伟大的公司都要具备的能力。我相信,未来的数据存储肯定不仅仅局限于数据库,数据库和其他NoSQL产品一定会百花齐放。
我们做了大量的努力和尝试,包括Sharding和功能分区,SSD的尝试,MySQL高可用架构,数据同步工具等等,都是为了一个目标:证明的是我们能够设计出一种架构,可以做到用PC server和开源数据库(不仅仅局限于MySQL)来替换高端设备和Oracle,不被设备厂家和Oracle所绑架,将主动权掌握在自己手中。所以,我们不要过分纠结于Oracle和MySQL 在具体性能上的差异,作为一个数据库产品,MySQL无法和Oracle相比,单个PC server的可用性更是无法同小型机相比,但是我们用架构去弥补,整体上达到更高的可用性。
所以,我们不应该单纯用MySQL和Oracle本身的优劣,来评估技术方案,更不能用pc server的可用性和小型机去相比。关键是我们的技术架构能否用廉价的东西搭建出高可用可扩展的系统,这才是我们真正引以为傲的地方。
–EOF–

4 27th, 2010 | Filed under 大话技术
标签: ,