SQL Server中灾难时备份结尾日志(Tail of log)的两种方法

来源:互联网 发布:淘宝网怎么退保证金 编辑:程序博客网 时间:2024/05/21 11:01

1) 

数据库管理员最大的梦魇,莫过于已经做了备份,但是在想恢复的时候,发现备份文件也是坏的。这将意味着数据库的丢失,后果非常可怕。发生这种情况的原因一般有3个:

·        备份文件和数据库放在同一个(或一组)物理硬盘上。硬盘出故障,备份也保不住。

·        备份介质损坏;或者做的是网络备份,数据在网络传输中发生了损坏。

·        数据库在做完整备份、文件备份或者文件组备份的时候,里面的内容就已经有了损坏。
SQL Server在做数据备份的时候为了节省时间,基本只是很简单地把数据页面拷贝下来,不会做一致性检查的。但是在恢复的时候,需要将数据库恢复(Recover)到事务一致的一个时间点。如果备份中的损坏妨碍了SQL Server的前滚后滚(Redo和Undo),恢复动作就会遇到错误。

无论何种情况,您都可以:

·        修复硬件错误并重新尝试还原操作。

·        忽略错误,继续还原操作,并在还原完成后修复数据库。

·        放弃还原操作,改用备用还原计划。

                在现实环境里,能够通过重试解决的问题还是比较少的。硬件错误往往会永久地损坏备份文件里的内容。在先前的SQLServer版本里,管理员可能不得不尝试去寻找更早的备份。这往往意味着有很多天的数据丢失,损失是比较大的。

SQL Server 数据库恢复有一个“忽略错误”的功能,在这种为难的时刻可以发挥很大的作用。

忽略错误继续执行操作

CONTINUE_AFTER_ERROR是恢复命令(RESTORE)里面的一个选项。它将使还原操作跳过错误继续进行,并还原SQL Server现在所能还原的所有内容。数据还原结束后,可以应用后续事务日志备份,将数据库恢复。如果日志恢复时遇到错误,SQLServer会在日志中报告,并且不让用户访问和这些事务有关的页面。数据库将在尽可能的情况下联机。所以大部分情况下,数据库整体还是能恢复出来,只是部分数据有可能会丢失。

数据丢失量取决于遇到的错误。例如,一般数据页中的错误只会引起该页进入可疑状态,但数据库恢复还会继续。有问题的页面编号将被写入磁盘并记录到suspect_pages表和错误日志中,提醒管理员在恢复结束后继续处理它们。如果不设置CONTINUE_AFTER_ERROR,SQL Server只要遇到一个页面有问题,整个恢复动作都会停止。

如果错误发生在一些比较关键的地方,比如某个数据文件的文件头信息,那么恢复还是有可能完全失败,数据库无法恢复。所以这个方法只供救急之用。不能保证每次使用的效果。使用WITHCONTINUE_AFTER_ERROR还原数据后,要检查错误日志以了解有关错误的详细信息。

基本的RESTORE语法为:

RESTORE DATABASE database_name

FROM backup_deviceWITH CONTINUE_AFTER_ERROR, [NORECOVERY ]

管理员可以在忽略错误继续执行的还原顺序结束时,使用DBCCCHECKDB修复数据库。要使CHECKDB在使用RESTORECONTINUE_AFTER_ERROR后以最大的一致性运行,建议在DBCC CHECKDB命令中使用WITH TABLOCK选项。在极个别情况下,可能没有足够的信息来修复数据库,CHECKDB也没办法修好数据库,数据丢失将不可避免。不是说,有了RESTORE CONTINUE_AFTER_ERROR,备份坏掉也没关系的。

建立备用(Standby)服务器

CONTINUE_AFTER_ERROR只不过是命令SQLServer跳过一切它能够跳过的错误,将所有还能读出来的数据恢复出来,从而最大程度地挽回数据。但是有些对数据一致性要求比较高的系统,比如银行账户系统,用户可不接受“部分”数据恢复。对他们来讲,数据不一致可能就意味着钱已经从一个账户转走,但是没有进入另一个账户,这是不可接受的。所以他们宁可将数据库恢复到昨天的状态,把今天所有的操作重做一遍。

