ITPub博客

首页 > 数据库 > Oracle > 资源供给:并发性控制和buffer lock

资源供给:并发性控制和buffer lock

原创 Oracle 作者:sunsapollos 时间:2013-12-07 00:31:30 0 删除 编辑
       buffer busy wait的运行案例很多,但记忆中没有非常清晰的,居然无法在案头写个简单案例,惭愧。
       在写之前简单的搜索知识点整理些思路的时候,发现这片文章不错:http://www.itpub.net/thread-1801066-1-1.html,大家主要参考这篇文章可以了解buffer lock是如何运作的,本来计划要写buffer lock之一和之二的,现在用不着了。说实话,我以前一直简单以为CR块是不存在X的,为了写这篇东西需要补充些知识,才发现是存在CRX的,惭愧的很。
      不过,我一直强调一个观点,性能优化者并不太需要了解所谓的内核和原理,次序错误也关系不大,只要大致知道就可以了。如果性能优化者一定要了解内核和原理,那么Oracle核心开发小组就会成为性能优化专家,但是大家都知道,大部分开发人员不具备性能优化能力。当然你如果在局部点遇到了性能优化不可理解的事情,那这个需要理解内核和原理运行,就好像需要了解业务一样。只有在性能优化者遇到了不可思议的现象的时候,内核和原理运行才会成为性能优化者的巨大助力。可惜这种情况会比较少遇到,所以在实践中更好的方式为你有些可靠的精通内核的外援或者收集他们的文章就可以了,在需要的时候进行咨询或者查看。
      大家阅读参考的文章之后应该可以基本明确buffer lock的运行,这里不再重复,只是简单强调两点(1)、buffer lock和tx lock不同,buffer lock仅仅作用于修改的瞬间,也就是所谓的pin,只有在获得pin才可以修改块,而tx lock则作用于整个事务周期。(2)、buffer lock不是作用buffer block,所以不涉及到redo,而tx作用于block,涉及到redo。
     
      Buffer lock的冲突的发生首先必须要有写:
         写数据块
         延迟块清理
         dbwr写(应该会加载buffer lock)
          commit或者rollback(直接更新)
     
     从上面描述可以看出,大家不要奇怪select|select会产生buffer busy waits,延迟块清理事实上对于数据块产生了更新。
     commit或者rollback同样对于数据块进行了更新(Undo Segment Header或者data Block),导致select|select产生buffer busy waits
        
      主要看看我们如何来解决涉及到buffer lock的冲突问题。  
      buffer lock的冲突来源于以下三个方面:
      (1)、buffer lock的获取需求量太大
      (2)、buffer lock在某些热点快的需求量太大
      (3)、buffer lock的更新速度太慢
     在一个固定的业务系统,更新记录的数量是业务特征决定的,也就是说,相对来说更新是不可优化。而通过访问多少数据块来获得更新一行记录则是一个弹性很大的区域,也就是这部分具有相当的可优化空间。

     只有更新才会发生buffer lock冲突,这里就可以明显看出CBC latch和buffer lock的冲突类型。CBC latch会极为频繁的作用于Index root block和branch Block上,而Buffer lock会比较少的作用在index root block和branch block上,因为这里的更新相对比较少。

      buffer lock的获取需求量太大
      buffer lock的获取量和逻辑读是密切相关的,当固定的db block change和大量的逻辑读相遇的时候就很有可能会产生buffer lock之间的冲突。降低获取一行需要访问的数据块数量自然就可以降低buffer lock的获取需求。遗憾的是降低逻辑读数量的几乎唯一办法就是调整SQL。更加遗憾的是似乎Oracle没有提供关于buffer busy waits的Block的统计信息记录。我们可以主要依赖一下信息来获得buffer lock的冲突量:
     (1)、v$waitstat仅仅记录了在不同数据块类型上的冲突。
     (2)、Buffer lock总是在CBC latch的保护之下获得,从CBC latch的覆盖我们可以侧面获得buffer lock的获得情况,从其覆盖的数据块数量来判断是否存在热点块。
     (3)、v$active_session_history粗略的记录了buffer lock冲突涉及的Block信息。
     (4)、以ms级速度直接访问SGA,可以获得比较v$active_session_history更加细致的信息。

    
      当每个CBC latch保护的数据块相对均匀的时候,我们一般可以认为数据热点的分布相对均匀。 


      buffer lock在某些热点快的需求量太大
      热点在哪里? 大家必须要注意到,只有被更新的时候才会产生buffer lock,所以一般情况下更新频繁的块,也就是buffer lock冲突多的块,也就是所谓的热点。这个观点对于某个时刻的运行是不正确的,但是对于持续运行一段时间的buffer lock统计是正确的。      
      CBC Latch覆盖的数据块越长,说明该latch的保护数据也越热,CR块越多表示该数据块越热。
      常见来说的热点数据块:
      Segment Header:
             全表扫描必须访问块头
             更新,插入和删除必须访问块头(Freespace的变化)
             显然一个索引访问的查询表格不会产生buffer lock(read,write)。

             显然索引访问可以降低在segment Header之上的Buffer Lock冲突
      undo segment header:
            事务开始必须访问Undo segment header,分配事务表
            事务扩展Undo Block需要访问Undo Segment Header,管理free block pool
            consistent read需要访问Undo segment Header,检查延迟提交,检查retention有效性
            可以看到虽然会产生大量的访问Undo segment header,但是在undo Segment Header的更新访问还是比较有限的。

            显然更多的回滚段可以降低Undo segment header之上的buffer lock冲突
      undo segment block
       一个Undo segment Block可以容纳更多Block的Undo Image信息,访问不同数据块的Consistent read会同时访问相同的Undo Block,但是每个Undo Block只能被一个事物所使用,也就是undo Block从来不会产生write|write的Buffer lock冲突,而只会产生read|write冲突。
      在undo segment Block上的冲突似乎只能通过降低Consistent read的访问量来完成,也就是降低逻辑读数量。
      ASSM Block(1st,2st,3st) or Freelist Block
      ASSM Block和Freelist Block之间只会产生write|write冲突,而且由于Update操作很少会涉及到ASSM Block或者FreeList Block的变化,很少会有冲突发生。在业务系统应用中,由于Delete操作往往比较少,更多的冲突会发生在Insert操作之间或者Insert和Delete操作。
     降低ASSM Block冲突的最简单方式为分区,分区对于ASSM Block冲突具有以下两个好处:
     (1)、增加ASSM Block,分散操作的插入点
      (2)、减少ASSM Block的层次,加快访问速度
 
      Segment tail Block(Insert Point Block):
      表格为堆组织,数据插入总是在堆尾,在堆尾总是会产生更多的插入热点。
      对于频繁删除形成freelist block的表格,ASSM管理也很有可能缺乏智能化总是选择某个Block进行同时插入(有待验证)。
     
      减少Segment tail Block冲突的最佳方法为分区,提供多个不同的插入点

      Index leaf block
      索引块由于其存储更多的数据行信息使其比较表格更加容易受到Buffer Block的影响(Index leaf block的并发访问程度更高)。
     
      Index leaf block header or tail
      单调增长或者单调降低的索引是业务中最主要的插入热点冲突所在(buffer lock)

     降低冲突的主要方法也是建立分区,利用分区能力把该索引分布到不同的段中。主要并不是在这个索引上建立分区索引,而是依赖于其他列的分区把该索引分布到不同的分区中去。 
      理论上反向索引可以降低冲突,但是反向索引在绝大部分业务系统中不具有可操作性。

      表格热点数据块
      表格热点数据块的主要手段就是分布,分布有以下几种不同的方式:
      更高的pct free,使行数据分配到不同的数据块中。这种方式往往只有在小型表格中可以生效,大型表格的空间浪费和全表扫描导致的性能损失往往是不能忍受的。
      合适的分区,使数据落到不同的数据块,如果可以进行合适的分区,最好的方式。
      重新分布热点数据块的行,需要定期对于热点进行维护。
    
     Buffer Lock的更新速度太慢:
     当更新进程拥有buffer lock的时间太长,自然就会引起buffer lock冲突。
     块更新,事实上包含两部分,Oracle遵循Log ahead协议,所有更新必须首先写redo。
     也就是一个块更新包含两部分操作:write log Buffer,Write Data Block。
     而commit或者rollback会更加严重,估计会包含log file sync的时间。

     为什么会更新慢?
        更新的行数比较多
        IO速度太慢导致从磁盘读取到内存的速度很慢,这个在10g演变为一个独立的等待事件:read by other session。
        内存更新的速度太慢
