在 SharePoint Server 中配置日志传送

 

**上一次修改主题:**2018-02-21

**摘要:**了解如何在灾难恢复方案中为 SharePoint Server 2016 和 SharePoint Server 2013 实现日志传送。

通过日志传送,可以将事务日志从主数据库备份到 SQL Server 单独实例上的辅助数据库。在本文所述的方案中,SQL Server 日志传送与分布式文件系统复制 (DFSR) 结合使用,将数据库和事务日志复制到 Microsoft Azure 中的恢复场,如下所示。

在此灾难恢复方案中,SharePoint Server 生产场位于本地,恢复场位于 Azure 中。也可以参考本主题中的指南,实现其他类型的灾难恢复方案。

Azure 中热备用状态解决方案的元素

Elements of a warm standby solution in Azure

在此图中:

  • 两个环境并排显示:本地 SharePoint 场和 Azure 中的恢复(备用)场。

  • 每个环境包含一个文件共享。

  • 日志传送用于将日志从本地环境中的辅助数据库服务器复制到本地文件共享。

  • DFSR 将文件从本地环境中的文件共享复制到 Azure 环境中的文件共享。在 WAN 方案中,DFSR 比将日志直接传送到 Azure 中的辅助服务器更为有效。

  • 日志传送将日志从 Azure 环境中的文件共享中继到恢复环境中 SQL Server AlwaysOn 可用性组的主副本。

  • 进行日志传送的数据库不会连接到 SharePoint Server 场,直到执行恢复操作。

下图显示了 Azure 解决方案中包含的完整 SharePoint Server 灾难恢复过程的七个阶段。图中突出显示了“阶段 6:设置到恢复场的日志传送”,并在下列部分中详细说明。

Disaster recovery solution roadmap

本文内容:

  • 使用日志传送进行灾难恢复

  • 性能注意事项

  • 配置日志传送的先决条件

  • 日志传送基础结构

  • 配置和验证日志传送需执行的步骤

使用日志传送进行灾难恢复

日志传送允许您将数据库的事务日志文件从主数据库服务器实例自动发送到辅助数据库服务器实例。在我们的本地测试环境中,我们使用具有两个副本的 AlwaysOn 可用性组实现高可用性。我们在两个副本上配置日志传送。每个副本都必须能够传送事务日志。只有处于活动状态且拥有数据库的副本才能传送日志。但是,如果发生故障转移事件且辅助副本变为活动状态,则必须传送事务日志,而非失败的副本。

在 Azure 环境中收到事务日志后,会将其还原到辅助数据库服务器上的每个 SharePoint 数据库,一次还原一个。有关我们的测试环境的详细信息,请参阅 Microsoft 概念证明环境

备注

某些组织使用第三个数据库服务器作为监视器来记录备份和还原操作的历史记录与状态。此可选监视服务器在备份操作失败时会创建警报。

有关日志传送的详细信息,请参阅下表中列出的文章。

表:日志传送的参考文章

URL 说明

关于日志传送 (SQL Server)

介绍了日志传送事务日志备份及可用的选项。

配置日志传送 (SQL Server)

介绍如何使用 SQL Server 2012 或 Transact-SQL 在 SQL Server Management Studio 中配置日志传送。

查看日志传送报告 (SQL Server Management Studio)

说明在 SQL Server Management Studio 中如何查看事务日志传送状态报告。您可以在监视服务器、主服务器或辅助服务器上运行状态报告。

性能注意事项

日志传送由三个作业组成。每个作业执行以下操作之一:

  1. 在主服务器实例上备份事务日志。

  2. 将事务日志文件复制到辅助服务器实例。

  3. 在辅助服务器实例上还原日志备份。

每个作业按计划以一定间隔运行,这可能对数据库服务器具有重大影响,且默认具有 SharePoint 服务器场性能。

要为日志传送正确设置备份、复制和还原作业间隔,必须分析进行日志传送的数据量。进行日志传送的数据量受内容数据库中每天变更量的影响。变更百分比可能因内容、维护变更和使用峰值而有很大差异。

要获取精确的变更百分比,请计算您在指定间隔进行日志传送的每个内容数据库的事务日志备份变更总和。使用此数据计算与主数据库相比的变更百分比。

下列指南源自 Microsoft 现场人员对多版 SharePoint Server 使用日志传送的经验。

  • 通过确保所有日志传送作业与前一个作业至少具有一分钟延迟,避免由于同时启动所有作业而出现性能下降。

  • 最好备份并复制大量小型事务日志,而非少数大型事务日志。

  • 计划以频繁的间隔执行日志备份和复制。您可以较低的频率还原事务日志。例如,首先使用 5 分钟间隔进行备份和复制,使用 15 分钟间隔进行还原。

