DB2事务日志使用经验

责任编辑:晓熊    做者: IT168 徐晓锋   2008-11-24  
  咱们常常接到客户的电话,个人数据库日志满了,有没有什么好办法快速清除?尤为对于一些初入门的DB2使用者去维护一个大数据量的系统,这几乎是他们必然会碰到的一个问题。
  咱们也常常接到客户更紧急的电话,个人数据库不能使用了,由于日志占用太多空间,文件系统满了,就把日志删除了,如今数据库没法使用,这个是生产系统,须要尽快恢复,有什么办法可让数据库马上使用?
  碰到这样的问题,咱们能够不厌其烦的一遍遍向客户解释这个问题的缘由,也能够给出很是明确的解决方案,可是对于不少客户看来,这彷佛是一个比较无奈的解决方案,他们只能承担着这种操做带来的系统中断。
  所以,对于数据库的设计人员,开发人员和维护人员来说,很是清楚的了解数据库的日志原理与合理的规划一些操做以免发生这样的状况是很是重要的!下面,咱们就对数据库的日志原理和使用中常常遇到的问题以及其解决方法跟你们分享下。
  一、DB2数据库的日志原理
  事务日志记录数据库中全部对象和数据的改变,在早前版本中最大可达256G,其大小为( logprimary + logsecond ) * logfilsiz,其中logprimary + logsecond的值小于或等于256,logfilsiz的最大为262144,在9.5版本中,日志最大已经能够达到512G,其中logfilsz的大小更改成524286。
  DB2数据库的日志分为主日志和辅助日志,其中主日志在第一个链接到达数据库或者数据库被激活后当即分配,而辅助日志在主日志大小不够的时候动态分配。因此须要注意一点,日志所在的文件系统的大小必须大于主日志文件与辅助日志文件的大小之和。
  DB2数据库有2种日志配置方式,循环日志与归档日志。
  循环日志:这是数据库默认的日志使用方式,主日志用来记录全部的更改,当事务提交后,日志文件会被重用。当主日志文件达到限制时,辅助日志文件将被使用。这种日志方式能够进行崩溃恢复和版本恢复,不能进行前滚恢复,不支持在线备份。
  当活动事务的使用空间超过主日志和辅助日志的限制或者日志空间超过磁盘可以使用空间,将会获得日志满的错误。
DB2事务日志使用经验
  归档日志:启用logarchmetd一、logarchmetd2或打开logretain参数,注意,在9.5版本中,不推荐使用logretain参数,其全部的设置值将被忽略。在数据库归档日志规划时,建议再也不使用logretain的方法。日志文件将不会被删除-保持在线或者离线状态。支持前滚恢复和在线备份。