对于这样的系统,在建立备份和选择恢复策略的时候,就要考虑到最坏的情况,预先想好方案,将损失降到最低。

事先预备一台备用机,将做好的备份使用LogShipping或者其他类似的机制在备用服务器上预先恢复好,是一个值得推荐的方法。这样做的好处有:

(1)比起物理镜像之类的技术,这种方案比较经济。备用服务器的硬件要求不高,只要硬盘足够大。

(2)虽然SQL Server提供了若干备份校验机制,但是确保备份完整可靠的唯一办法是真正地去恢复它。

(3)提前恢复备份,使得在真正灾难发生时,只需要恢复最后一个日志备份即可,而不需要在火烧眉毛的时候,去等那个漫长的完整备份恢复,可以大大节约灾难恢复时间。

(4)备用机上的数据库虽然不能修改,但是可以使用STANDBY参数将数据库恢复到只读模式。可以将一些报表查询工作转移到备用机上,减轻生产服务器的负担。

总之,数据安全非常重要,灾难恢复时间要求很短的数据库,如果没有镜像技术的保障,备用服务器是非常必要的

 

============================================================================================================

 2)

在数据库数据文件因各种原因发生损坏时,如果日志文件没有损坏。可以通过备份结尾日志(Tail of log)使得数据库可以恢复到灾难发生时的状态。

    例如:

     grid.ai

     上图中。在DB_1中做了完整备份,在Log_1,Log_2处做了日志备份。在Log_2备份之后不久,发生了故障。从Log_2备份到灾难发生时之间的日志。就是结尾日志(Tail of log)。如果不能备份尾端日志,则数据库只能恢复到Log_2备份的点。尾端日志期间所做的改动全部丢失。更详细的概念可以查看我之前关于日志的博文。

     下面我们分别来看在SQL Server实例运行良好和SQL Server实例崩溃状态下,备份结尾日志方法。

SQL Server实例运行正常时,结尾日志的备份

    下面来模拟一次灾难下结尾日志的备份:

    1

    现在数据库TestBackUp有了一个完整备份和一个日志备份,而最后那条”日志备份后的测试数据”是在上次日志备份之后的,被结尾日志所包含。

    接下来模拟数据库文件所在磁盘损坏(日志文件完好)

    1.停掉Server SQL服务

    2.删除数据库文件(MDF文件)

   

     此时在SSMS中访问数据库TestBackUp会出现不可用:

     2

     此时,因为SQL Server实例可用,通过在T-SQL语句指定NO_TRUNCATE选项(必须指定,否则无法备份尾端日志),备份尾端日志:

    3

     依次进行完整备份恢复,和两次事务日志恢复,可以看到数据已经成功恢复到灾难点:

    4

 

当SQL Server实例崩溃时,结尾日志的备份

    此时由于各种原因,所处的SQL Server实例也崩溃,无法通过T-SQL来备份结尾日志。此时数据库文件损坏,而事务日志文件保持正确。

    假设情况和上面例子一样,此时我手里有一个完整备份(TestBackUp_FULL.bak)和一个日志备份(TestBackUp_log1.bak),还有一个日志文件(ldf)。

    这时我将这几个文件拷贝到其他拥有SQL Server实例的机器上。

    新建一个和原数据库名一样的数据库。设置为脱机:

    5

    删除新建数据库的MDF文件。

    将需要备份的数据库的日志文件替换掉原有的LDF文件。

    此时直接备份结尾日志,成功:

    6

    原有Sql server实例恢复后一次恢复完整备份和两个日志备份。成功恢复到灾难发生点。

 

总结

    我相信看到这篇文章的人都不希望碰到用到上面两种方法的情况。但是,墨菲定律(事情如果有变坏的可能,无论这种可能性有多小,它总会发生)是残酷的,事先练习一下总是比真正遇到情况用生产数据练习惬意的多:-)

 

=====================================================================================================

3)

SQL Server提供了足够多的技术来做各种各样的数据库备份。作为一个数据库管理员,应该选择怎样的备份策略呢?建议您问自己两个问题。

(1)您管理的数据库最多能够容忍多长时间的数据丢失?

