ITPub博客

首页 > Linux操作系统 > Linux操作系统 > 谈谈Buffer Cache中Keep和Recycle子池(上)

谈谈Buffer Cache中Keep和Recycle子池(上)

原创 Linux操作系统 作者:realkid4 时间:2012-01-10 22:36:32 0 删除 编辑

 

Oracle是一个充分利用内存技术、缓存技术来解决数据库操作问题的DBMS。同外存储器(硬盘存储)相比,内存虽然具有断电遗失的问题,但是处理速度上却有显而易见优势。

 

Oracle早期进行的架构设计中,就充分体现出缓存Cache的广泛应用。目前Oracle的核心技术,如Undo/Redo、Share Pool和Buffer Cache,都是建立在缓存数据重用的基础之上。而作为数据库Instance关键组件的SGA,就是一块共享内存组织。

 

1、从Buffer Cache中的缓存block谈起

 

Buffer Cache是Oracle SGA的一块重要区域。其中的内容就是所有Server Process读出的数据块。

 

 

SQL> select * from v$version;

 

BANNER

----------------------------------------------------------------

Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod

PL/SQL Release 10.2.0.1.0 - Production

CORE    10.2.0.1.0    Production

 

TNS for 32-bit Windows: Version 10.2.0.1.0 - Production

NLSRTL Version 10.2.0.1.0 Production

 

 

Oracle中,当一个Server Process需要进行数据读写的时候,通常的行为并不是直接到物理存储上进行物理IO读写。Server Process首先会在buffer cache中寻找需要的数据块之前有没有被缓存到其中,如果有的话,就直接操作数据块(我们称作发生一次Logical Read)。如果Server Process没有在Buffer Cache中找到对应数据块的话,才会启动物理存储设备的读写操作,将需要的数据块读取出来(我们称作发生一次Physical Read)。

 

对操作完的数据块,Oracle并不是直接就将其释放掉,而是缓存在Buffer Cache中一段时间。这里Oracle的出发点是这样:如果这个数据块现在使用过,那么之后也需要的概率就会很高。那么,该数据块留在buffer cache中,下次使用的时候就可以避免一次Physical Read,用于提高性能。

 

通过buffer cache机制,Oracle加快了数据访问的速度,大大缓解了由于物理IO而带来的性能问题。

 

但是,buffer cache的引入还带来了管理复杂性。数据块缓存在buffer cache中,需要进行快速的检索和管理,同时伴随着生命周期管理。其中,常常被我们提及的就是数据块的“age out”机制:数据块什么时候会剔除出buffer cache。

 

Age Out的问题上,Oracle使用的是基于LRU(Least Recent Use)算法和数据链。Buffer cache本质上是一系列的数据链表,分别根据数据块使用的频度和时间分布在两端,一端为经常使用、“热度较高”的MRU端,而另一端则是使用频度较低的数据块。当buffer cache中空闲空间不足,或者其他引发条件发生时,Oracle就会将LRU端的数据块清除出缓存。

 

2、“Who should be aged out !”

 

相对于整个数据库,SGA中的buffer cache总是相对较小的。总是有数据块会被age out出去。那么,这种机制有什么问题呢?

 

如果一个数据块经常被访问,那么肯定会驻留在LRU列表的MRU端,这样被age out出去的几率较低。这种情况也就是可以最大限度的利用cache的优势,减少物理IO的发生。

 

但是,如果一个系统中,buffer cache相对较小,而操作SQL进行IO读取量又比较大。那么,即使经常使用的数据块,也是存在会被频繁age out,但又频繁cache入内存。这样,系统的IO性能会形成负载。

 

上面的情况在实际中是很典型的。有的时候,我们会以高频繁度访问一些数据表,访问的数据相似。这种情况最好的处理方式是在应用前端建立数据缓存,直接减少SQL交互次数。但是实际中,我们却经常发现该部分数据频繁的物理IO。

 

还有一些情况也值得关注,就是不同类型的数据块在buffer cache中可能存在优先级差异。例如,索引块比数据块在buffer cache中保留的几率要高,因为Oracle认为索引块的作用要比普通的数据块大得多。还有,如果数据块是通过全表扫描(Full Table Scan)读取进buffer cache,那么Oracle认为这个数据块只是暂时的被使用,很快就会被age out出去。

 

上面的一些问题告诉我们:在统一的buffer cache管理下,一些特殊情况是不能够忽视的。我们需要建立一种机制,来进行细致化的cache管理。于是,Oracle对Buffer Cache使用了Keep和Recycle两个特殊管理空间。

 

 

3、Keep池和Recycle池

 

Oracle将Buffer Cache划分为三个子池,分别为Default、Keep和Recycle。在三个子池中,Oracle对不同缓存优先级别数据块进行分别管理,力图维持不同的缓存策略。

 

Default、Keep和Recycle三个子池会共享Buffer Cache大小。在Oracle10g和11g时代,广泛应用自动内存调整技术(ASMM),这部分空间在参数文件设置中是为空的。

 

 

SQL> show parameter buffer;

 

NAME                                 TYPE        VALUE

------------------------------------ ----------- ------------------------------

buffer_pool_keep                     string     

buffer_pool_recycle                  string     

db_block_buffers                     integer     0

 

--10g以上版本应用

SQL> show parameter cache_size;

 

NAME                                 TYPE        VALUE

------------------------------------ ----------- ------------------------------

