Jaa


支持提示:在 DPM 2007、2010 和 2012 上,计划磁带备份在错误日期运行

各位 DPM 管理员,大家好,我是 DPM 支持团队的 Wilson Souza。大家知道,Data Protection Manager 提供了很多保护 Exchange、SQL、SharePoint、Hyper-V、系统状态、裸机、文件、共享等服务器工作负荷的方式。它可通过以下方式提供保护:

磁盘到磁盘 (D-D) – 受保护数据从受保护服务器上的磁盘转移到位于 DPM 服务器上的卷。

磁盘到磁带 (D-T)– 受保护数据从受保护服务器上的磁盘转移到由 DPM 服务器管理的磁带设备。

磁盘到磁盘到磁带 (D-D-T) – 结合使用以上两个选项,受保护数据从受保护服务器上的磁盘转移到位于 DPM 服务器上的卷,然后我们再将数据从 DPM 卷复制到磁带设备。

 

使用磁带时,对于何时将数据备份转移到磁带,我们有一系列可用选项。可以是每天、每周、每月、每季度和每年,或者您认为适合 SLA 的任意组合。

 

DPM 将计划备份控制委托给 SQL 代理,到了运行磁带备份时,SQL 代理会触发 DPM 引擎作业以启动备份。

 

设想一下,有一天上午您来到办公室,查看创建备份的情况,发现原本应在两个月之后运行的备份在昨晚已经完成,但您却没有收到任何警告,提醒 DPM 将在这个出人意料的日期运行备份。本篇博文旨在解释这个问题并提供解决方法。

 

注意:此问题不会影响每天、每周或每月的磁带备份计划,而主要影响几个月的磁带备份,例如每季度、每半年、每年的备份等。此问题会在 DPM 2007、2010 和 2012 上出现,但本文的解决方法不适用于 DPM 2007。

 

解释问题

 

  clip_image001

 

假定今天是 2011 年 10 月 7 日,我们创建了一个新的保护组并设置了长期保护(每周、每季度和每年)。在新保护组向导的最后,DPM 将创建必要的计划作业,并将它们发送到 SQL 代理。

如下图所示,从 SQL 代理看来,这是每季度备份。

 

注意:每季度备份仅应在 1 月/4 月/7 月/10 月运行

 clip_image002

 

SQL 代理显示,此作业应在作业创建之后两天后运行

 

  clip_image003

 

2011 年 10 月 9 日,磁带备份作业按预期运行。根据季度计划定义,我们现在预期此备份将在 2012 年 1 月 9 日运行。

 

对保护组进行的几乎所有操作(手动:添加/删除受保护成员、修改磁盘分配或在没有进行任何更改的情况下完成修改保护组向导,或者自动:SQL 和 SharePoint 自动保护、磁盘自动增长)都将导致所有计划作业从该组删除和重新创建。这正是计划作业可能在错误日期运行的潜在原因。

 

在删除/创建新计划之后,DPM 将使用原始 XML 来生成新的计划作业。ScheduleXml 将使用原始的开始日期,该日期现在可能已经过去。以下是 ScheduleXML 的片段。

 

<?xmlversion="1.0"encoding="utf-16"?>

<Schedulexmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"xmlns:xsd="https://www.w3.org/2001/XMLSchema"ScheduleID="9b0c036b-5c2d-49b8-a374-3842ba6cfb96"JobDefID="c5241cb4-8dc2-4574-b758-2e7b7db0ca70"xmlns="https://schemas.microsoft.com/2003/dls/Scheduler.xsd">

  <Recurrence>

    <MonthlyStartDt="2011-10-09"EndDt="9999-12-31"Interval="3"MonthDayList="9" />

    <TimeStartTm="20:00:00"EndTm="20:00:00" />

  </Recurrence>

</Schedule>

 

  clip_image004

 

现在,我们快进到 11 月 6 日,保护组已被修改,添加了新数据源。原始计划作业将被删除,并创建新的作业。

请注意,以下的开始日期没有更改。

 

 clip_image005

 

突出显示的是由修改保护组操作创建的新计划(每周、每季度和每年的计划)。季度的新计划作业是倒数第二行的作业(下一次运行 = 11/09/2011 8:00:00 PM)

 

 clip_image006

 

