内容提要:
DB2一个锁的使用在内存中需要占用一定比例的资源,对于数据库的并发应用,如果锁资源占用太多,会导致内存容量等相关性能问题,因此DB2为了减少锁应用所带来的内存开销,提供了DB2锁升级(Lock escalation)的功能。那么究竟什么是锁升级,他是如何工作的? 我们通过本文来了解一下。
正文:
锁升级是通过在表上加非意向性的表锁(S,U,X,Z),同时释放行锁来减少锁的数目从而达到减少锁在内存中开销的目的。锁升级由数据库管理器自动完成,同时是否发生锁升级也是由数据库参数LOCKLIST和MAXLOCKS来决定的。当应用程序使用的LOCKLIST的百分比达到MAXLOCKS指定的值的时候(也就是说如果应用程序所使用锁的数量超出了LOCKLIST*MAXLOCKS的值),数据库管理就执行锁升级,将应用程序的锁内存百分比降低到MAXLOCKS指定的百分比以下。在锁升级过程中将使表中的所有行锁转换成一个单独的表锁。
特别的,如果数据库中已被加上的全部锁所占用的内存空间超出了LOCKLIST定义的大小,那么数据库管理器将找出持有一个表上最多行锁的应用连接,并将这些行锁转换为表锁,从而达到释放LOCKLIST锁内存的目的。
虽然锁升级过程本身不会花费很多时间,但是由于锁升级会导致整个表被锁定这种情况,却会大大降低并发性,整个数据库的性能可能会被后来访问遇见的锁冲突所降低,同时deadlock出现的机率肯定也就高了起来。因此为了避免发生锁升级,我们需要适度调整LOCKLIST和MAXLOCKS这两个参数的值。
锁升级还有可能失败,比如,现在一个应用程序已经在一个表上加了IX锁,表中的某些行上有X锁,另一个应用程序又来请求表上的IS锁,以及很多行的S锁,由于申请的锁数目过多引起了锁升级。这个时候数据库管理器试图为该应用程序申请表上的S锁来减少所需要的锁数目,但是S锁与表上原有的IX锁有冲突,因此锁升级不成功。当锁升级失败时候,引起锁升级的应用程序将收到一个-912的SQLCODE。
再说一下LOCKLIST和MAXLOCKS这两个参数的作用:
LOCKLIST: 参数就指的是数据库的一个锁列表的页面数量(4KB一个页面)。一个数据库只有一个LOCKLIST,这个锁列表包含了连接到该数据库所有并发应用程序所持有的锁。当第一个应用程序连接到数据库中的时候这个LIST的资源就开始分配。
MAXLOCKS: 定义了应用程序持有的锁占LOCKLIST的百分比。当任何一个应用程序所使用的锁数量占整个LOCKLIST大小的百分比达到了MAXLOCKS时,数据库管理器会升级这些锁,也就是说会用表锁来代替行锁,从而减少列表中锁的数量。当通过锁升级使得LOCKLIST被占用比例小于MAXLOCKS时候锁升级就会停止。特别需要注意的是MAXLOCKS参数和MAXAPPLS参数的值的乘积绝对不能小于100。
在32bit的系统平台,每一个锁需要申请48或96个字节的锁列表资源。到底是48个还是96个字节取决于在对象上如何加锁。下面是一个原则:
* 96 bytes are required to hold a lock on an object that has no other locks held on it.
* 48 bytes are required to record a lock on an object that has an existing lock held on it.
在64bit系统平台(except HP-UX/PA-RISC), 每一个锁需要申请64或128个字节的锁列表资源。到底是64个还是128个字节取决于在对象上如何加锁。下面是一个原则:
* 128 bytes are required to hold a lock on an object that has no other locks held on it.
* 64 bytes are required to record a lock on an object that has an existing lock held on it.
在64bit HP-UX/PA-RISC的系统平台, 每一个锁需要申请80或160个字节的锁列表资源。到底是80个还是160个字节取决于在对象上如何加锁。下面是一个原则:
* 160 bytes are required to hold a lock on an object that has no other locks held on it.
* 80 bytes are required to record a lock on an object that has an existing lock held on it.
刚才提到了Lock Escalation会导致死锁和降低整体DB2数据库的性能,我们平时工作生活中如何设置LOCKLIST和MAXLOCKS两个参数来尽量避免锁升级的发生呢?
LOCKLIST参数的设置:
如果这个参数被设置为AUTOMATIC,那么就意味着让DB2数据自己根据系统的内存负载需要去调节这个参数。因为DB2可以在不同的内存组件中交换 (trades)内存资源。因此我们可以了解到如果要想开启自动调整功能,至少需要有两个相关组件被开启使得这种自动调整可以实现。注意在开启 AUTOMATIC之前,数据库参数self_tuning_mem这个配置参数一定要设置为ON。
$ db2 get db cfg for perfdb | grep -i self_tuning_mem
Self tuning memory (SELF_TUNING_MEM) = ON
1. 根据具体环境计算出LOCKLIST的使用下限:
(512 * x * maxappls) / 4096
with Concentrator enabled:
(512 * x * max_coordagents) / 4096
in a partitioned database with Concentrator enabled:
(512 * x * max_coordagents * number of database partitions) / 4096
其中512是估计的平均一个应用程序持有的锁的数量,x表示对象(已有一把锁)上每把锁所需要的字节数(48 bytes on 32-bit platforms, 64 bytes on 64-bit platforms).
2. 根据具体环境计算出LOCKLIST的使用上限:
(512 * y * maxappls) / 4096
其中y是某对象上第一把锁所需的字节数. (96 bytes on 32-bit platforms, 128 bytes on 64-bit platforms).
3. 根据我们在第1,2步得出的数据,估计数据库可能出现的并发数。选择一个在上限和下限之间的一个值,来对LOCKLIST进行初始设定。
4. 在系统运行过程中,我们可以利用database system montior来根据系统状况不断的对系统进行调整。
如果在我们的应用环境中MAXAPPLS和MAX_COORDAGENTS被设置成AUTOMATIC,那么我们也应该将LOCKLIST设置为AUTOMATIC.
如果我们增加了MAXAPPLS参数,那么LOSTLIST也应该被增加, 如果你更改了这个参数,就应该考虑rebinding应用程序.
MAXLOCKS参数的设置:
如果这个值设置为AUTOMATIC,那么就可以被设置为自动调节. 这样一来DB2就可以使用Memory Tuner动态的来设置和这个参数控制有关的内存区域。需要注意的是在DB2 V9.7中如果我们将LOCKLIST设置为AUTOMATIC后,那么MAXLOCKS也会默认被设置为AUTOMATIC,可以说这两个参数是密切相关的。反过来也是这样。当然对于AUTOMATIC的设置,我们需要DB2本身要开启self tuning memory的特性(self_tuning_mem configuration parameter is set to ON).
$ db2 get db cfg for perfdb | grep -i self_tuning_mem
Self tuning memory (SELF_TUNING_MEM) = ON
下面的这些原则是设置MAXLOCKS参数的公式:
maxlocks = 2 * 100 / maxappls
其中2表示应用程序拥有平均两倍的的锁, 100则表示一个百分比。
如果我们运行的并发应用程序不多,我们可以利用下面的公式:
maxlocks = 2 * 100 / (average number of applications running concurrently)
通常在设置MAXLOCKS参数的时候,我们应该将LOCKLIST的设置考虑在内。实际上一个应用程序在什么时候会发生锁升级呢?我们可以量化这个设置(锁数量的临界值)。突破这个设置那么锁升级就会发生:
maxlocks * locklist * 4096 /(100 * 48) on a 32-bit system
maxlocks * locklist * 4096 /(100 * 80) on a 64-bit system HP-UX/PA-RISC environment
maxlocks * locklist * 4096 /(100 * 64) on other 64-bit systems
对于MAXLOCKS的设置需要注意的是,如果MAXLOKS的设置过低,在LOCKLIST还拥有大量锁页面容量的情况下,仍然会发生锁升级。而如果 MAXLOCKS设置过高,可能会导致部分应用占用大量LOCKLIST资源,导致LOSTLIST资源被耗尽,从而导致其他应用程序只能面临锁升级。
在对LOCKLIST和MAXLOCKS参数进行设置后,在数据库运行过程中,我们可以使用Database System Monitor来帮助我们自己跟踪和调整这两个配置参数。
$ db2 connect to perfdb
Database Connection Information
Database server = DB2/AIX64 9.5.5
SQL authorization ID = DB2INST1
Local database alias = PERFDB
$ db2 get db cfg for perfdb | grep -i locklist
Max storage for lock list (4KB) (LOCKLIST) = 100000
$ db2 get db cfg for perfdb | grep -i maxlocks
Percent. of lock lists per application (MAXLOCKS) = 50
$ db2 get monitor switches
Monitor Recording Switches
Switch list for db partition number 0
Buffer Pool Activity Information (BUFFERPOOL) = ON 07/12/2010 13:43:47.241297
Lock Information (LOCK) = ON 07/12/2010 13:43:47.241297
Sorting Information (SORT) = ON 07/12/2010 13:43:47.241297
SQL Statement Information (STATEMENT) = ON 07/12/2010 13:43:47.241297
Table Activity Information (TABLE) = ON 07/12/2010 13:43:47.241297
Take Timestamp Information (TIMESTAMP) = ON 07/12/2010 13:43:47.241297
Unit of Work Information (UOW) = ON 07/12/2010 13:43:47.241297
$ db2 get snapshot for database on perfdb | grep -i lock
Locks held currently = 0
Lock waits = 5
Time database waited on locks (ms) = 120110
Lock list memory in use (Bytes) = 13376
Deadlocks detected = 0
Lock escalations = 1
Exclusive lock escalations = 1
Agents currently waiting on locks = 0
Lock Timeouts = 4
Internal rollbacks due to deadlock = 0
Number of MDC table blocks pending cleanup = 0
Memory Pool Type = Lock Manager Heap
这里,如果Lock list memory in use (Bytes)超过定义LOCKLIST的百分之50,那么就应该增大LOCKLIST的参数中4kb页面的数量。如果发生的Lock escalations大于0或者Exclusive lock escalations大于0,那么就应该增大LOCKLIST和MAXLOCK的参数.
参考资料:
关于LOCKLIST的参数说明:
http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.config.doc/doc/r0000267.html
关于MAXLOCKS的参数说明:
http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.db2.luw.admin.config.doc/doc/r0000268.html
添加新评论0 条评论