首页 > 其他 > 详细

buffer cache实验1-内存结构图解

时间:2014-02-18 14:03:37      阅读:387      评论:0      收藏:0      [点我收藏+]

1.为什么要使用buffer cache???

buffer cache就是一块含有许多数据块的内存区域,这些数据块主要都是数据文件里的数据块内容的拷贝。
从buffer cache中读取一个数据块一般需要100ns左右,从一般的存储硬盘中读取一个数据块需要10ms;所以大概算一下,从内存中读取数据块比从硬盘中快近十万倍。
故oracle在读取数据块时,先在buffer cache中查找,如存在,则读取--逻辑读;如果数据块不存在,则发生物理读,从物理文件中将数据读入buffer cache(不考虑直接读的情况)。
在初始化参数中,设置buffer cache大小的参数是db_cache_size
在11.2.0.4.0中此参数支持动态修改:
BYS@ bys3>show parameter db_cache_size
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_cache_size                        big integer 48M
BYS@ bys3>alter system set db_cache_size=40M;
System altered.
BYS@ bys3>show parameter db_cache_size
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_cache_size                        big integer 40M

buffer cache所提供的功能主要包括:

1) 通过缓存数据块,从而减少I/O。
2) 通过构造CR块,从而提供读一致性功能。
3) 通过提供各种lock、latch机制,从而提供多个进程并发访问同一个数据块的功能。

2.buffer cache的内存结构图解

话说大神们都用WORD画图,为了模仿大神, 我也用WORD画了好久的原创:
bubuko.com,布布扣
从这张buffer cache的内存结构图,用一句话来说明
buffer cache中 结构大致是:buffer pool--->working set--->hash latch--->hash bucket--->hash chain--->buffer header--->buffer dba
下面就把这些结构的概念大致说明一下: --更详细的的在之后


1.buffer header:

每一个数据块在被读入buffer cache时,都会先在buffer cache中构造一个buffer header,buffer header与数据块一一对应(buffer header 中有指定buffer 具体内存地址的信息)。

buffer header包含的主要信息有:   详见:
1) 该数据块在buffer cache中实际的内存地址。
2) 该数据块的类型,包括data、segment header、undo header、undo block等等。
3) 该buffer header所在的hash chain,是通过在buffer header里保存指向前一个buffer header的指针和指向后一个buffer header的指针的方式实现的。
4) 该buffer header所在的LRU、LRUW、CKPTQ等链表(这些链表我们后面都会详细说明)。也是通过记录前后buffer header指针的方式实现。
5) 当前该buffer header所对应的数据块的状态以及标记。
6) 该buffer header被访问(touch)的次数。
7) 正在等待该buffer header的进程列表(waiter list)和正在使用该buffer header的进程列表(user list)。

我的测试环境:buffer cache大小是40M,buffer的个数是4936(每个buffer在x$bh中都存在一条记录)。 在11G中db_cache_size 是一个动态参数,可以手动更改此参数后再查询x$bh,可以发现buffer的个数也会随之变化的。
SYS@ bys3>show parameter db_cache_si
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_cache_size                        big integer 40M
SYS@ bys3>select count(*) from x$bh;   --用这句查出buffer的个数,也就是可以存放4936个数据块(因为还有一部分空间是生成buffer header),db_cache_size/4936-8K就能算出一个buffer header的大致大小
  COUNT(*)
----------
      4936
################################

2.hash chain与hash bucket:

从上图中可以看到,一个hash bucket是对应着一条hash chain的。Hash Bucket-直译叫hash桶
Hash Bucket   一个逻辑上的概念,通过对buffer header 里记录的数据块地址和数据块类型运用hash算法以后,得到的组号。
hash chain    将属于同一个hash bucket的所有buffer header串起来的链表

服务器进程将数据块读取到buffer cache后,将数据块的DBA进行HASH运算,将具有相同HASH值的数据块的buffer header挂载到同一个hash bucket下(可能多个块的HASH值相同),并用hash chain串联起来。
buffer cache中,缺省的hash bucket的数量或者说缺省有多少条hash chain链表,是由一个隐藏参数: _db_block_hash_buckets决定的。
关于_db_block_hash_buckets参数的取值:据说在8i下,该参数缺省为db_block_buffers×2;但是到了9i以后,该参数似乎取的是小于且最接近于db_block_buffers×2的素数。
在ORACLE 10G和11G中,默认值是大于2倍的buffer数量的最小的2的幂的值。举例如buffer数量是500,2倍就是1000,那么大于1000的最小的2的幂的值是1024,也就是就会有1024个hash bucket。