(2)您准备投入多少人力物力来做数据库备份与恢复策略?

问题似乎有点残酷。但是世界上大多数事情,要获得越好的效果,就需要越多的投入。数据库备份策略尤其是这样。不考虑镜像技术(包括SQLServer自己的数据库镜像和物理磁盘级镜像),SQL Server不可能时时刻刻地做数据库备份,每次备份之间总要有一定的时间间隔。而这个间隔之间的数据变化在下一次备份之前,是没有保护的。所以讲到底,数据丢失的最大时间段,就是两次备份之间的时间间隔。利用备份恢复机制保护数据,是不可能保证数据一点都不丢失的如果您的用户提出的要求是不能有任何数据丢失,则必须跟用户沟通,让他们了解这样的要求仅使用数据库备份技术实现是不现实的,需要做更大的投入,引入镜像技术。

既然数据丢失的最大时间段,就是两次备份之间的时间间隔,那么备份做得越多,数据丢失量就会越少。可是,做备份越频繁,需要的投入也越多。涉及的因素有:

(1)备份越多,要管理的备份文件也越多,数据库恢复时要恢复的文件也越多。要建立一个合适的备份管理制度。

(2)备份虽然不会阻塞数据库的正常操作,但是会产生一系列的硬盘读写。如果服务器本身I/O就比较繁忙,备份动作会进一步影响数据库的性能。须要增强服务器的硬盘读写处理能力,才能避免这种问题发生。

(3)备份难免会因为种种因素失败。备份越勤,遇到失败的几率越大。管理员要及时处理错误,将备份任务恢复常态。这对管理员的要求也比较高。

当您对将要投入的人力物力心中有数以后,就可以来决定采用什么样的备份策略了。

使用日志备份,可以将数据库恢复到故障点或特定的时点。所以日志备份在备份策略中扮演着很重要的角色。但是日志备份只能在完整恢复模式和有些大容量日志恢复模式的数据库上进行。

制定备份策略,首先要决定是否需要做日志备份。如果需要做日志备份,数据库恢复模式就要选成完整模式。(大容量恢复模式不能总保证日志备份成功,所以一般不推荐在生产环境下使用。)如果不做日志备份,数据库模式就要设置简单,否则会遇到日志文件无限增长问题。

9.2.1 简单恢复模式下的备份

 

 

 

简单恢复模式下,不能做日志备份。所以它只支持最简单的备份和还原方式,很容易管理。不过如果没有日志备份,就只能将数据库恢复到最后一次备份的结尾。如果发生灾难,数据库最后一次备份之后做的数据修改将全部丢失。

在简单恢复模式下,工作损失风险会随时间增长而增加,直到进行下一个完整备份或差异备份为止。因此,建议您排订充足的备份的频率,以避免遗失大量数据。同时,频率也不能太高而让备份变得难以管理。

 

为了降低风险,可以引入差异备份。图9-2显示了使用差异数据库备份补充数据库完整备份,来减轻工作损失风险的一种备份策略。在第一次数据库备份之后,连续建立了3次差异备份。第3个差异备份后,进行数据库完整备份,建立新的差异基准。因为差异备份的开销一般都比完整备份低,所以能够比较经常地运行。这样的备份策略可以使用在数据量稍大,能够容忍较长时间数据丢失的数据库上。

 

以上两种备份策略的优势,是不管是备份还是恢复,管理起来都比较简单。但是不管是数据库完整备份,还是差异备份,都不可能以比较频繁的频率进行,一般都只能在晚间进行。如果数据库比较庞大,或者不允许比较长时间的数据丢失,这样的备份策略是不能满足要求的。必须引入日志备份,建立更为复杂,但是也更强大的备份恢复策略。

 

9.2.2 完整恢复模式下的备份

 

 

选取完整恢复模式,就可以使用日志备份。由于日志备份只拷贝上次日志备份以来的所有日志记录,所以开销会比数据库备份小很多。可以定义以一种很频繁的频率(5分钟甚至更短)来做备份,以达到在最大限度内,防止出现故障时丢失数据的目的。使用日志备份的优点是允许您将数据库还原到日志备份内包含的任何时点(“时点恢复”)。假定可以在发生严重故障后备份活动日志,则可将数据库一直还原到没有发生数据丢失的故障点处。使用日志备份的缺点是它们的数量很多,而且恢复备份时,需要严格按照备份产生的顺序依次恢复。中间不能有任何备份缺失或跳跃。所以日志备份做得越多,还原时间就越长,管理复杂性也越高。