,页面交换往往会引起内存更新的速度降低,可以检查操作系统配置以及vmstat交换情况。
        由于故障或者其他原因进行内存Block Dump。
        磁盘IO写太慢,导致dbwr进程长时间持有Buffer lock(待验证)。
        pctfree太小,引起行迁移。
        Log buffer不足
        日志写速度太慢
        日志发生切换导致阻塞
   
     关于Buffer busy waits和Log Buffer以及Online Redo Logfile之间的关系也许存在争议,有必要的话我会构造案例来验证这种说法是否正确。
    包括dbwr进程慢会导致buffer busy waits慢,也是一个需要验证的话题,有必要的会构造验证正确性。

可以参考的视图信息:
      x$kcbfwait: 文件上的buffer waits次数和时间
      v$waitstat:不同数据块类型的buffer waits
      v$session_wait:即时的会话buffer waits
      v$session_wait_history: 最近10次的wait
      v$active_session_wait:每秒的buffer wait,特别是依据该视图可以获得某个Block的并发等待队列信息。
      v$system_event: 系统的buffer wait
      v$eventmertic:最近1分钟的buffer wait       
     v$event_histogram: 事件柱状图


     和TX lock一样,Buffer lock冲突是不可避免的,关键问题是不能让Buffer lock的等待队列过长,等待队列过长将导致长时间的延迟。
     多长的等待队列长度是可以接收的,这个问题有待研究和验证? 下面做一个简单的推论:
     Write一个Buffer Block假设为10微秒,0.5ms为可以接收buffer busy waits等待,那最长的等待队列长度为50个。也许用队列这个词不好,由于Oracle具有在一定时间的Buffer Lock唤醒机制,我更愿意相信Buffer lock采用队列机制和竞争机制的混合用法,而不是单纯的队列锁。虽然是队列所还是队列+竞争的模式对于性能优化并没有本质性的影响,但感兴趣的人可以去研究一下Buffer lock究竟采用什么样的机制来获得buffer pin的。





         

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

请登录后发表评论 登录
全部评论
专注于Oracle,BI,Security,DR &^BCP,Performance tuning

注册时间:2013-10-15

  • 博文量
    68
  • 访问量
    725324