DB2事务日志使用经验
  疑问:归档日志下,日志一直保留,持续生成新日志,为何还会出现日志满的错误?
  归档日志下,其可用的活动日志大小依然受到主日志与辅助日志大小之和的限制,因此,即便在归档日志下,日志满的场景与活动日志下是彻底同样的。
  二、日志使用中的问题与解决方法
  在平常使用中,咱们遇到最多的问题就是日志满,如今用几个实际的例子来看如何分析和解决日志满的问题,通常的,日志满能够分如下几个场景:
  A、 环境准备,并介绍数据库日志使用大小评估方法:
  数据库参数设置以下:
  日志文件大小(4KB) (LOGFILSIZ) = 10000
  主日志文件的数目 (LOGPRIMARY) = 3
  辅助日志文件的数目 (LOGSECOND) = 2
  日志总大小为200M.
  建立测试用表: 
  C:Documents and Settingsadministrator>db2 "create table test_log(col int, col2 char(10)
  ,col3 timestamp,col4 varchar(100),col5 varchar(100),col6 varchar(100),col7 varch
  ar(100),col8 varchar(100))"
  DB20000I SQL命令成功完成。
  建立插入数据的存储过程: 
  C:Documents and Settingsadministrator>db2 -td@ -vf proc_testlog.sql
  create procedure proc_testlog(v1 int)
  begin
  declare time int default 0;
  while (time < v1)
  do
  insert into test_log values(1,'testlog',current timestamp,'testlogtestlogte
  stlogtestlogtestlogtestlogtestlogtestlogtestlogtestlogtestlogtestlogtestlogtestl
  og','testlogtestlogtestlogtestlogtestlogtestlogtestlogtestlogtestlogtestlogtestl
  ogtestlogtestlogtestlog','testlogtestlogtestlogtestlogtestlogtestlogtestlogtestl
  ogtestlogtestlogtestlogtestlogtestlogtestlog','testlogtestlogtestlogtestlogtestl
  ogtestlogtestlogtestlogtestlogtestlogtestlogtestlogtestlogtestlog','testlogtestl
  ogtestlogtestlogtestlogtestlogtestlogtestlogtestlogtestlogtestlogtestlogtestlogt
  estlog');
  set time = time + 1;
  end while;
  end
  DB20000I SQL命令成功完成。
  咱们来评估下插入使用日志的状况,以便构造日志满的场景,使用db2pd来查看事务日志的使用。
  分别打开2个db2cmd会话窗口,在窗口1中咱们执行:
  C:Documents and Settingsadministrator>db2 +c call proc_testlog(1)
  返回状态 = 0
  会话2中执行: 
  C:Documents and Settingsadministrator>db2pd -db sample -transactions
  Database Partition 0 -- Database SAMPLE -- Active -- Up 0 days 00:29:20
  Transactions:
  Address AppHandl [nod-index] TranHdl Locks State Tflag Tflag2
  Firstlsn Lastlsn LogSpace SpaceReserved TID
  AxRegCnt GXID
  0x7FC21A80 7 [000-00007] 2 7 WRITE 0x00000000 0x00000
  000 0x000027718800 0x000027718800 110 700 0x000000004F13
  1 0
  能够看到这个写操做占用的日志大约为700个字节,在回话1中再重复执行上面的命令,会话2中在看db2pd的输出: 
  C:Documents and Settingsadministrator>db2pd -db sample -transactions
  Database Partition 0 -- Database SAMPLE -- Active -- Up 0 days 00:45:55
  Transactions:
  Address AppHandl [nod-index] TranHdl Locks State Tflag Tflag2
  Firstlsn Lastlsn LogSpace SpaceReserved TID
  AxRegCnt GXID
  0x7FC21A80 7 [000-00007] 2 8 WRITE 0x00000000 0x00000
  000 0x000028E385B8 0x000028E38806 154 1334 0x000000004F57
  1 0
  1334-700=634,咱们能够这样评估,单个事务每执行一次表插入,插入一行占用的日志约为700字节,在一个事务中,插入多条记录,插入一行记录占用的日志约为634字节,固然,实际上当插入多行时,日志的大小会比计算值略大。
  使用这个方法能够根据业务运行状况来评估须要数据库应该配置的日志大小,也能够评估单个大事务须要的日志空间。
  根据估算,200M总日志大小,200*1024*1024/635=330781。所以能够一次插入大约33W记录来构造日志满的场景。
  B、 事务日志满场景一:当前未提交的事务太大,超过日志的限制。
  在会话1中执行:
  C:Documents and Settingsadministrator>db2 commit
  DB20000I SQL命令成功完成。
  提交前面未提交的事务。
  C:Documents and Settingsadministrator>db2 +c call proc_testlog(330000)
  SQL0964C 数据库的事务日志已满。 SQLSTATE=57011
  这时候我打开另一个session,执行一个不相关的插入操做。
  C:Documents and Settingsadministrator>db2 "insert into test values(1112,1,’sdfsdfsdfsdf’,’sdfsdfsdfsdfsdf’,’sdfsdfsdffsdfsd’)
  DB21034E 该命令被看成 SQL 语句来处理,由于它是无效的“命令行处理器”命令。在
  SQL 处理期间,它返回:
  SQL0964C 数据库的事务日志已满。 SQLSTATE=57011
  能够看到,当日志满的时候其余的任何记日志的操做都将不能进行,因此整个系统基本处于不可用的状态,除非等事务回滚结束。
  OK,事务日志满的状况出现,如今咱们就根据日志满的日志,来逆向分析是哪一个操做致使的该问题,分析步骤以下:
  首先,肯定哪一个应用的事务占用了大量的日志空间:
  在回话2中执行: 
  C:Documents and Settingsadministrator>db2pd -db sample -transactions
  Database Partition 0 -- Database SAMPLE -- Active -- Up 0 days 00:02:27
  Transactions:
  Address AppHandl [nod-index] TranHdl Locks State Tflag Tflag2
  Firstlsn Lastlsn LogSpace SpaceReserved TID
  AxRegCnt GXID
  …..
  0x7FC21A80 7 [000-00007] 2 10 WRITE 0x00000000 0x00000
  000 0x00003D86000C 0x000048C4FCD0 14014572 201955470 0x000000004F91
  1 0
  …..
  能够看到上面红色部分, AppHandl为7的应用的一个事务占用了大量的日志。若是有多个应用占用了大量的日志,咱们能够按照下面的方法逐个分析,看每一个应用是执行了什么sql致使的占用如此大的日志。
  而后使用db2pd肯定这个日志执行了什么语句致使占用了大量的日志: 
  C:Documents and Settingsadministrator>db2pd -db sample -applications
  Database Partition 0 -- Database SAMPLE -- Active -- Up 0 days 00:02:36
  Applications:
  Address AppHandl [nod-index] NumAgents CoorEDUID Status C-
  AnchID C-StmtUID L-AnchID L-StmtUID Appid
  WorkloadID WorkloadOccID
  …..
  0x7AED8080 7 [000-00007] 1 1572 UOW-Waiting 0
  0 185 1 *LOCAL.DB2.081111100729
  1 1
  …..
  Application handle为7的应用,对应的L-AnchID为185,L-StmtUID为1。在回话2中继续使用db2pd找到对应的sql语句:
  db2pd -db sample -dynamic
  …..
  Dynamic SQL Statements:
  Address AnchID StmtUID NumEnv NumVar NumRef NumExe Text
  0x7EA7D540 185 1 1 1 1 1 CALL proc_testlog(?)
  …
  对应AnchID为185, StmtUID为1的语句,是CALL proc_testlog(?),经过上面的分析,咱们能够找到,是调用存储过程proc_testlog致使占用了大量的日志,从而找出致使日志满的罪魁祸首。
  解决方案:
  首先,尽可能规避超大事务的操做,对于必须执行的这种大操做,能够考虑是否能够分解成几个事务进行,若是能够,尽可能分解为小事务的方式进行;若是业务上不能够分解,是否能够考虑采用不记日志的方式?好比,load代替insert?表针对这个操做,暂时改成不记日志的方式等等。
  注意:当进行不记日志的操做时,必须很是清楚这样的操做的影响,好比,归档日志下数据库前滚的影响,hadr与复制的数据同步影响,操做失败结果如何等等。
  其次,总有些咱们没法预料的操做发生,可能某个维护人员某天发出一个不适当的命令,删除了大量的数据,致使日志满,整个系统没法运行,如何规避这样的操做带来的系统运行影响呢?能够设置参数:max_log和DB2_FORCE_APP_ON_MAX_LOG注册变量。
  max_log此参数指示一个事务能够消耗的主日志空间的百分比。该值是为 logprimary 配置参数指定的值的百分比。若是该值设置为 0,那么对一个事务能够消耗的总的主日志空间的百分比没有限制。咱们能够配合设置DB2_FORCE_APP_ON_MAX_LOG注册变量来规定若是应用程序违反了 max_log 配置,咱们对该应用如何处理,DB2_FORCE_APP_ON_MAX_LOG设置为true,则超过max_log的应用回被强制与数据库断开链接,事务将被回滚,而且将返回错误 SQL1224N。若是 DB2_FORCE_APP_ON_MAX_LOG 注册表变量设置为 FALSE,则违反了max_log设置的的事务将失败,并返回错误 SQL0964N。该应用程序仍然能够提交在工做单元中由先前语句完成的工做,它也能够回滚已完成的工做以撤销该工做单元。
  经过次设置咱们能够保证即便有大事务操做,总有(1-max_log/100)*log_primary+log_second的日志能够用来处理平常交易,从而避免系统中断。
  注意: 由 max_log 配置参数施加的限制不适用于下列 DB2 命令:ARCHIVE LOG、BACKUP DATABASE、LOAD、REORG TABLE(联机)、RESTORE DATABASE 和 ROLLFORWARD DATABASE。
  C、 事务日志满场景二:某个事务一直未提交,占用的日志不能被重用,致使日志满
  如今看另一个场景,我在一个会话中执行了以下命令:
  C:Documents and Settingsadministrator>db2 +c call proc_testlog(3)
  SQL0964C 数据库的事务日志已满。 SQLSTATE=57011
  显然,数据库日志已满,因而,根据上面的方法,我找是哪一个事务占用了日志。
  C:Documents and Settingsadministrator>db2pd -db sample -transactions
  Database Partition 0 -- Database SAMPLE -- Active -- Up 0 days 00:10:12
  Transactions:
  Address AppHandl [nod-index] TranHdl Locks State Tflag Tflag2
  Firstlsn Lastlsn LogSpace SpaceReserved TID
  AxRegCnt GXID
  0x7FC21A80 12 [000-00012] 2 7 READ 0x00000000 0x00000
  000 0x000000000000 0x000000000000 0 0 0x0000000053A9
  1 0
  0x7FC22780 13 [000-00013] 3 0 READ 0x00000000 0x00000
  000 0x000000000000 0x000000000000 0 0 0x00000000538F
  1 0
  0x7FC23480 14 [000-00014] 4 0 READ 0x00000000 0x00000
  000 0x000000000000 0x000000000000 0 0 0x0000000053BE
  1 0
  0x7FC24180 15 [000-00015] 5 0 READ 0x00000000 0x00000
  000 0x000000000000 0x000000000000 0 0 0x000000005391
  1 0
  0x7FC24E80 16 [000-00016] 6 0 READ 0x00000000 0x00000
  000 0x000000000000 0x000000000000 0 0 0x000000005394
  1 0
  0x7FC25B80 17 [000-00017] 7 4 WRITE 0x00000000 0x00000
  000 0x0000538A93B7 0x0000538A9455 184 408 0x00000000539A
  很奇怪,从结果显示,我没有发现任何一个占用大量日志的应用程序,日志的使用显然都很是的小,那为何日志还会满呢?咱们再注意下占用日志的应用,查看下各自使用的日志文件。
  C:Documents and Settingsadministrator>db2pd -db sample -logs
  Database Partition 0 -- Database SAMPLE -- Active -- Up 0 days 00:12:34
  Logs:
  Current Log Number 4
  Pages Written 9498
  Method 1 Archive Status n/a
  Method 1 Next Log to Archive n/a
  Method 1 First Failure n/a
  Method 2 Archive Status n/a
  Method 2 Next Log to Archive n/a
  Method 2 First Failure n/a
  Address StartLSN State Size Pages Filename
  0x7FBECBD4 0x0000537F0000 0x00000000 10000 10000 S0000000.LOG
  0x7FBECC74 0x000055F00000 0x00000000 10000 10000 S0000001.LOG
  0x7FBECD14 0x000058610000 0x00000000 10000 10000 S0000002.LOG
  0x7EABB2F4 0x00005AD20000 0x00000000 10000 10000 S0000003.LOG
  0x7EABB394 0x00005D430000 0x00000000 10000 10000 S0000004.LOG
  分析发现,这个占用日志的应用的日志开始lsn为0x0000538A93B7,结束lsn为0x0000538A9455,正好落在第一日志文件中,由于这个事务一直没有被提交,因此S0000000.LOG一直不能被重用,这样业务在将主日志和辅助日志用完后,没法从新开始使用日志文件,致使出现日志满的错误。一样,使用上面的方法,咱们能够查找出这个Applications handle为7的一直没有提交的小事务执行的是什么操做。
  上面的状况模拟方法:
  在一个回话中执行一个小事物,好比
  C:Documents and Settingsadministrator>db2 +c "insert into test values ( 1112,1, ’sdfsdfsdfsdf’ , ’sdfsdfsdfsdfsdf’ , ’sdfsdfsdffsdfsd’ )
  在另一个回话中执行占用事务比较大的操做,好比:db2 call proc_testlog(300000),在这个回话中的操做都及时提交,直到配置的日志文件被使用完,再执行小操做db2 call proc_testlog(3),就能够出现上面的日志满的状况。
  解决方案:
  能够看出,不是日志满的问题必定是因为应用占用大量的日志致使的,一个被忽略的未提交的操做也可能致使系统的日志没法被重用而致使日志满,在应用中,这是咱们应该尽可能避免的。可是老是若是没法保证全部的操做都及时的提交,咱们能够设置num_log_span参数来规避这个问题,参数指定是否对一个事务能够跨越多少个日志文件具备限制以及该限制是多少,当设置这个参数后,未提交的事务所在的日志与当前日志跨越的个数超过这个值,将被中断,从而避免事务长时间存在致使系统日志满。另外大事务能够跨越的日志也不能超过这个限制,因此当设置max_log和num_log_span后,一个事务所可使用的事务日志将取2者中比较小的值。
  当启用了无限活动日志空间时,max_log和 num_log_span 配置参数很是有用。若是打开了无限记录(即,logsecondary 为 -1),那么事务数不受日志文件数的上限(logprimary + logsecond)限制。当到达 logprimary 的值时,DB2 将开始归档活动日志,而不是使事务失败。这样可能会致使问题,例如,有一个长期运行的事务,但一直未落实它(多是因为应用程序不正确致使的)。若是出现这种状况,那么活动日志空间会不断增加,从而可能使得崩溃恢复性能不好。为了防止这样,能够为 max_log 和/或 num_log_span 配置参数指定值。
  注意:系统临时表的使用,系统临时表的数据操做是不记日志的,可是表的定义是有少许日志记录的,因此,临时表定义了一直没操做,不提交也可能会引发部分小日志的一直被占用。
相关文章
相关标签/搜索