配置日志传送的先决条件

请先确保满足以下先决条件,然后才能对灾难恢复解决方案使用日志传送。

  • SQL Server 登录名是具有日志传送所需权限级别的域帐户。日志传送存储过程需要具有 sysadmin 固定服务器角色的成员资格。

  • 主数据库必须使用完全或批量日志恢复模型。

    警告

    如果您想将数据库切换到简单恢复,日志传送将停止运行。

  • 在配置日志传送之前,必须创建共享,使事务日志备份对辅助服务器可用。这是生成事务日志备份的目录共享。

除您的恢复点目标 (RPO) 外,尽可能确保恢复的服务器场数据保持完整且未破坏。要实现这些目标,您必须认真规划和计划日志传送的每个方面。

日志传送基础结构

下图显示了用于灾难恢复解决方案环境的日志传送基础结构。

日志传送基础结构和数据流

Shows the log shipping infrastructure and directional flow between the on-premise and Azure farms.

上图显示了日志传送基础结构和数据流。图中显示了生产服务器场和 Azure 恢复场中的 SQL Server 数据库服务器与文件服务器。这些服务器场几乎相同,每个场包含每个 AlwaysOn 可用性组的主副本和辅助副本。文件服务器 FIL1 和 AZ-FIL1 配置得相同,包括硬盘数量和磁盘大小。不显示场中的其他服务器。

为提供高可用性,可用性组中的每个副本存储其他副本的一个备份(完整、差异和事物日志)。

主副本和辅助副本(分别为 SQL-HA1 和 SQL-HA2)将进行备份,备份存储在合作伙伴的可用性组中。

事务日志传送在辅助副本上配置,以最大限度地减小备份对生产数据库的影响。这些事务日志将写入到本地文件服务器 (FIL1) 上的共享文件夹中。Windows Server 分布式文件系统 (DFS) 复制服务将事务日志从 FIL1 复制到 AZ-FIL1。AZ-FIL1 上的事务日志还原到恢复场中可用性组的主副本 AZ-SQL-HA1。

配置和验证日志传送需执行的步骤