SQL 代理认为此计划设置在 2011 年 10 月 9 日第一次运行。现在已经过去了将近一个月,“上一次运行”列显示此作业从未运行。为了解决这个问题,SQL 代理将这个新作业的下一次运行时间设置为第一个可用日期。由于现在是 6 日距离 9 日有三天时间,SQL 代理将计划在 9 日运行此作业

 

因此,它不会按预期在 1 月运行每季度备份,而是现在立即运行备份,提早了 2 个月。此外,此作业不会在 DPM 用户界面中显示为已计划(我们将在另一篇博客中对这个问题进行解释)。您只会在此作业正在运行、完成或失败时看到对此作业的引用。

 

解决方法

 

为了解决这个问题,请将以下脚本复制到 SQL Server Management Studio 并执行该脚本。这个新存储的程序将检查开始日期是否已过,如果是,它将计算下一次运行时间,并进行相应设置。从 SQL 代理的角度来看,错误计划只会在计划开始日期设置为过去日期时发生,一旦超过原始计划日期,这种情况始终都会发生。

 

脚本:

 

=====

 

USE [DPMDB]

GO

/****** Object: StoredProcedure [dbo].[prc_IM_UserSchedule_Update] Script Date: 11/10/2011 19:11:01 ******

******* Edited by........: Wilson Souza     

******* Version..........: 2.2

******* Date Created.....: 11/10/11

******* Date Last Change.: 04/04/11

******* THIS SCRIPT IS FOR DPM 2010/2012 RTM   

******* Change Log for V 2.2

******* Addressed issue if selected DAY instead any day of the week.

******* Change log for V 2.0

******* Now using XML variable to retrieve data instead of searching string on schedule variable

******* Now addresses issues for Weekly schedules. Not only Months

******* Now addresses issues when user select First, Second, Third, Four or Last day of the month.

*/

 

SETANSI_NULLSON

GO

SETQUOTED_IDENTIFIERON

GO

 

--

-- Update one row in UserSchedule table by ScheduleID.

-- If this ScheduleID doesn't exist,

-- add a new row with this ScheduleID.

--

ALTERPROCEDURE [dbo].[prc_IM_UserSchedule_Update]

(

    @ScheduleID GUID,

    @ProtectedGroupID GUID,

    @JobType tinyint,

    --------------- Change Start ---------------

    -- @Schedule ntext,

    @Schedule nvarchar(max),

    --------------- Change end ---------------

    @Immediacy bit,

    @TimeOffset int,

    @MaxDuration bigint,

    @ScheduleListId GUID

)

AS

 

DECLARE @error int,

        @rowcount int,

       

       

    --------------- Change Start ---------------

     

                  @xml xml,

                  @CurrentDate date,

                  @ForLOfTheMonth date,-- First or Last Day of the Month

                  @count int,

                  @count1 int,

 

                  @Monthly_StartDt date,

                  @Monthly_Interval int,

                  @Monthly_MonthDayList int,-- This might not be needed

 

                  @MonthlyRelative_StartDt date,

                  @MonthlyRelative_Interval int,

                  @MonthlyRelative_RelativeWeekDay nvarchar(3),

                  @MonthlyRelative_RelativeInterval nvarchar(6),

                 

                  @Weekly_StartDt date,

                  @Weekly_Interval int,

                  @Weekly_WeekDayList nvarchar(20)-- This might not be needed

 

 

set @xml =CONVERT(xml,SUBSTRING(@schedule,42,LEN(@schedule)-41))

set @CurrentDate =GETDATE()

 

select @Weekly_StartDt = @xml.value('(//*[local-name()="Weekly"]/@StartDt)[1]','date')

select @Weekly_Interval = @xml.value('(//*[local-name()="Weekly"]/@Interval)[1]','int')

select @Weekly_WeekDayList = @xml.value('(//*[local-name()="Weekly"]/@WeekDayList)[1]','nvarchar(20)')-- This might not be needed

 

select @Monthly_StartDt = @xml.value('(//*[local-name()="Monthly"]/@StartDt)[1]','date')

select @Monthly_Interval = @xml.value('(//*[local-name()="Monthly"]/@Interval)[1]','int')

select @Monthly_MonthDayList = @xml.value('(//*[local-name()="Monthly"]/@MonthDayList)[1]','int')-- This might not be needed

 

select @MonthlyRelative_StartDt = @xml.value('(//*[local-name()="MonthlyRelative"]/@StartDt)[1]','date')