在第一个完整数据库备份完成,并且常规日志备份开始之后,潜在的工作丢失风险存在时间,仅为数据库损坏时点,到上一次常规日志备份的那一段时间。因此,建议经常执行日志备份,以将工作丢失的风险限定在业务要求所允许的范围内。

出现故障后,可以尝试备份“日志尾部”(尚未备份的日志)。如果尾日志备份成功,则可以通过将数据库还原到故障点来避免任何工作丢失。所以这种备份计划的优点也是很明显的。

但是上述备份计划的一大缺陷,就是灾难发生后需要恢复的日志文件数目太多。假设每个小时做一次日志备份,每周日做一次数据库备份,如果灾难在周五发生,就不得不恢复上百个日志备份。这个工作量和所要花的时间是很大的。为了最大程度地缩短还原时间,可以对数据库进行一系列差异备份做补充。

 

 

 

下面我们以Adventure数据库为例子,来具体了解一下完整恢复模式下的数据库备份。

 

第一步:对数据库做一个全备份:

BACKUP DATABASE [AdventureWorks] TODISK='C:\temp\AdvFull1.bak'

 

然后用下面的查询,显示AdventureWorks这个数据库历史上曾经的备份信息。这些信息存放在msdb数据库中,所以可以查询得到。

SELECT DISTINCT s.first_lsn, s.last_lsn,

                           s.database_backup_lsn,s.backup_finish_date,

                           s.type,y.physical_device_name 

FROM msdb..backupset AS s INNER JOIN

msdb..backupfile AS f ONf.backup_set_id = s.backup_set_id INNER JOIN

msdb..backupmediaset AS m ONs.media_set_id = m.media_set_id INNER JOIN

msdb..backupmediafamily AS y ONm.media_set_id = y.media_set_id

WHERE  (s.database_name = 'AdventureWorks')

ORDER BY  s.backup_finish_date DESC;

 

这里有几个字段的含义我们需要稍微解释一下。对于日志备份来讲,first_lsn标识备份集中第一个日志记录的日志序列号,last_lsn标识备份集之后的下一条日志记录的日志序列号。所以(first_lsn,last_lsn-1)标识了这个日志备份所包含的所有日志序列。这里last_lsn-1表示前面一条日志序列号,而不表示日志序列号减1。因为日志序列号虽然是递增的,但并不一定以1为单位递增。

 

对于全备份或者差异备份来讲,它们也会包含有少量的日志信息。(first_lsn,last_lsn)表示做数据恢复时,在做roll forward(前滚)动作时,一定要遍历的LSN。不然的话,数据库在做恢复的时候,数据会不一致。

 

database_backup_lsn标识上一次数据库做全备份的起始LSN。Type标识数据库备份的类型,主要有: D(数据库), L(日志), I(差异数据库),F(文件或文件组)。

 

所以上面的查询显示,我们做的备份是一个数据库全备份,备份存放在C:\temp\AdvFull1.bak。

 

第二步:对数据库做一个操作,然后紧接着做一个日志备份

CREATE TABLE TESTTABLE

(number int,

 name nvarchar(50)

)

INSERT INTO TESTTABLE VALUES (1,'aaaa')

GO

BACKUP LOG [AdventureWorks] TODISK='C:\temp\AdvLog2.bak'

 

再次执行查询,读者可以看到,又添加了一条新的记录,这个备份是日志备份。这个日志备份的LSN是从45000000052600001到46000000007400001。

 

第三步:对数据库做一个操作,再做一个日志备份

INSERT INTO TESTTABLE VALUES (2, 'bbbb')

GO

BACKUP LOG [AdventureWorks] TODISK='C:\temp\AdvLog3.bak'

 

再次执行查询,读者可以看到,又添加了一条新的记录,这个备份是日志备份, LSN是从46000000007400001到46000000007600001,读者可以看到这个日志备份的first_lsn和上一次日志备份的last_lsn一定是一样的。这是因为,数据库在做日志备份的时候,LSN要求是连续的。

 

