Oracle Data Buffer Cache

5,131 views

Published on

Oracle Database internal info

Published in: Technology, Business
2 Comments
3 Likes
Statistics
Notes
No Downloads
Views
Total views
5,131
On SlideShare
0
From Embeds
0
Number of Embeds
390
Actions
Shares
0
Downloads
219
Comments
2
Likes
3
Embeds 0
No embeds

No notes for slide

Oracle Data Buffer Cache

  1. 1. data buffer cache 管理机制浅析
  2. 2. 内容 <ul><li>Oracle 如何寻找到需要的 buffer? </li></ul><ul><li>Oracle 如何管理 data buffer cache 里面的块? </li></ul><ul><li>Oracle 如何确定哪些块应该写入数据文件,如何写? </li></ul><ul><li>和 Data buffer cache 相关的一些等待事件 </li></ul>
  3. 3. 引入 <ul><li>Instance 最大的内存区域 </li></ul><ul><li>db_cache_size 参数 </li></ul><ul><li>分配单位: granule </li></ul><ul><li>提供了 default 、 keep 、 recyle 三种不不同类型的 cache </li></ul><ul><li>多种数据块尺寸( 2 、 4 、 8 、 16 或 32k )的 buffer cache 对应不同的 blocksize 数据块 db_nk_cache_size </li></ul>
  4. 4. 定位 buffer <ul><li>Buffer 存放的位置: </li></ul><ul><li>The hash bucket for a particular block header is determined based on the modulus of the Data Block Address (DBA) and the value of the _DB_BLOCK_HASH_BUCKETS parameter. For example, hash bucket = MOD(DBA, _DB_BLOCK_HASH_BUCKETS). </li></ul><ul><li>先在 PGA 中构造 buffer discriptor 内存结构,同需要的锁定模式一起传入搜索函数, hash 算法找到对应的 bucket </li></ul><ul><li>搜索函数: kcbget(descriptor,lock_mode) </li></ul>
  5. 5. Buffer cache 示意图 _db_block_hash_buckets _db_block_hash_latches
  6. 6. BH 结构 <ul><li>视图: X$BH V$BH </li></ul><ul><li>BH (0x0x5cfce8c4) file#: 45 rdba: 0x0b417f8f (45/98191) class 1 ba: 0x0x5c73e000 </li></ul><ul><li>set: 5 dbwrid: 0 obj: 198268 objn: 198268 </li></ul><ul><li>hash: [6893c08c,6893c08c] lru: [61ff9348,57fee018] </li></ul><ul><li>LRU flags: hot_buffer </li></ul><ul><li>ckptq: [NULL] fileq: [NULL] </li></ul><ul><li>st: XCURRENT md: NULL rsop: 0x(nil) tch: 2 </li></ul><ul><li>LRBA: [0x0.0.0] HSCN: [0xffff.ffffffff] HSUB: [255] RRBA: [0x0.0.0] </li></ul>
  7. 7. Hash chain+BH <ul><li>CHAIN: 4889 LOC: 0x0x5a6e4100 HEAD: [51fdf58c,56fcc874] </li></ul><ul><li>BH (0x0x51fdf58c) file#: 1 rdba: 0x00402432 (1/9266) class 1 ba: 0x0x51a1a000 </li></ul><ul><li>set: 12 dbwrid: 0 obj: 3807 objn: 3807 </li></ul><ul><li>hash: [56fcc874,5a6e4100] lru: [51fdf8c4,51fdeff4] </li></ul><ul><li>LRU flags: </li></ul><ul><li>ckptq: [NULL] fileq: [NULL] </li></ul><ul><li>st: XCURRENT md: NULL rsop: 0x(nil) tch: 7 </li></ul><ul><li>LRBA: [0x0.0.0] HSCN: [0xffff.ffffffff] HSUB: [255] RRBA: [0x0.0.0] </li></ul><ul><li>buffer tsn: 0 rdba: 0x00402432 (1/9266) </li></ul><ul><li>scn: 0x0000.000071f9 seq: 0x01 flg: 0x04 tail: 0x71f90601 </li></ul><ul><li>frmt: 0x02 chkval: 0x42ef type: 0x06=trans data </li></ul>
  8. 8. Hash chain 上的搜索 <ul><li>For each buffer in the chain: </li></ul><ul><li>- Ignore buffers that do not match RDBA </li></ul><ul><li>- Wait for READING buffer and return them </li></ul><ul><li>- Skip CR (consistent read) buffers </li></ul><ul><li>- If the CUR (current) buffer is held in a compatible mode, then use it </li></ul><ul><li>- Otherwise if all other users are CR state objects </li></ul><ul><li>– Make it a CR copy and create a new EXLCUR copy of the buffer </li></ul><ul><li>– Or wait for the current buffer to be released </li></ul><ul><li>If no usable buffers exist in cache, read from disk </li></ul><ul><li>搜索的时候,需要持有 cache buffer chain latch </li></ul>
  9. 9. Working sets _db_block_lru_latches 缺省值为 DBWR 进程的数量 ×8 (允许的最大的 buffer pool 数量)
  10. 10. Working sets <ul><li>Each list that is shown above will have sublists called the auxiliary write list (AUX) and a MAIN list. For example, the LRU-P list will have a LRUP-AUX and a LRUP-MAIN list. </li></ul><ul><li>LRU-XR, LRU-XO and LRU-P are also called write lists.buffers are linked to these due to a specific write action. </li></ul><ul><li>these lists are candidates for immediate write-outs by the DBWR. </li></ul><ul><li>enable write prioritization capabilities </li></ul><ul><li>一个 BH 只能在 LRU 或 LRUW 上,但能存在多个 write list 上 </li></ul>
  11. 11. working sets <ul><li>Dump of buffer cache at level 10 </li></ul><ul><li>(WS) size: 501 wsid: 1 state: 0 </li></ul><ul><li>(WS_REPL_LIST) main_prev: 5a6ff9bc main_next: 5a6ff9bc aux_prev: 58fffd08 aux_next: 58fa4048curnum: 501 auxnum: 501 </li></ul><ul><li>cold: 5a6ff9bc hbmax: 0 hbufs: 0 </li></ul><ul><li>(WS_WRITE_LIST) main_prev: 5a6ff9d8 main_next: 5a6ff9d8 aux_prev: 5a6ff9e0 aux_next: 5a6ff9e0curnum: 0 auxnum: 0 </li></ul><ul><li>(WS_XOBJ_LIST) main_prev: 5a6ff9f4 main_next: 5a6ff9f4 aux_prev: 5a6ff9fc aux_next: 5a6ff9fccurnum: 0 auxnum: 0 </li></ul><ul><li>(WS_XRNG_LIST) main_prev: 5a6ffa10 main_next: 5a6ffa10 aux_prev: 5a6ffa18 aux_next: 5a6ffa18curnum: 0 auxnum: 0 </li></ul><ul><li>(WS) fbwanted: 0 </li></ul><ul><li>(WS) bgotten: 0 sumwrt: 0 sumscan: 0 </li></ul><ul><li>(WS) numscan: 0 hotscan: 0 dmoves: 0 </li></ul><ul><li>MAIN RPL_LST Queue header (NEXT_DIRECTION)[NULL] </li></ul><ul><li>MAIN RPL_LST Queue header (PREV_DIRECTION)[NULL] </li></ul><ul><li>AUXILIARY RPL_LST Queue header (NEXT_DIRECTION)[58fa4048,58fffd08] </li></ul><ul><li>0x58fa4000=>0x58fa42f0=>0x58fa45e0=>0x58fa48d0=>0x58fa4bc0=>0x58fa4eb0=>0x58fa51a0=>0x58fa5490 </li></ul><ul><li>0x58fa5780=>0x58fa5a70=>0x58fa5d60=>0x58fa6050=>0x58fa6340=>0x58fa6630=>0x58fa6920=>0x58fa6c10 </li></ul><ul><li>0x58fa6f00=>0x58fa71f0=>0x58fa74e0=>0x58fa77d0=>0x58fa7ac0=>0x58fa7db0=>0x58fa80a0=>0x58fa8390 </li></ul>
  12. 12. 确定可重用 buffer 的过程 <ul><li>8i: 从 list 的尾端开始 scan ,将冷端的 buffer head 所指向的内容牺牲掉 </li></ul><ul><li>9i: 当查询所需要的块需要从磁盘读进来,挂在 lru 链上时, </li></ul><ul><li>从 list 的尾端开始 scan ,先扫描辅 list ,再扫描主 list </li></ul><ul><li>lru 算法 +touch count 数 </li></ul><ul><li>热块往主 list 上移动,从中插入主 list 。辅 list 上空了之后,执行相同的算法在 Lru 中找出可牺牲的块,换到辅 list 上 </li></ul>
  13. 13. LRU 算法 <ul><li>IF ( touch count of scanned buffer >_db_aging_hot_criteria ) </li></ul><ul><li>THEN </li></ul><ul><li>Give buffer another chance (do not select as a victim) </li></ul><ul><li>IF (_db_aging_stay_count >= _db_aging_hot_criteria) THEN </li></ul><ul><li>Halve the buffer's touch count </li></ul><ul><li>ELSE </li></ul><ul><li>Set the buffer's touch count to _db_aging_stay_count </li></ul><ul><li>END IF </li></ul><ul><li>ELSE </li></ul><ul><li>Select buffer as a victim </li></ul><ul><li>END IF </li></ul>
  14. 14. LRUW <ul><li>LRUW list: </li></ul><ul><li>The LRU-W (write) list is used to hold buffers that aged out of the LRU but need to be written to disk before they can be reused. </li></ul>
  15. 15. block 更改的过程 <ul><li>Update block 的过程: </li></ul><ul><li>假如我要修改 BH2 指向的块的内容 </li></ul><ul><li>1)oracle 会将 BH2 从辅助 LRU 链表上摘下,同时插入主 LRU 链表的中间,也就是插入 BH1 和 BH4 中间,同时增加 BH2 的 touch 的数量。 2)  将该 BH2 的标记设置为钉住( ping )。( latch 保护) 3)  更新 BH2 对应的内存数据块的内容。 4)  更新完以后,取消钉住的标记。 5)  将 BH2 从主 LRU 链表转移到主 LRUW 链表上。 6)  如果这个时候又有进程发出更新 BH2 所对应的内存数据块的内容,则 BH2 再次被钉住,更新,取消钉住。 7) DBWR 启动以后,在扫描主 LRUW 链表时会将 BH2 转移到辅助 LRUW 链表上。 </li></ul><ul><li>8) DBWR 将辅助 LRUW 链表上的 BH2 对应的数据块写入数据文件。 9)  确认成功写入数据文件以后,将 BH2 从辅助 LRUW 链表上转移到辅助 LRU 链表上 </li></ul>
  16. 16. checkpoint <ul><li>Checkpoints ( checkpoint queue latch ) </li></ul><ul><li>To ensure that the data blocks that have their redo </li></ul><ul><li>generated up to a certain point in the redo log (RBA) are written to the disk </li></ul><ul><li>Checkpoint structure includes: </li></ul><ul><li>– Checkpoint SCN </li></ul><ul><li>– Checkpoint RBA </li></ul><ul><li>– Thread that allocated the checkpoint </li></ul><ul><li>– Enabled thread bitmap </li></ul><ul><li>Timestamp </li></ul><ul><li>关于 DDL: </li></ul><ul><li>The Oracle server ensures that the DDL is successfully mini-checkpointed before the DROP (which depends on the SCN and seq# of the data blocks within the object). </li></ul>
  17. 17. CKPTQ & FQ Pre-Oracle8 DBWR scanned the entire cache to find buffers with checkpoint bit set. CKPTQ and FQs eliminate this scan. – When the buffer is first modified, it is inserted into the CKPTQ in RBA order – The buffer is also inserted into the appropriate FQ When a checkpoint is initiated, DBWR writes all buffers on the queue until the checkpoint RBA is less than the head of the CKPTQ RBA. 全量检查点发生条件: 发出命令: alter system checkpoint ; 除了 shutdown abort 以外的正常关闭数据库。
  18. 18. DBWR 触发条件: 1.Lru 链上扫描以查找可以覆盖的 buffer header 时,如果已经扫描的 buffer header 的数量到达一定的限度(由隐藏参数: _db_block_max_scan_pct 决定,我的库中是 40 ) 2. 当 DBWR 在主 LRUW 链表上查找已经更新完而正在等待被写入数据文件的 buffer header 时,如果找到的 buffer header 的数量超过一定限度(由隐藏参数: _db_writer_scan_depth_pct 决定 我的库中是 25 ) 3. 如果主 LRUW 链表和辅助 LRUW 链表上的脏数据块的总数超过一定限度,。该限度由隐藏参数: _db_large_dirty_queue (我的库是 25 )决定。 4. 完全检查点时触发 DBWR 。 5. 将表空间设置为离线( offline )状态时触发 DBWR 。 6. 发出命令: alter tablespace … begin backup ,从而将表空间设置为热备份状态时触发 DBWR 。 7. 将表空间设置为只读状态时,触发 DBWR 。 8. 删除对象时(比如删除某个表)会触发 DBWR 。
  19. 19. 写数据 DBWR 会将要写的脏数据块所对应的 buffer header 拷贝到一个名为批量写( write batch )的结构中。每个 working set 所对应的 DBWR 进程都可以向该结构里拷贝 buffer header 。当 write batch 的 buffer header 的个数达到一定限额时,才会发生实际的 I/O
  20. 20. 等待事件 <ul><li>buffer busy waits </li></ul><ul><li>P1=file# p2=block_id p3= reason code </li></ul><ul><li>Reason code 130 和 220 是最常见 </li></ul><ul><li>Free buffer waits </li></ul><ul><li>If a session spends a lot of time on the free buffer waits event, it is usually due to one or a combination of the following five reasons: </li></ul><ul><li>Inefficient SQL statements </li></ul><ul><li>Not enough DBWR processes </li></ul><ul><li>Slow I/O subsystem </li></ul><ul><li>Delayed block cleanouts. </li></ul><ul><li>Small buffer cache </li></ul>
  21. 21. 等待事件 <ul><li>Latch free </li></ul><ul><li>– Cache buffers chain </li></ul><ul><li>热点块问题 </li></ul><ul><li>可以通过 v$session_wait 的 p1raw 字段来判断 latch free 等待事件是否是由于出现了热点块。如果 p1raw 保持一致,那么说明 session 在等待同一个 latch 地址,系统存在热点块。 </li></ul><ul><li>– Cache buffers lru chains </li></ul><ul><li>– Checkpoint queue latch </li></ul>

×