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


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画了好久的原创:

从这张buffer cache的内存结构图,用一句话来说明
buffer cache中 结构大致是:buffer pool--->working set--->CBC 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     如果是动态SGA管理,应该查:select * from v$sga_dynamic_components;
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

BH buffer header----block_buffers块个数是一一对应的,事实上相等
BH的大小计算-- 即db_cache_size的大小减去block_buffers*8K   --这里数据库的默认块大小是8K

10G中BH的大小:
9I据说是 188byte.
SYS@ ocm1>select 48*1024*1024/5988-8192 from dual;
48*1024*1024/5988-8192
----------------------
            213.418838

在数据库中知道 FILE# BLOCK#如何查询ba buffer address
SYS@ bys3> select ba from x$bh where dbarfil=4 and dbablk=171;   --32位LINUX,需要用SYS用户查X$BH
BA
--------
207A4000    ---内存中的位置,16进制,一个16进制表示4bit,对应32位OS

################################

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。

虚拟机中,CPU是一个,在10G中是有8个LRU LATCH,在11GR2中,是16个LRU LATCH.
SYS@ bys3>select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - Production
PL/SQL Release 11.2.0.4.0 - Production
CORE    11.2.0.4.0      Production
TNS for Linux: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 - Production

SYS@ bys3>@?/rdbms/admin/show_para
Enter value for p: lru_latch
old   3: WHERE i.inst_id = USERENV ('Instance') AND CV.inst_id = USERENV ('Instance') AND i.indx = CV.indx AND upper(i.ksppinm) LIKE upper('%&p%') ORDER BY REPLACE (i.ksppinm, '_', '')
new   3: WHERE i.inst_id = USERENV ('Instance') AND CV.inst_id = USERENV ('Instance') AND i.indx = CV.indx AND upper(i.ksppinm) LIKE upper('%lru_latch%') ORDER BY REPLACE (i.ksppinm, '_', '')

P_NAME                                   P_DESCRIPTION                                      P_VALUE                        ISDEFAULT ISMODIFIED ISADJ
---------------------------------------- -------------------------------------------------- ------------------------------ --------- ---------- -----
_db_block_lru_latches                    number of lru latches                              8                              TRUE      FALSE    FALSE

BYS@ bys3>show parameter cpu_c
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
cpu_count                            integer     1
BYS@ bys3>select addr,child#,name from v$latch_children where name ='cache buffers lru chain';

ADDR         CHILD# NAME
-------- ---------- ----------------------------------------------------------------
290A80DC         16 cache buffers lru chain
290A8058         15 cache buffers lru chain
297FC670         14 cache buffers lru chain
297FC5EC         13 cache buffers lru chain
297883B8         12 cache buffers lru chain
29788334         11 cache buffers lru chain
29714100         10 cache buffers lru chain
2971407C          9 cache buffers lru chain
2969FE48          8 cache buffers lru chain
2969FDC4          7 cache buffers lru chain
2962BB90          6 cache buffers lru chain
2962BB0C          5 cache buffers lru chain
295B78D8          4 cache buffers lru chain
295B7854          3 cache buffers lru chain
29543620          2 cache buffers lru chain
2954359C          1 cache buffers lru chain
SYS@ bys3>select id,name,block_size,current_size,target_size from v$buffer_pool;

        ID NAME                 BLOCK_SIZE CURRENT_SIZE TARGET_SIZE
---------- -------------------- ---------- ------------ -----------
         3 DEFAULT                    8192           36          36
###################3
SYS@ ocm1>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 Linux: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production

SYS@ ocm1>@?/rdbms/admin/show_para
Enter value for p: lru_latch
old   3: WHERE i.inst_id = USERENV ('Instance') AND CV.inst_id = USERENV ('Instance') AND i.indx = CV.indx AND upper(i.ksppinm) LIKE upper('%&p%') ORDER BY REPLACE (i.ksppinm, '_', '')
new   3: WHERE i.inst_id = USERENV ('Instance') AND CV.inst_id = USERENV ('Instance') AND i.indx = CV.indx AND upper(i.ksppinm) LIKE upper('%lru_latch%') ORDER BY REPLACE (i.ksppinm, '_', '')
P_NAME                                   P_DESCRIPTION                                      P_VALUE                        ISDEFAULT ISMODIFIED ISADJ
---------------------------------------- -------------------------------------------------- ------------------------------ --------- ---------- -----
_db_block_lru_latches                    number of lru latches                              8                              TRUE      FALSE    FALSE

SYS@ ocm1>show parameter cpu_c
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
cpu_count                            integer     1
SYS@ ocm1>
SYS@ ocm1>select name from v$latch_children where name ='cache buffers lru chain';
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
8 rows selected.

SYS@ ocm1>select id,name,block_size,current_size,target_size from v$buffer_pool;
        ID NAME                 BLOCK_SIZE CURRENT_SIZE TARGET_SIZE
---------- -------------------- ---------- ------------ -----------
         3 DEFAULT                    8192           48          48

每个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,每个buffer pool使用自己的cache buffers lru chain LATCH,一个数据库实例可以配置:DEFAULT,2KB,4KB,8KB,16KB,32KB,KEEP,RECYCLE 这8种类型的buffer pool,故cache buffers lru chain LATCH的数量最少为8个。每个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链表之一:不能同时存在这两个链表上。




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值