select @MonthlyRelative_Interval = @xml.value('(//*[local-name()="MonthlyRelative"]/@Interval)[1]','int')

select @MonthlyRelative_RelativeWeekDay = @xml.value('(//*[local-name()="MonthlyRelative"]/@RelativeWeekDay)[1]','nvarchar(3)')

select @MonthlyRelative_RelativeInterval = @xml.value('(//*[local-name()="MonthlyRelative"]/@RelativeInterval)[1]','nvarchar(6)')

 

If @Monthly_StartDt isNOTNULL

      while @Monthly_StartDt < @Currentdate

            Set @Monthly_StartDt =DATEADD(MONTH,@Monthly_Interval,@Monthly_StartDt)

           

if @Weekly_StartDt isNOTNULL

      if @Weekly_Interval > 1

            while @Weekly_StartDt < @CurrentDate

                  set @Weekly_StartDt =DATEADD(DAY,@Weekly_Interval * 7,@Weekly_StartDt)

     

If @MonthlyRelative_StartDt isNOTNULL

Begin

      set @ForLOfTheMonth =DATEADD(dd,-(DAY(DATEADD(mm,1,@Currentdate))-1)-(DAY(@Currentdate)-DAY(DATEADD(mm,1,@Currentdate))),@Currentdate)

      if @MonthlyRelative_RelativeInterval ='Last'

      begin

            set @ForLOfTheMonth =DATEADD(Month,1,@ForLOfTheMonth)

            set @ForLOfTheMonth =DATEADD(dd,-(DAY(DATEADD(mm,1,@ForLOfTheMonth))-1)-(DAY(@ForLOfTheMonth)-DAY(DATEADD(mm,1,@ForLOfTheMonth))),@ForLOfTheMonth)

            set @ForLOfTheMonth =DATEADD(day,-1,@ForLOfTheMonth)

      end

      while @MonthlyRelative_StartDt < @CurrentDate

      begin

            while @MonthlyRelative_StartDt < @ForLOfTheMonth

                  Set @MonthlyRelative_StartDt =DATEADD(MONTH,@MonthlyRelative_Interval,@MonthlyRelative_StartDt)

            if @MonthlyRelative_RelativeInterval ='Last'

            Begin

                  set @MonthlyRelative_StartDt =DATEADD(Month,1,@ForLOfTheMonth)

                  set @MonthlyRelative_StartDt =DATEADD(dd,-(DAY(DATEADD(mm,1,@MonthlyRelative_StartDt))-1)-(DAY(@MonthlyRelative_StartDt)-DAY(DATEADD(mm,1,@MonthlyRelative_StartDt))),@MonthlyRelative_StartDt)

                  set @MonthlyRelative_StartDt =DATEADD(day,-1,@MonthlyRelative_StartDt)

            End

            else

                  set @MonthlyRelative_StartDt =DATEADD(dd,-(DAY(DATEADD(mm,1,@MonthlyRelative_StartDt))-1)-(DAY(@MonthlyRelative_StartDt)-DAY(DATEADD(mm,1,@MonthlyRelative_StartDt))),@MonthlyRelative_StartDt)

            if @MonthlyRelative_RelativeInterval ='First'or @MonthlyRelative_RelativeInterval ='Last'

                  set @count = 1

            if @MonthlyRelative_RelativeInterval ='Second'

                  set @count = 2

            if @MonthlyRelative_RelativeInterval ='Third'

                  set @count = 3

            if @MonthlyRelative_RelativeInterval ='Fourth'

                  set @count = 4

            set @count1 = @count

            if @MonthlyRelative_RelativeWeekDay ='Day'

                  if @count <> 1

                  Begin

                        set @MonthlyRelative_StartDt =DATEADD(dd,@count-1,@MonthlyRelative_StartDt)

                        set @count = 0

                  End

                  Else

                        set @count = 0         

            while @count <> 0

            begin

                  ifsubstring(DATENAME(dw,@MonthlyRelative_StartDt),1,2)= @MonthlyRelative_RelativeWeekDay

                        set @count = @count - 1

                  if @count <> 0

                        if @MonthlyRelative_RelativeInterval <>'Last'

                              set @MonthlyRelative_StartDt =DATEADD(day,1,@MonthlyRelative_StartDt)

                        else

                              set @MonthlyRelative_StartDt =DATEADD(day,-1,@MonthlyRelative_StartDt)

            end

            if @MonthlyRelative_StartDt < @CurrentDate

            begin

                  set @MonthlyRelative_StartDt =DATEADD(MONTH,@MonthlyRelative_Interval,@MonthlyRelative_StartDt)

                  set @MonthlyRelative_StartDt =DATEADD(dd,-(DAY(DATEADD(mm,1,@MonthlyRelative_StartDt))-1)-(DAY(@MonthlyRelative_StartDt)-DAY(DATEADD(mm,1,@MonthlyRelative_StartDt))),@MonthlyRelative_StartDt)

                  if @MonthlyRelative_RelativeInterval ='Last'

                  begin

                        set @MonthlyRelative_StartDt =DATEADD(Month,1,@MonthlyRelative_StartDt)

                        set @MonthlyRelative_StartDt =DATEADD(dd,-(DAY(DATEADD(mm,1,@MonthlyRelative_StartDt))-1)-(DAY(@MonthlyRelative_StartDt)-DAY(DATEADD(mm,1,@MonthlyRelative_StartDt))),@MonthlyRelative_StartDt)

                        set @MonthlyRelative_StartDt =DATEADD(day,-1,@MonthlyRelative_StartDt)

                  end

                  set @count = @count1

                  if @MonthlyRelative_RelativeWeekDay ='Day'

                        if @count <> 1

                        Begin

                              set @MonthlyRelative_StartDt =DATEADD(dd,@count-1,@MonthlyRelative_StartDt)

                              set @count = 0

                        End

                        Else

                              set @count = 0         

                  while @count <> 0

                  begin

                        ifsubstring(DATENAME(dw,@MonthlyRelative_StartDt),1,2)= @MonthlyRelative_RelativeWeekDay

                              set @count = @count - 1

                        if @count <> 0

                              if @MonthlyRelative_RelativeInterval <>'Last'

                                    set @MonthlyRelative_StartDt =DATEADD(day,1,@MonthlyRelative_StartDt)

                              else

                                    set @MonthlyRelative_StartDt =DATEADD(day,-1,@MonthlyRelative_StartDt)

                  end

            end

      end