(篇幅原因,有省略

db_cache_size                        big integer 0

db_keep_cache_size                   big integer 0

db_recycle_cache_size                big integer 0

 

 

当我们启动数据库实例后,Oracle会根据参数文件和最后一次启动的配置数值,进行内存SGA空间分配。

 

 

SQL> select * from v$sgastat where pool is null;

 

POOL         NAME                            BYTES

------------ -------------------------- ----------

             fixed_sga                     1336904

             buffer_cache                 79691776

log_buffer                    6111232

 

 

Keep池就是在buffer cache中的一块区域。如果我们希望数据表或者其他对象长期的保留在内存buffer cache中,不会轻易的被age out出去,就可以设置在Keep池中。设置在Keep池中的对象,和Default池对象相同,都是通过LRU算法维持在LRU列表中。放置在Keep池中对象,拥有单独的LRU列表,不会被其他低优先级数据表“排挤”出内存空间的。

 

Recycle池道理与Keep池相同。如果一些数据对象体积很大,但是访问机率较低,我们希望尽快被age out出去,就可以将其放置在recycle中。这样,独立的recycle LRU列就会将该部分的数据块单独维护,并且尽快的age out出去。

 

Keep和Recycle池,有两个方面问题需要关注:

 

首先,默认情况下,数据段对象的缓存是在Default池中的。只有在特殊的系统、业务需求下,我们处于优化的目的,才会考虑启用Keep池和Default池。

 

 

SQL> select component, current_size, min_size, max_size from v$sga_dynamic_components where component in ('DEFAULT buffer cache','KEEP buffer cache','RECYCLE buffer cache');

 

COMPONENT                      CURRENT_SIZE   MIN_SIZE   MAX_SIZE

------------------------------ ------------ ---------- ----------

DEFAULT buffer cache               83886080   79691776          0

KEEP buffer cache                         0          0          0

RECYCLE buffer cache                      0          0          0

 

 

其次,所谓Keep池和Recycle池,其中差异是分类类型的差异。针对不同的类型数据,在Keep、Recycle和Default池中,都是采用相同的LRU算法,都是存在Age Out机制。例如,如果Keep池设置较小,而我们设置的Keep住对象较大,同样会有Keep池的对象被Age Out出去。

 

下面,我们来看一下如何定义数据表在Keep和Recycle池中,以及相应的效果。

 

4、子池对象定义和特性——Default池

 

默认情况下,数据表等对象是定义在Default池中的。

 

 

SQL> create table t_def as select * from dba_objects;

Table created

 

SQL> col segment_name for a20;

SQL> select segment_name,BUFFER_POOL from dba_segments where segment_name='T_DEF';

 

SEGMENT_NAME         BUFFER_POOL

-------------------- -----------

T_DEF                DEFAULT

 

SQL> select table_name, cache from dba_tables where table_name='T_DEF';

 

TABLE_NAME                     CACHE

------------------------------ ----------

T_DEF                              N

 

 

默认情况下,我们的数据表是定义在Default池中。那么,我们在使用时,数据表对应块是放置在default池。

 

 

SQL> set timing on;

SQL> set autotrace traceonly;

SQL> select count(*) from t_def;

已用时间:  00: 00: 00.49

 

统计信息

----------------------------------------------------------

         28  recursive calls

          0  db block gets

        770  consistent gets

        692  physical reads

          0  redo size

        410  bytes sent via SQL*Net to client

        385  bytes received via SQL*Net from client

          2  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

          1  rows processed

 

SQL> select count(*) from t_def;

已用时间:  00: 00: 00.03

 

统计信息

----------------------------------------------------------

          0  recursive calls

          0  db block gets

        697  consistent gets

          0  physical reads

          0  redo size

        410  bytes sent via SQL*Net to client

        385  bytes received via SQL*Net from client

          2  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

          1  rows processed

 

SQL>

--之后进行一系列的数据操作,不涉及数据表T_DEF。再次执行该语句。

SQL> select count(*) from t_def;

 

已用时间:  00: 00: 00.58

统计信息

----------------------------------------------------------

          0  recursive calls

          0  db block gets

        697  consistent gets

        377  physical reads

          0  redo size

        410  bytes sent via SQL*Net to client

        385  bytes received via SQL*Net from client

          2  SQL*Net roundtrips to/from client

          0  sorts (memory)

          0  sorts (disk)

          1  rows processed

 

 

上面典型是一个Default池处理场景。一共执行了三次语句,执行时间分别为0.49s、0.03s和0.58s。体现出default LRU链工作的特点。

 

当第一次执行的时候,Oracle Server Process从Buffer Cache中不能够获取到全部的数据表T_DEF块。于是进行692次的物理IO和770次逻辑IO,返回结果,同时将数据块缓存在Default池的LRU链上。

 

第二次执行的时候,由于两次间隔短且没有额外IO操作,所以Server Process直接在Buffer Cache中找到了需要的数据块。该次操作就不需要进行物理IO,只有697次逻辑IO。执行时间也因为纯内存操作而减少到0.03s。

 

最后一次操作前,系统进行了一系列的数据块操作,有部分的Default数据表块被age out出去。该次的操作伴随着一定的物理IO操作,执行时间也有所增加。

 

下面我们看Keep池和Recycle池的使用。

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/17203031/viewspace-714717/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
求道~

注册时间:2010-11-30

  • 博文量
    545
  • 访问量
    7568551