本文阐述了开发人员和测试人员如何确定 DB2 for z/OS 环境下复杂 Web 应用程序中的死锁原因。简介在任何数据库环境中,死锁检测对于应用程序并发性都是很重要的。就像其他应用程序一样,在复杂 Web 环境中也需要能够确定任何死锁的起因。本文解释了如何配置 DB2 for os/390 的死锁跟踪设置,以启用死锁分析。先阐述了如何指定相关的 DB2 for z/OS 跟踪以获取足够信息,然后说明如何分析这些跟踪报告,并指出引起 DB2 for z/OS 环境中运行的复杂 Web 应用程序出现死锁的不良 SQL 语句。本文假定读者熟悉基本的 z/OS 操作。使用 DB2 Performance Monitor 来配置跟踪Locking 跟踪若要启用 Locking 跟踪,首先打开 IBM DB2 Performance Monitor 应用程序。然后执行下面步骤:配置 Collect Task A 以收集死锁跟踪。设置 Trigger by 4=Immediate Start 以立即激活任务。选择 Locking, Data Type, IFICD, Requesting Location, Plan name and Authid,然后按 Enter。图 1. 配置 Collect Task A
选择数据类型 Lockout,然后按 Enter。在 IFCID Selection 面板中,选择下面的 IFICD,然后按 Enter。105DBID/OBID for database and tablespace translation107Data set open/close information
172Deadlock在 Trace Qualification 面板中,填入 DB 用户名(在本例中为 TUSER03)和 DB 模式(在本例中为 TGUSER03),然后按 Enter。图 2. Trace qualification 面板
在 Trigger Immediately 面板中,填入 DB2 跟踪数据的输出数据集(例如,TGUSER03.DB2PM.TRACE01)。设置 Disposition 为 Overwrite。注重:可以使用其他方法来配置 DB2 跟踪停止触发器(例如,经过一段时间后)。图 3. Trigger immediately 面板按 Enter,完成 Locking 跟踪配置。假如 Web 应用程序运行期间有死锁,则激活 Collect Task A 来收集死锁信息。SQL Activity 跟踪按照下面步骤来配置 SQL Activity 跟踪:配置 Collect Task B 以收集 SQL Activity 跟踪。设置 Trigger by 4=Immediate Start 来立即激活任务。选择 SQL Activity, Data Type, IFCID, Requesting Location, Plan name and Authid,然后按 Enter。选择全部收集数据类型,然后按 Enter。在 IFCID Selection 面板中,选择下面的 IFCID,然后按 Enter:16Start of the first insert20Lock summary
53Describe, SQL commit/rollback or error before SQL analyzed
58End of SQL statement execution
59Start of FETCH
60start of SELECT
61Start of INSERT, UPDATE or DELETE
63SQL statement to be parsed
64start of PREPARE
65start of OPEN CURSOR for static or dynamic SQL
66Start of CLOSE CURSOR for static or dynamic SQL
68Start of ROLLBACK
69End of ROLLBACK
70Start of COMMIT phase 2
71End of COMMIT phase 2
88start of synchronous request (commit phase 1)
89End of synchronous request (commit phase 1)
105DBID/OBID for database and tablespace translation在 Trace Qualification 面板中,填入 DB 用户名(例如,TUSER03)和 DB 模式(例如,TGUSER03),然后按 Enter。在 Trigger Immediately 面板中,填入 DB2 跟踪数据的输出数据集(例如,TGUSER03.DB2PM.TRACE02)。设置 Disposition 为 Overwrite。注重:可以使用其他方法来配置 DB2 跟踪停止触发器(例如,经过一段时间后)。按 Enter 完成 SQL Activity 配置。在 Web 应用程序运行期间,激活 Collect Task B 来收集 SQL 语句。分析跟踪报告以确定不良 SQL 语句Web 应用程序中 DB2 锁的原理通常 Web 应用程序有页锁和行锁。根据创建数据库所使用的数据定义语言 (DDL) 模式文件,可以确定正在使用的锁类型。行锁有三种模式:S(Share)、U(Update) 和 X(Exclusive)。要尽量避免的锁影响是挂起、超时和死锁。当两个或两个以上应用程序进程均持有对资源(该资源是其他进程所需,且没有该资源时进程无法继续进行)的锁时,会发生死锁。下面是关于发生死锁情况的具体解释:JobOne 和 JobTwo 是两个事务。JobOne 访问表 M,并持有页 B 的 X (exclusive) 锁,包含记录 000300。JobTwo 访问表 N,并持有页 A 的 X (exclusive) 锁,包含记录 000010。JobOne 请求表 N 页 A 的锁,同时仍持有表 M 页 B 的锁。因为 JobTwo 持有页 A 的 X 锁,所以作业被挂起。JobTwo 请求表 M 页 B 的锁,同时仍持有表 N 页 A 的锁。因为 JobOne 持有页 B 的 X 锁,所以作业被挂起。这种情况就是死锁。为了改善应用程序的并发性,您需要找到引起死锁的 SQL 语句。然后,优化 SQL 语句以消除死锁。根据死锁报告来分析锁信息作为例子,我们假定当多个顾客同时登录并注册一个商店时发生死锁。您已经得到死锁跟踪报告和 SQL 语句报告。首先,您应检查死锁跟踪报告(在本文中为 TGUSER03.DB2PM.LOCKS)。下面是跟踪报告中一些要害参数的说明,有助于理解该进程:图 4. 跟踪参数
分析一下表 USERS(图 5 和图 6)上的第一个死锁。在图 5 中,可以看到死锁涉及到两个资源。分别是 row X'2B'、page X'00004E'、page USERS、DB SW03DB1 和 row X'2B'、page X'00004C'、table USERS、DB SW03DB1。WAITERS =2 表明死锁中有两个等待者(0CC544053119 和 0E26A4053107)。死锁发生在 12/05/05 06:30:09.40。从图 6 可以看到资源持有者和等待者与图 5 中的相反。等待者(实际上是图 5 中的持有者)正在请求持有者(实际上是图 5 中的等待者)所持有的资源。按照死锁的定义,在这种情况下会发生死锁。现在,利用图 5 和图 6 来总结一下锁关系。从图 5 中可以看到 LUW 0CC544053119 所持有的锁是 row X'2B'、page X'00004E'、table USERS、DB SW03DB1 上的行锁,且保持在 X 状态。等待者 LUW 实例 0E26A4053107 正在请求同一个资源上的 S 锁模式。而在图 6 中,LUW 0E26A4053107 所持有的锁是 row X'2B'、page X'00004C'、table USERS、DB SW03DB1 上的行锁,且保持在 X 状态。等待者 LUW 实例 0CC544053119 正在请求同一个资源上的 S 锁模式。因此发生死锁。最后,请注重图 5 中的 BLOCKER is HOLDER --*VICTIM*,该线程 ("victim") 的作用是回滚以进行其他线程。图 5. Locking 跟踪 —— 死锁报告图 6. Locking 跟踪 —— 死锁报告表 1 总结死锁分析:表 1. 死锁分析LUW 实例
持有的资源(X 锁)
请求的资源(S 锁)
死锁时间表
0CC544053119
SW03DB1.USERS.X'00004E'.X'2B'
SW03DB1.USERS.X'00004C'.X'2B'
06:30:09.41044991
0E26A4053107
SW03DB1.USERS.X'00004C'.X'2B'
SW03DB1.USERS.X'00004E'.X'2B'
06:30:09.41044991
根据 SQL 活动报告来分析 SQL 信息打印 SQL ACTIVITY 跟踪(在本文中为 TGUSER03.DB2PM.SQL),使用死锁所涉及的 LUW INSTANCE 数量(0CC544053119 和 0E26A4053107)进行过滤。可以发现最后一次 commit 操作应正好在死锁出现 (06:30:09.41044991) 前完成。接下来,搜索仅在完成最后一次 commit 操作后执行的 SQL 语句。COMMIT processing in SQL ACTIVITY trace for INSTANCE 0CC544053119
COMMIT RECEIVED06:28:50.72
COMMIT RECEIVED06:28:50.85
COMMIT RECEIVED06:28:50.97
COMMIT RECEIVED06:28:51.04the latest commit before the deadlock occurred.
COMMIT RECEIVED06:30:09.61
COMMIT RECEIVED06:30:09.64
COMMIT RECEIVED06:30:09.73
COMMIT RECEIVED06:30:09.77
COMMIT RECEIVED06:30:09.80因此,应该研究那些访问过 SW03DB1.USERS 且在 06:28:51.04 到 06:30:09.41044991 之间执行的 SQL 语句。如图 7 所示。图 7. SQL 报告
根据锁状态 X 和 S,对于资源 SW03DB1.USERS,在 SELECT 语句之前应是 INSERT 语句。按照同样的方法,对于 INSTANCE 0E26A4053107,可以找到在出现死锁前进行最后一次 commit 的时间.COMMIT processing in SQL ACTIVITY trace for INSTANCE 0E26A4053107COMMIT RECEIVED 06:28:50.65the latest commit before the deadlock occurred.
COMMIT RECEIVED 06:30:49.67然后,研究那些访问过 SW03DB1.USERS 且在 06:28:50.65 到 06:30:09.41044991 之间执行的 SQL 语句。如图 8 所示。图 8. SQL 报告
从图 5 和图 6 中可以看到两个实例 0CC544053119 和 0E26A4053107 正尝试提交 INSTER INTO USERS 和 SELECT FROM USERS SQL 语句。由于 INSERT 和 SELECT 语句之间没有 COMMIT,死锁可能是由表扫描引起的。因此运行并发线程时,出现了死锁。结束语本文阐述了如何使用 DB2 Performance Monitor 工具来收集死锁和 SQL Activity 跟踪。另外,给出了一个例子,演示如何通过分析跟踪找到一个死锁情况所涉及的 SQL 语句。使用该方法,开发人员和测试人员都可以发现不良 SQL 语句,并完成并发性能问题解决方案的第一步。