以下列表中概括了配置、运行和验证日志传送需执行的步骤:

  1. 备份数据库。

    1. 将完整和差异备份配置到文件服务器上的本地文件夹和共享文件夹。

    2. 确认对本地文件夹和共享文件夹执行了备份。

  2. 设置和测试分布式文件系统 (DFS) 复制。

    1. 创建命名空间和复制,以便传输事务日志并在文件服务器上共享文件夹的本地服务器场和 Azure 场之间备份文件。

    2. 运行日志传送后验证所有传输。

  3. 设置和测试日志传送。

    1. 使用以下脚本在主数据库服务器上设置日志传送:Primary-Logshippingsetupparameter。此脚本可创建备份作业,计划作业以进行日志传送,然后启动作业。

      SET NOCOUNT ON
      USE MSDB
      GO
      
      --@PrimServer : Primary Server name
      --@SecServer  : DR/Secondary Server Name
      --@SecInstance : DR/Secondary FQDN
      --@Domain  : Domain Name
      --@BkpDrive : Production Backup server Name
      --@DBName : DatabaseName
      
      DECLARE @LS_BackupJobIdAS uniqueidentifier,  @LS_PrimaryIdAS uniqueidentifier , @SP_Add_RetCode As int 
      DECLARE @Time as nvarchar(10),@SecInstance as nvarchar(250), @PrimServer as nvarchar(50),@SecServer as nvarchar(50),
      @Domain as nvarchar(50),@DBName as nvarchar(max),@BkpDrive as nvarchar(250),@CMD as nvarchar(max),@Counter int
      ----------------------------------------------------------------------------
      IF OBJECT_ID ('tempdb.DBO.#LogShipping','U') IS NOT NULL DROP TABLE #LogShipping
      Create table #LogShipping ( LSDBs nvarchar(max))
      
      Set @PrimServer ='SQL1'
      Set @SecServer ='SQL2'
      Set @SecInstance ='SQL2.corp.adventureworks.com'
      Set @Domain ='corp.adventureworks.com'
      Set @BkpDrive ='FS1.corp.adventureworks.com'
      Set @DBName = 'Social_DB'
      Set @Time = '0130'
      
      SET @DBName = UPPER(REPLACE(@DBName, ' ', ''))
      SET @DBName = '''' + REPLACE(@DBName, ',', ''', ''') + ''''
      
      Set @CMD =   ' Select ' +
      '''DECLARE  @SP_Add_RetCode As int, @LS_BackupJobIdAS uniqueidentifier,  @LS_PrimaryIdAS uniqueidentifier
      EXEC @SP_Add_RetCode = master.dbo.sp_add_log_shipping_primary_database ' + CHAR(10) +
      '@database = ''''''  + db.Name + ''''''' + CHAR(10) +
      ',@backup_directory = ''''\\' + @BkpDrive + '\LS\' + ''' + db.Name + ''''' + '''' + CHAR(10) +
      ',@backup_share = ' + '''''\\' + @BkpDrive + '\LS\' + ''' + db.Name + ''''' + ''''  + CHAR(10) +
      ',@backup_job_name = ''''' + 'LSBackup_' + ''' + db.Name + ''''' + '''' + CHAR(10) +
      ',@backup_retention_period = 4320
      ,@backup_compression = 1
      ,@backup_threshold = 180 
      ,@threshold_alert_enabled = 1
      ,@history_retention_period = 5760 
      ,@backup_job_id = @LS_BackupJobId OUTPUT 
      ,@primary_id = @LS_PrimaryId OUTPUT 
      ,@overwrite = 1 ' +
      
      'IF (@@ERROR = 0 AND @SP_Add_RetCode = 0) 
      BEGIN 
      DECLARE @LS_BackUpScheduleUIDAs uniqueidentifier ,@LS_BackUpScheduleIDAS int 
      EXEC msdb.dbo.sp_add_schedule 
      @schedule_name = ''''' + 'LSBackupSchedule_'+ @PrimServer + '_' + ''' + db.Name + ''''' + ''''  + CHAR(10) +
      ',@enabled = 1 
      ,@freq_type = 4 
      ,@freq_interval = 1 
      ,@freq_subday_type = 4 
      ,@freq_subday_interval = 13 
      ,@freq_recurrence_factor = 0 
      ,@active_start_date = 20090506 
      ,@active_end_date = 99991231 
      ,@active_start_time = ' + @Time  + CHAR(10) +
      ',@active_end_time = 235900 
      ,@schedule_uid = @LS_BackUpScheduleUID OUTPUT 
      ,@schedule_id = @LS_BackUpScheduleID OUTPUT 
      
      EXEC msdb.dbo.sp_attach_schedule @job_id = @LS_BackupJobId ,@schedule_id = @LS_BackUpScheduleID  
      EXEC msdb.dbo.sp_update_job @job_id = @LS_BackupJobId ,@enabled = 1 
      END 
      
      EXEC master.dbo.sp_add_log_shipping_alert_job 
      EXEC master.dbo.sp_add_log_shipping_primary_secondary 
      @primary_database = '''  + ''''' + db.Name + ''''' + ''''  + CHAR(10) + 
      ',@secondary_server = ''''' + @SecInstance + ''''''  + CHAR(10) +
      ',@secondary_database = ''' + ''''' + db.Name + ''''' + ''''  + CHAR(10) +
      ',@overwrite = 1 ''' +
      ' [LSDBs] FROM sys.databases db  where name in (' + @DBName + ')' +
      
      'and    db.name  not in (''master'',''model'',''msdb'',''tempdb'',''metricsops'',''periscope'' )
      and   Not (exists (select lss.Secondary_database from msdb.dbo.log_shipping_Secondary_databases lss where  db.Name = lss.Secondary_database)
      or exists (select lsp.primary_database from msdb.dbo.log_shipping_primary_databases lsp where  db.Name = lsp.primary_database)
         )'
      
      Insert #LogShipping (LSDBs)
      Exec ( @CMD)
      
      Set @Counter = @@rowcount
      
      While (@counter > 0)
        Begin
        select top 1  @CMD = LSDBs from #LogShipping
        exec sp_executesql @CMD
        set @counter = @counter - 1
        delete top (1) from #LogShipping
      
        End
      
      IF OBJECT_ID ('tempdb.DBO.#LogShipping','U') IS NOT NULL DROP TABLE #LogShipping
      -- ****** End: Script to be run at Primary: [DB1-PSMSQL-01]  ******
      
    2. 使用以下脚本在辅助数据库服务器上设置日志传送:Secondary-Logshippingsetupparameter scripts。在我们的实验室环境中,辅助数据库服务器位于 Azure 中的恢复场内。

      -- ****** Begin: Script to be run at Secondary:  9.3 BUILD******
      SET NOCOUNT ON
      USE MSDB
      GO
      --@PrimServer : Primary Server name
      --@SecServer  : DR/Secondary Server Name
      --@SecInstance : DR/Secondary FQDN
      --@Domain  : Domain Name
      --@PrimaryBkpDrive : Production Backup server Name
      --@BkpDrive : Secondary Backup server Name
      --@DBName : DatabaseName
      
      DECLARE @LS_BackupJobIdAS uniqueidentifier,  @LS_PrimaryIdAS uniqueidentifier , @SP_Add_RetCode As int 
      DECLARE @Time as nvarchar(10),@SecInstance as nvarchar(250), @PrimServer as nvarchar(50),@SecServer as nvarchar(50),
      @Domain as nvarchar(50),@DBName as nvarchar(max),@PrimaryBkpDrive as nvarchar(250),@BkpDrive as nvarchar(250),@CMD as nvarchar(max),@CMD2 as nvarchar(max),@Counter int
      DECLARE  @Delimeter char(1),@DB nvarchar(200), @StartPos int, @Length int
      
      IF OBJECT_ID ('tempdb.DBO.#LogShipping','U') IS NOT NULL DROP TABLE #LogShipping
      Create table #LogShipping ( LSDBs nvarchar(max))
      
      IF OBJECT_ID ('tempdb.DBO.#DBs','U') IS NOT NULL DROP TABLE #DBs
      Create TABLE #DBs (Name nvarchar(200))
      
      Set @PrimServer ='az-sql-ha1'
      Set @SecServer =' az-sql-ha2'
      Set @SecInstance ='SQL1.corp.adventureworks.com'
      Set @Domain =' corp.adventureworks.com '
      SET @PrimaryBkpDrive = 'fs1.corp.adventureworks.com'
      Set @BkpDrive =' az-sp-fs.corp.adventureworks.com '
      Set @DBName = 'Social_DB'
      Set @Time = '0130'
      
      --Parsing Function
      
      SET @Delimeter = ','
      
      WHILE LEN(@DBName) > 0
        BEGIN
          SET @StartPos = CHARINDEX(@Delimeter, @DBName)
          IF @StartPos < 0 SET @StartPos = 0
          SET @Length = LEN(@DBName) - @StartPos - 1
          IF @Length < 0 SET @Length = 0
          IF @StartPos > 0
            BEGIN
              SET @DB = Rtrim(Ltrim(SUBSTRING(@DBName, 1, @StartPos - 1)))
              SET @DBName = SUBSTRING(@DBName, @StartPos + 1, LEN(@DBName) - @StartPos)
            END
          ELSE
            BEGIN
              SET @DB = Rtrim(Ltrim(@DBName))
              SET @DBName = ''
            END
          INSERT #DBs (Name) VALUES(@DB)
      END
      
      --SET @DBName = UPPER(REPLACE(@DBName, ' ', ''))
      --SET @DBName = '''' + REPLACE(@DBName, ',', ''', ''') + ''''
      
      Set @CMD = 'Select ' +
      ''' DECLARE @LS_Secondary__CopyJobId AS uniqueidentifier, @LS_Secondary__RestoreJobId AS uniqueidentifier ,@LS_Secondary__SecondaryId AS uniqueidentifier , @LS_Add_RetCode As int ,@LS_Add_RetCode2 As int 
        DECLARE @LS_SecondaryCopyJobScheduleUIDAs uniqueidentifier ,@LS_SecondaryCopyJobScheduleIDAS int, @LS_SecondaryRestoreJobScheduleUIDAs uniqueidentifier ,@LS_SecondaryRestoreJobScheduleIDAS int 
        EXEC @LS_Add_RetCode = master.dbo.sp_add_log_shipping_secondary_primary 
      @primary_server = ''''' + @PrimServer + ''''''+  CHAR(10) +
      ',@primary_database = '' + ' +  ''''''''' + db.Name + ''''''''' +  CHAR(10) +
      ' + '',@backup_source_directory = ' + '''''\\' + @PrimaryBkpDrive + '\LS\'' + db.Name + ''''''' +  CHAR(10) +
      ' ,@backup_destination_directory =  ' + '''''\\' + @BkpDrive + '\LS\'' + db.Name + ''''''' +  CHAR(10) +
      ',@copy_job_name = ''''LSCopy_DB1-PSMSQL-01_'' + db.Name + ''''''' +  CHAR(10) +
      ',@restore_job_name = ''''LSRestore_'+ @PrimServer + '_'' + db.Name + ''''''' +  CHAR(10) +
      ',@file_retention_period = 4320 
      ,@overwrite = 1 
      ,@copy_job_id = @LS_Secondary__CopyJobId OUTPUT 
      ,@restore_job_id = @LS_Secondary__RestoreJobId OUTPUT 
      ,@secondary_id = @LS_Secondary__SecondaryId OUTPUT 
      IF (@@ERROR = 0 AND @LS_Add_RetCode = 0) 
      BEGIN 
      EXEC msdb.dbo.sp_add_schedule 
      @schedule_name =''''DefaultCopyJobSchedule'''' 
      ,@enabled = 1 
      ,@freq_type = 4 
      ,@freq_interval = 1 
      ,@freq_subday_type = 4 
      ,@freq_subday_interval = 15 
      ,@freq_recurrence_factor = 0 
      ,@active_start_date = 20090506 
      ,@active_end_date = 99991231 
      ,@active_start_time = ' + @Time + ' 
      ,@active_end_time = 235900 
      ,@schedule_uid = @LS_SecondaryCopyJobScheduleUID OUTPUT 
      ,@schedule_id = @LS_SecondaryCopyJobScheduleID OUTPUT 
      
      EXEC msdb.dbo.sp_attach_schedule 
      @job_id = @LS_Secondary__CopyJobId 
      ,@schedule_id = @LS_SecondaryCopyJobScheduleID  
      
      EXEC msdb.dbo.sp_add_schedule 
      @schedule_name =''''DefaultRestoreJobSchedule'''' 
      ,@enabled = 1 
      ,@freq_type = 4 
      ,@freq_interval = 1 
      ,@freq_subday_type = 4 
      ,@freq_subday_interval = 15 
      ,@freq_recurrence_factor = 0 
      ,@active_start_date = 20090506 
      ,@active_end_date = 99991231 
      ,@active_start_time = ' + @Time + '
      ,@active_end_time = 235900 
      ,@schedule_uid = @LS_SecondaryRestoreJobScheduleUID OUTPUT 
      ,@schedule_id = @LS_SecondaryRestoreJobScheduleID OUTPUT 
      
      EXEC msdb.dbo.sp_attach_schedule 
      @job_id = @LS_Secondary__RestoreJobId 
      ,@schedule_id = @LS_SecondaryRestoreJobScheduleID  
      END 
      
      IF (@@ERROR = 0 AND @LS_Add_RetCode = 0) 
      BEGIN 
      EXEC @LS_Add_RetCode2 = master.dbo.sp_add_log_shipping_secondary_database 
      @secondary_database = ' +  ''''''' + db.Name + ''''''' +  CHAR(10) + '
      ,@primary_server = ''''' + @PrimServer + '''''
      ,@primary_database = '+  ''''''' + db.Name + ''''''' +  CHAR(10) +
      ',@restore_delay = 0 
      ,@restore_mode = 1 
      ,@disconnect_users= 1 
      ,@restore_threshold = 180   
      ,@threshold_alert_enabled = 1 
      ,@history_retention_period= 5760 
      ,@overwrite = 1 
      END 
      IF (@@error = 0 AND @LS_Add_RetCode = 0) 
      BEGIN 
      EXEC msdb.dbo.sp_update_job @job_id = @LS_Secondary__CopyJobId ,@enabled = 0 
      EXEC msdb.dbo.sp_update_job @job_id = @LS_Secondary__RestoreJobId ,@enabled = 1 
      END '''  + '[LSDBs] FROM #DBs db'
      
      --Print @CMD
      Insert #LogShipping (LSDBs)
      Exec ( @CMD)
      
      Set @Counter = @@rowcount
      
      While (@counter > 0)
        Begin
        select top 1  @CMD = LSDBs from #LogShipping
        exec sp_executesql @CMD
        set @counter = @counter - 1
        delete top (1) from #LogShipping
      
        End
      
      IF OBJECT_ID ('tempdb.DBO.#LogShipping','U') IS NOT NULL DROP TABLE #LogShipping
      IF OBJECT_ID ('tempdb.DBO.#DBs','U') IS NOT NULL DROP TABLE #DBs
      
      -- ****** End: Script to be run at Secondary:  9.3 Build ******
      
    3. 确认事务日志已传送到共享,且 DFS 正在将这些日志复制到 Azure 文件服务器上的共享。在 SQL Server 中打开作业活动监视器,确认事务日志已成功传送。在生产服务器场和 Azure 场中的文件服务器上打开共享文件夹,确认 DFS 正在传输事务日志。

See also

为 SharePoint Server 配置 SQL Server AlwaysOn 可用性组

关于日志传送 (SQL Server)
复制教程