问题概述
在一次数据库监控告警中,我们遇到了一个典型的 DB2 事务日志使用率过高问题,使用率飙升至 98.07%。经过分析,根本原因是一个应用程序句柄为 56644 的索引重建活动事务长时间运行,持续占用事务日志空间,导致数据库无法归档包含该活动事务的日志文件,从而使得日志使用率不断攀升,最终触发告警。
这里给所有 DBA 和应用开发者一个关键提醒:在执行耗时较长的数据变更类 SQL(如大规模重建索引、批量更新/删除)时,务必选择业务空闲时间窗口。更重要的是,要及时提交(COMMIT)或回滚(ROLLBACK)事务。否则,一旦事务日志被填满,数据库为了保护自身一致性,会强制回滚导致日志满时正在执行的 SQL,最终导致操作失败。
问题根因
锁定问题的根源:一个持久的索引重建活动事务。该事务由应用程序句柄 56644 发起,在长达数小时的操作过程中持续占用事务日志空间。DB2 的日志归档机制要求:一个日志文件必须在其包含的所有事务都完成后(提交或回滚)才能被归档并释放空间。由于这个长事务持有最早的日志文件不释放,导致后续所有新生成的日志文件都无法被循环复用,日志空间使用率一路走高至警戒线。
诊断与排查步骤
下面我们复盘一下完整的诊断流程,这些命令和步骤对于处理类似问题具有通用参考价值。
1. 连接至目标数据库
首先,切换到 DB2 实例用户并连接到出现问题的数据库。
su - <db2user>
db2 list active databases
db2 connect to <database_name>
2. 检查当前事务日志使用情况
通过查询管理视图,可以直观地看到数据库的日志总量、已用量、可用量以及使用率。
db2 "select substr(db_name,1,15) as db_name
,(total_log_used_kb+total_log_available_kb)/1024 as total_m
,total_log_used_kb/1024 as total_used_m
,total_log_used_top_kb/1024 as total_used_top_m
,total_log_available_kb/1024 as total_avai_m
,log_utilization_percent
,dbpartitionnum
from SYSIBMADM.LOG_UTILIZATION order by dbpartitionnum"
执行后,输出结果会清晰地显示出极高的 LOG_UTILIZATION_PERCENT,例如接近 98.07%。
DB_NAME TOTAL_M TOTAL_USED_M TOTAL_USED_TOP_M TOTAL_AVAI_M LOG_UTILIZATION_PERCENT DBPARTITIONNUM
--------------- -------------------- -------------------- -------------------- -------------------- ----------------------- --------------
<database_name> 9960 9769 1769 191 98.07 0
3. 定位阻塞源事务
下一步是找出那个“最老”的、导致日志无法归档的活动事务。
db2 "select T.APPL_ID_OLDEST_XACT AGENT_ID,K.APPL_CON_TIME from TABLE(SNAP_GET_DB('',-2)) AS T,TABLE(SNAP_GET_APPL(CAST(NULL AS VARCHAR(128)),-1))
AS K where T.APPL_ID_OLDEST_XACT=K.AGENT_ID"
在问题解决后,此查询会返回空结果。但在问题发生时,它会返回持有最老日志的事务句柄及其开始时间。
4. 使用 db2top 进一步确认
db2top 工具能提供动态、详细的数据库活动视图,是数据库运维的利器。
db2top -d <database_name>
在交互界面中,键入 l 进入日志菜单,可以查看详细的日志文件和活动事务信息。
5. 检查 DB2 事务日志配置
了解当前的日志配置,有助于评估问题发生的背景和调整方向。
su - <db2user>
db2 list active databases
db2 connect to <database_name>
db2 get db cfg |grep -i log
或:
db2 list active databases
db2 get db cfg for <database_name>|grep -i log
关键配置项解读:
LOGFILSIZ:每个日志文件的大小(4KB页数),本例为 51200,即 51200 * 4KB = 200MB。
LOGPRIMARY:主日志文件数量,本例为 10。
LOGSECOND:辅助日志文件数量,本例为 40。
- 总日志空间上限: (主日志数 + 辅助日志数) 日志文件大小 = (10 + 40) 200MB ≈ 10GB。当活动事务消耗掉所有50个日志文件时,就会触发日志满错误。
6. 深入诊断日志 (db2diag.log)
DB2 的诊断日志 db2diag.log 是追溯问题的“黑匣子”。我们需要从中寻找错误信息和事务活动的蛛丝马迹。
db2 get dbm cfg|grep -i diag
cd <DIAGPATH>
tail -20000f db2diag.log |more
tail -n 20000 db2diag.log |grep -A13 -B7 ‘The active log is full’|more
在本次案例的日志中,我们发现了关键时间线:
-
长事务开始:从 2025-07-17-09.53.16.579014 开始,应用句柄 56644 陆续对多张表(如 APPLY_RELATIVE, APPROVE_RELATIVE, CUSTOMER_MEMO 等)执行了大量的 ADM5540W/ADM5541W/ADM5542W(索引开始重建/重建中/重建完成)操作,一直持续到 2025-07-17-11.32.46.032939。
-
日志满错误:在 2025-07-17-11.45.16.854103,DB2 抛出了致命的 ADM1823E 错误:
ADM1823E The active log is full and is held by application handle "56644". Terminate this application by COMMIT, ROLLBACK or FORCE APPLICATION.
这条信息明确指出:活动日志已满,且被应用句柄 56644 持有。解决方案是让该应用执行提交、回滚或强制终止。
-
事务结束后归档恢复:在 ADM1823E 错误出现后不久,从 11.33.00 开始,日志中又出现了连续的 Started archive for log file... 和 Completed archive for log file... 信息。这说明当事务最终被终止(可能是应用侧主动操作或超时)后,被阻塞的日志归档队列得以释放,数据库恢复了正常。
7. 再次确认活动会话
问题解决后,应再次检查,确认阻塞事务已消失。
su - <db2user>
db2 list active databases
db2top -d <database_name>
键入:l
此时,db2top 的活动会话列表中应不再有句柄为 56644 的会话。
解决方案与预防建议
针对此类问题,解决方案是直接且明确的:
立即解决:与应用侧确认,要求其及时提交、回滚或由 DBA 强行终止(FORCE APPLICATION)那个阻塞源事务,释放被占用的日志空间。
例如,DBA 可以执行以下命令强行终止特定应用句柄:
db2 "force application(<app_handle>)"
长期预防:
- 规范操作窗口:将耗时长的 DDL(如重建大表索引)或大批量 DML 操作安排在业务低峰期或维护窗口进行。
- 合理设计事务:避免在单个事务中处理过多的数据量。可以考虑分批提交(Batch Commit)。
- 监控与告警:建立对事务日志使用率、长事务(通过
APPL_ID_OLDEST_XACT)的监控,在达到阈值前提前告警,防患于未然。
- 审视日志配置:根据业务峰值和事务特点,评估并合理设置
LOGPRIMARY、LOGSECOND 和 LOGFILSIZ 参数。但要注意,盲目增大日志空间只是延缓问题,优化事务本身才是根本。
本次对 DB2 事务日志满问题的排查,完整展示了从告警现象到根因定位,再到解决方案的技术路径。掌握这些数据库诊断方法,能帮助我们在云栈社区更好地应对各种棘手的运维挑战。