数据库系统中的cache

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数据库,操作系统和存储子系统共同来保证的。

分享一些东西。磁盘的cache绝对没有被关掉,读io是绝对有cache的,磁盘本身就有预读功能,这个存储系统控制器不会干预,而只会干预写cache。 OS可以通过ioctl来发送scsi mode sense指令从磁盘获取相关cache信息,包括cache是否是write back模式的,是否是write through模式的等等,这些信息磁盘都会告诉控制器。控制器还可以发送指令来告诉磁盘使用何种cache模式,一次性生效,直到断电。

一些外部设备比如Raid适配器、SCSI适配器,都具有自己的缓存,这些缓存如果用来做预读操作,那么没有任何问题,但是如果用Write Back的模式来缓存写数据,那么在这些适配卡没有电池保护其上缓存的情况下,一旦发生供电故障或者Down机,则被缓存的写数据就会永久丢失。在Windows下,Class Driver层有必要知道底层设备是否支持Write Back缓存,如果支持,是否有电池保护等信息。对于没有电池保护的WriteBack模式的设备缓存,Class Driver有两种解决办法:第一种是使用SCSI SYNCHRONIZE CACHE指令来强制让设备将缓存内的所有Dirty写数据写入存储介质中,这种方法需要消耗很多的设备自身的处理资源,因为设备一旦接收到这个指令,就需要全力以赴的执行,而写盘动作是一个慢速动作,在执行这个动作期间,新进入的写IO可能得不到处理,而上层在此时的反应就仿佛设备挂死一般。如果频繁的使用SCSI SYNCHRONIZE CACHE指令,系统整体性能将会非常差。第二种方法则是针对每个写IO使用Write Through标记(FUA置1,即Force Unit Access),这样,设备在从总线上接收这个IO请求写的数据入缓存的同时,将数据写向介质中,只有成功写入了介质,才返回完成信号,而写入完成后,缓存中的这些数据将被视作预读内容处理。使用Write Through的方法虽然也不能提高写性能,但是其相对SCSI SYNCHRONIZE CACHE指令的方式来讲节约了设备处理资源。有些设备并不支持FUA,但是它对待每个写IO都会做Write Through处理,也就是原生的WT模式写缓存。而有些设备则带有电池为其缓存供电,那么这时候,Class Driver就没有必要发起Write Though或者SCSI SYNCHRONIZE CACHE了。
Class Driver使用IOCTL_STORAGE_QUERY_PROPERTY功能函数来向Port Driver查询设备属性信息,其中就有关于写缓存的信息,具体写缓存信息包括:
 设备是否具有写缓存
 设备具有何种写缓存类型。又包含两种具体类型:Write Back和原生Write Through。
 设备是否支持SCSI SYNCHRONIZE CACHE指令。
 设备是否具有电池保护。

另外捎带提一下,刚记起来。FUA和DPO是两个用于控制器来控制磁盘缓存的bit。FUA就不说了。DPO是指Data page out,用来控制某个page的数据写入磁盘之后(会停留在磁盘缓存中),是否可以允许后续的预读page将其强制换出,=0则不允许换出,=1则允许换出。控制器用这种方法来有选择性的提高某些它认为后续很有可能再读出的数据。不过控制器本身有缓存,所以一般没有必要利用磁盘的这点缓存了,但是scsi指令不管虚拟化层,比如主机如果向外部存储控制器发送带有DPO的指令,那么控制器此时就需要考虑支持了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值