从Oracle的ITL等待谈起
昨天一个客户遇到一个因为ITL问题导致锁等待十分严重,严重影响了某个业务。现象是很多DBA都遇到过的enq: TX – allocate ITL entry,关于如何解决这个问题,网上已经有大量的文章说明了,我在这里就不做重复了。今天就这个问题要讨论的是一个更为通用的问题,那就是不同存储结构和MVCC实现方式,对数据库的行锁性能的影响问题。
这个问题实际上在二十年前就有过一些争论,当时是讨论DB2与Oracle的性能对比的时候,刚开始IBM派的DBA认为DB2的性能是可以秒杀Oracle的,而Oracle派通过仔细分析,找到了DB2的一个弱点,就是页锁。与Oracle不同,DB2存在一种特殊的锁,页锁。当时对DB2的页锁也是一知半解,只是知道DB2的某些DML操作会导致RDBMS用页锁来替代行锁,从而导致DML操作锁冲突十分严重,影响并发性能。而Oracle则不会存在这个问题。
这些年DB2技术也在发展,不过页锁和行锁之间的这个矛盾统一体依然存在。这似乎又是一个哲学问题,因为底层采用了HEAP结构,以及MVCC实现方式,导致DB2的锁开销是比较大的。而获取、维护和释放行锁所需的资源与页锁所需的资源大致相同。因此每页的行数越多,行锁消耗的资源就越多。如果使用行锁而不是页锁,则每页 100行的表会在表空间上消耗100倍的锁资源。但是,一次锁一行而不是一次锁一页可以减少锁争用。是考虑节约资源还是考虑减少锁争用,这个问题DB2通过一个策略参数LOCKSIZE来交给应用去解决,当然LOCKSIZE ANY的策略可以自动进行判断,但是这种判断有时候会出现错误,从而出现错误的锁升级,引发应用的性能问题。
Oracle的MVCC实现与DB2有极大的不同,因此Oracle没有显式的引入PAGE LOCK的概念。因此在那场关于页锁行锁的争论中,DB2派毫无悬念的败下阵来。当时的ORACLE DBA都认为,因为Oracle的锁是在行头上的,因此每行都可以独立锁定,因此不需要考虑页锁的问题。而随着对Oracle内部结构的了解,我们还知道了一件事,那就是ITL(事务槽)。
上面的示意图是事务块中与MVCC以及一致性读有关的结构的逻辑图。当Oracle要修改一行数据的时候,会在共享池中分配锁结构的内存结构,从这个结构我们可以找到这个行锁对应的行,在行头标识中会指向一个数据结构ITL,这个ITL是一个24字节的数据结构。
struct ktbit {
kxid ktbitxid; /*事务号*/
kuba ktbituba; /* 最后一次修改undo地址*/
b2 ktbitflg; /* 块中锁的数量*/
ktbitun_t _ktbitun;
ub4 ktbitbas; /* SCN的BASE部分内容*/
}
Oracle通过ITL槽形成实现MVCC一致性读和事务回滚所需要的数据链。每一行的行头指向相应的ITL槽,ITL槽指向UNDO RECORD。这样的结构有个好处是每一行不需要都有独立的24字节来构建这条链,而是使用公用的几个ITL槽来实现。节约反面就是争用,一个事务在一个数据块中修改数据(包含插入、删除、修改)就需要一个事务槽,然后让这个块中所有被修改的行指向这个事务槽。那么当一个数据块上有多个事务的时候,就需要多个事务槽了。为了避免事务因为等待事务槽而影响性能,Oracle设计了一种行数据从下往上增长,ITL槽从上向下增长的存储结构。理论上这种结构能够解决事务槽争用的问题,不够就再扩24字节,产生一个新的事务槽就OK了。实际上在很多应用场景中不是这样的,就像我们昨天遇到的那个客户的性能问题。如果一个数据块中的数据已经写满了,ITL想要扩展24字节的时候就会遇到存储空间不足的问题。这时候事务槽就无法扩展了。那么此时Oracle的行锁机制会体现出什么呢?还是TX contention,不过等待的位置不同了,不是row contention了,而是allocate ITL entry。实际上这种等待不是行级的,而是block级的,此时,Oracle的行锁也从另外一种意义上升级为“块锁”了,这个块上的任何DML语句都会被阻塞。当时参加讨论的双方都还不知道这些技术细节,否则那场辩论又会有新的话题了。解决ITL等待的方法其实很简单,那就是增加表或者索引上的ini_trans参数和加大PCT_FREE的参数。具体的细节本文就不细谈了,网上有大量的文章介绍,要注意的是调整参数后,不会立即起效,因为只有新格式化的块才会使用新的参数,老数据块必须通过索引重建,表MOVE等才会被修改。
对于PG数据库,因为PG独特的MVCC实现方式,行锁升级的问题是不存在的,一种技术实现肯定也不是一点好处都没有的,在某方面的缺陷,可能会在另一方面存在优势。最近听说某基于PG的国产数据库想要在新版本里解决PG的行记录膨胀问题,不知道他们在修改MVCC的实现方式的时候,有没有考虑到行锁页锁的问题,Oracle的解决方案是一种可借鉴的方案。
实际上数据块的结构会对整个数据库的性能特征有十分重要的影响。不过在某些方面具有优势并不等于在任何方面都是优势。LSM-TREE结构在并发写入高性能上获得了好处,在MERGE上就要付出相应的代价。不过幸运的是计算机的算力和存储的性能提升超乎我们的想象,因此很多问题都可以暂时被硬件技术的发展而掩盖。对用户来说,不需要太纠结这些问题,除了十分极端的系统需要考虑这些差异之外,大多数用户和大多数用户的系统可以适合于目前的几乎所有的数据库系统。
《从Oracle的ITL等待谈起》来自互联网,仅为收藏学习,如侵权请联系删除。本文URL:http://www.bookhoes.com/392.html