End

 

if @Monthly_StartDt isNOTNULL

      set @xml.modify ('replace value of (//*[local-name()="Monthly"]/@StartDt)[1] with sql:variable("@Monthly_StartDt")')

If @MonthlyRelative_StartDt isNOTNULL

      set @xml.modify ('replace value of (//*[local-name()="MonthlyRelative"]/@StartDt)[1] with sql:variable("@MonthlyRelative_StartDt")')

if @Weekly_StartDt isNOTNULL

      set @xml.modify ('replace value of (//*[local-name()="Weekly"]/@StartDt)[1] with sql:variable("@Weekly_StartDt")')

 

set @Schedule ='<?xml version="1.0" encoding="utf-16"?> '+CONVERT(nvarchar(max),@xml)

 

 

      --------------- Change end ---------------

 

SET @rowcount = 0

SET @error = 0

 

SETNOCOUNTON

 

UPDATE dbo.tbl_IM_UserSchedule

SET ProtectedGroupID = @ProtectedGroupID,

        JobType = @JobType,

        Schedule = @Schedule,

        Immediacy = @Immediacy,

        TimeOffset = @TimeOffset,

        MaxDuration = @MaxDuration,

        ScheduleListId = @ScheduleListId

WHERE ScheduleID = @ScheduleID

 

SELECT @error =@@ERROR, @rowcount =@@ROWCOUNT

 

IF (@error = 0 AND @rowcount = 0)

BEGIN

    INSERTINTO dbo.tbl_IM_UserSchedule

    (

        ScheduleID,

        ProtectedGroupID,

        JobType,

        Schedule,

        Immediacy,

        TimeOffset,

        MaxDuration,

        ScheduleListId

    )

    values

    (

        @ScheduleID,

        @ProtectedGroupID,

        @JobType,

        @Schedule,

        @Immediacy,

        @TimeOffset,

        @MaxDuration,

        @ScheduleListId

    )

 

    SET @error =@@ERROR

END

 

SETNOCOUNTOFF

 

RETURN @error

 

=====

Wilson Souza | 高级支持呈报工程师 | 管理和安全部