在我测试系统中:buffer 数量是4936,2倍是9872,从隐含参数_db_block_hash_buckets  查出bufket数量是16384 ,完全符合。
SYS@ bys3>select count(*) from x$bh;   --用这句查出buffer的个数
  COUNT(*)
----------
      4936
P_NAME                                   P_DESCRIPTION                                      P_VALUE                        ISDEFAULT ISMODIFIED ISADJ
---------------------------------------- -------------------------------------------------- ------------------------------ --------- ---------- -----
_db_block_hash_buckets                   Number of database block hash buckets              16384                          TRUE      FALSE  FALSE
_db_block_hash_latches                   Number of database block hash latches              1024                           TRUE      FALSE  FALSE
SYS@ bys3>show parameter db_block_size
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_block_size                        integer     8192


而一条hash chain上的buffer header数量,没有固定限制(CR块有限制,一条hash chain上的CR块不能超过6个)。从隐含参数_db_block_max_cr_dba中可以查到这个限制:
P_NAME                                   P_DESCRIPTION                                      P_VALUE                        ISDEFAULT ISMODIFIED ISADJ
---------------------------------------- -------------------------------------------------- ------------------------------ --------- ---------- -----
_db_block_max_cr_dba                     Maximum Allowed Number of CR buffers per dba       6                              TRUE      FALSE  FALSE

判断是否有过长的hash chain的语句:过长的hash chain更容易引起热链进而引起CBC LATCH 
SYS@ bys3>select * from (select hladdr,count(*) from x$bh group by hladdr order by 2 desc) where rownum<5;   --x$bh.hladdr表示的是hash chain latch address
HLADDR     COUNT(*)
-------- ----------
2A3A46CC         14
2A7F0864         14
2A3A4EAC         13
2A7F26EC         12
在热链问题发生时,可以通过两种方法来增加hash chain数量:1、调整隐含参数_db_block_hash_buckets --有风险   2.按ORACLE 10G和11G中,bucket数量的默认值是大于2倍的buffer数量的最小的2的幂的值的公式,来计算出让系统自动调整bucket数量时buffer cache需要增加到的大小。--查出现在的_db_block_hash_buckets 数量,除以2,将得出值乘以当前数据块大小(暂不考虑bh大小,也可以把一个bh大小按1K或512bytes来计算),就可以得出要调整到的buffer cache大小。--注意注意:这个调整重启后才生效。
按我测试环境中值来计算:_db_block_hash_buckets 16384 ,db_block_size       8192,一个buffer header按512bytes。想让系统自动调整hash bucket的数量,需要将buffer cache大小调整为大于68M,计算方法如下:
SYS@ bys3>select 16384/2*(8192+512)/1024/1024 "Desired size" from dual;
Desired size
------------
          68
当然了,这种调整buffer cache大小进而增大hash bucket数量的方法是治标了,引起热链问题,不良SQL语句或者高并发是主因,要想从根本上解决热链问题,就要从这些方面入手解决了。--不过要真是buffer cache过小,还是要在系统内存资源允许情况下增大点好。
###########################

3.hash latch:就是latch:cache buffers chains --CBC LATCH

用于保护hash chain结构,一个CBC LATCH管理着多个hash chain。
用到此LATCH的场景:
1.服务进程需要扫描hash chain上的buffer header时或者叫要读取buffer cache中数据块,
2.服务器进程要将新读入的数据块挂载到hash chain上时,

我的测试系统中:hash_buckets  个数是16384 ,CBC LATCH数量是1024,计算出一个CBC LATCH要管理16个hash_chain

P_NAME                                   P_DESCRIPTION                                      P_VALUE                        ISDEFAULT ISMODIFIED ISADJ
---------------------------------------- -------------------------------------------------- ------------------------------ --------- ---------- -----
_db_block_hash_buckets                   Number of database block hash buckets              16384                          TRUE      FALSE  FALSE
_db_block_hash_latches                   Number of database block hash latches              1024                           TRUE      FALSE  FALSE
SYS@ bys3>select count(*) from v$latch_children where name like ‘%cache buffers chains%‘;
  COUNT(*)
----------
      1024
SYS@ bys3>select 16384/1024 from dual;
16384/1024
----------
        16


#############################################################################     
     
4.Data Buffer Cache多缓冲池技术:

指根据数据的不同访问方式,将Data Buffer Cache分为Default,Keep,Recycle.  Default 池则存放未指定存储池 的数据,按照LRU算法管理。Keep 池中 数据倾向于一直保存,可存放经常使用的数据,Recycle池中数据倾向于即时老化,可以存放一次性读取使用的数据。默认所有表(未指定存储的池)使用Default池,大小是数据缓冲区大小。
创建或修改表进指定:alter table test storage(buffer_pool keep);  
BUFFER_POOL { KEEP | RECYCLE | DEFAULT }
语句在10G官方文档-SQL Reference---alter table---storage_clause
ORACLE 9I后一个数据库可以存在2K/4K/8K/16K/32K这五种大小的block,db_block_size 定义的是主block_size。
如果要在数据库中创建不同block_size的表空间,就要设置db_nk_cache_size参数。
每个pool会有至少8个“Latch:cache buffers lru chain”.

5.working set:

每个working set都具有它自己的一组LRU和LRUW链表(LRU和LRUW链表总是成对出现的)。
ORACLE为了提高buffer cache性能(大内存),使用了多个working set
每个working set都由一个名为“Latch:cache buffers lru chain”的latch来保护,每一个lru latch对应一个working set。
而每个被加载到buffer cache的buffer header都以轮询的方式挂到working set上去。
而每个被加载到buffer cache的buffer header都以轮询的方式挂到working set上去。也就是说,当buffer cache加载一个新的数据块时,其对应的buffer header会去找一个可用的lru latch,如果没有找到,则再找下一个lru latch,直到找到为止。如果轮询完所有的lru latch也没能找到可用的lru latch,该进程只有等待latch free等待事件,同时出现在v$session_wait中,并增加“latch misses”。
如果启用了多个DBWR后台进程的话,每个DBWR进程都会对应一个不同的working set,而且每个DBWR只会处理分配给它的working set,不会处理其他的working set。
P_NAME                                   P_DESCRIPTION                                      P_VALUE                        ISDEFAULT ISMODIFIED ISADJ
---------------------------------------- -------------------------------------------------- ------------------------------ --------- ---------- -----
_db_block_lru_latches                    number of lru latches                              8                              TRUE      FALSE  FALSE
SYS@ bys3>select name from v$latch_children where name like ‘%buffers lru%‘;
NAME
----------------------------------------------------------------
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain
cache buffers lru chain

16 rows selected.

SYS@ bys3>select d.blk_size,c.child#,p.bp_name,c.gets,c.sleeps from x$kcbwds d,v$latch_children c,x$kcbwbpd p where d.set_latch=c.addr and d.set_id between p.bp_lo_sid and p.bp_hi_sid order by c.child#;
  BLK_SIZE     CHILD# BP_NAME                    GETS     SLEEPS
---------- ---------- -------------------- ---------- ----------
      8192          1 KEEP                         18          0
      8192          3 RECYCLE                      18          0
      8192          5 DEFAULT                    8887          5
      2048          7 DEFAULT                      18          0
      4096          9 DEFAULT                      18          0
      8192         11 DEFAULT                      18          0
     16384         13 DEFAULT                      18          0
     32768         15 DEFAULT                      18          0

8 rows selected.

每个working set中,还有其它的队列:ckpt queue,ObjectQ、FileQ等,根据块的不同,也可能会同时挂载在这些队列下。
working set与lru latch一一对应。lru latch的数量是由一个隐藏参数:_db_block_lru_latches决定的。
该参数缺省值为DBWR进程的数量×8。该参数最小必须为8,如果强行设置比8小的数值,oracle将忽略你设置的值,而使用8作为该参数值。
###############################################

6.最后结合上图:用一段话来简洁的概括buffer cache的内存结构:


buffer cache中有pool,每个pool中至少有8个Latch:cache buffers lru chain,每个Latch:cache buffers lru chain对应着一个working set,
每个working set中,有多个CBC LATCH来,每个CBC LATCH管理着多个hash bucket,每个hash bucket对应着一条hash chain。
数据块在读入buffer cache中时,同时会在buffer cache中构造一个buffer header,ORACLE对数据块的DBA进行hash运算,根据运算结果将buffer header挂载到相应的hash chain上。
同时,每个working set中,有一对LRU和LRUW链表,buffer cache中的数据块,胜块会挂载到LRUW链表,其它块在LRU链表。也就是buffer cache中的数据块,肯定在LRU和LRUW链表之一:不能同时存在这两个链表上。


DUMP查找:

buffer cache实验1-内存结构图解

原文:http://blog.csdn.net/haibusuanyun/article/details/19084583

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!