第四步:对数据库做一个操作,再做一个差异备份

INSERT INTO TESTTABLE VALUES (3, 'cccc')

GO

BACKUP DATABASE AdventureWorks TODISK='C:\temp\AdvDiff4.bak' WITH DIFFERENTIAL

 

再次执行查询,读者可以看到,又添加了一条新的记录,这个备份是差异备份

一直这样操作,直到最后我们对数据库做一次日志操作。

从上面的查询结果,我们可以发现:

(1)不管是全备份还是差异备份,都不会影响LSN的序列。所以,即使最近的几个全备份或差异备份受损,只要有一个全备份,以及该全备份后所有的日志备份,我们也是能够完整无缺地把数据恢复出来,只是恢复的时间会稍微长一点。中间的差异备份或其他全备份只是减少了我们需要恢复的日志备份数目。这进一步说明了日志备份的重要性。

(2)日志备份的LSN是连续的。否则的话,在恢复的时候,则会碰到日志链断裂的问题,恢复是不能继续下去的。

 

9.2.3  文件或文件组备份

完整文件备份指备份一个或多个文件或文件组中的所有数据。在完整恢复模式下,一整套完整文件备份和跨所有文件备份的日志备份合起来,等同于一个完整数据库备份。使用文件备份能够只还原损坏的文件,而不用还原数据库的其余部分,从而可加快恢复速度。例如,如果数据库由位于不同磁盘上的若干个文件组成,在其中一个磁盘发生故障时,只须还原故障磁盘上的文件。

文件备份在默认情况下包含足够的日志记录,可以将文件前滚至备份操作的末尾。(但是在简单恢复模式下,必须一起备份所有读/写文件,而不是逐个指定每个读/写文件或文件组。)

相对于数据库备份,文件备份具有如下优点:

·        能够更快地从隔离的媒体故障中恢复。可以迅速还原损坏的文件。

·        与完整数据库备份(对于超大型数据库而言,变得难以管理)相比,文件备份增加了计划和媒体处理的灵活性。文件或文件组备份的更高灵活性对于包含具有不同更新特征的数据的大型数据库也很有用。

与完整数据库备份相比,文件备份的主要缺点是管理较复杂。如果某个损坏的文件未备份,那么媒体故障可能会导致无法恢复整个数据库。因此,必须维护一组完整的文件备份,对于完整/大容量日志恢复模式,还必须维护一个或多个日志备份,这些日志备份至少涵盖第一个完整文件备份和最后一个完整备份之间的时间间隔。

维护和跟踪这些完整备份是一种耗时的任务,所需空间可能会超过完整数据库备份的所需空间。所以这种备份策略在实际使用中应用得还是比较少的。它只有在管理超大数据库时,才能发挥出其不可替代的优势。

在完整恢复模式下,一整套完整文件备份与涵盖从第一个文件备份开始的所有文件备份的足够日志备份合起来等同于完整数据库备份。

仅使用文件备份和日志备份还原数据库的操作可能比较复杂。因此,如果可能,最好执行完整数据库备份并在第一个文件备份开始之前开始日志备份。图9-10显示了在创建数据库(在t0时间)之后立即执行完整数据库备份(在t1时间)的策略。创建了第一个数据库备份之后,便可开始执行事务日志备份。事务日志备份计划按设置的间隔执行。文件备份以最适合数据库业务要求的间隔执行。此图显示了4个文件组,每次备份其中的一个文件组。它们的备份顺序(A、C、B、A)反映了数据库的业务要求。

在完整恢复模式下,恢复一个文件组备份,不但需要恢复文件组备份本身,还需要依次恢复从上一次完整数据库备份后,到恢复的目标时间点为止的所有日志备份,以确保该文件与数据库的其余部分保持一致。所以要恢复的事务日志备份数量会很多。要避免这种情况,可以考虑使用差异文件备份。可是这样会使整个备份计划更加难于管理。这也是为什么文件备份不常使用的重要原因。但是在管理超大数据库时,这可能是唯一的选择。

 

 

原创粉丝点击