使用Powershell实现数据库自动化运维

Powershell (3.2万) 2016-12-06 10:06:28

目前市场上针对SQLServer的图书,好的原创图书屈指可数,翻译的图书较多,但只限于专门针对SQL Server数据库本身的开发、管理和商业智能。

而针对PowerShell的图书,可以说大多为MSDN里的学习笔记,主要针对Windows操作系统的管理。

微软在大的布局和技术动向来看,力推云平台。而平台化的基础是自动化、高可用。那么细化到最基础的技术着眼点,微软正在大力开发其所有服务器端产品对 PowerShell的支持。针对SQL Server来说,运用好PowerShell这项技能来将管理任务自动化,才能实现进一步的平台化,它是云平台的基石。

国外大力推广的DEVOPS、开发型运维,不仅仅让数据库管理员或系统管理员局限于手工来操作繁杂的日常工作,这样风险极大。学习PowerShell来提升脚本开发能力,让日常工作化繁为简,是大势所趋。

我翻译了一本微软MVP的《PowerShell V3 -- SQL Server 2012数据库自动化运维权威指南》,这本书涉及的知识点非常全面、实用性很强。对SQL Server DBA来说,是提高数据库管理技能的利器。

下面我通过两个实例来讲解下,使用PowerShell如何实现对SQL Server和MongoDB的自动化运维的。

一、 恢复SQL Server数据库到一个时间点

在本方案中,我们将使用不同备份文件恢复到一个时间点。

准备

在本方案中,我们将使用AdventureWorks2008R2数据库。你也可以选择你的开发环境中的你更喜欢的数据库。

AdventureWorks2008R2数据库有一个包含一个单独数据库文件的文件组。我们将使用来自以下三种不同的备份类型的三个不同备份文件,来基于时间点恢复数据库到另一个SQL Server实例:

  • 完整备份
  • 差异备份
  • 事务日志备份

我们可以使用PowerShell,像在之前的方案描述的,在AdventureWorks2008R2数据库上创建这三种类型的备份。如果你对T-SQL相当熟悉,你也可以使用T-SQL备份命令。

为了帮助我们验证是否基于时间点的恢复的结果是我们期待的,在做任何类型的备份之前,创建一个时间戳标识的表。相应的,创建一个表,并在备份前插入一个时间戳标识的记录到表中。

将这些备份放在C:\Backup\目录。

使用Powershell实现数据库自动化运维_https://www.tiejiang.org_Powershell_第1张

你可以使用下面的脚本来创建你的文件,6464 - Ch06 - 10 - Restore a database to a point in time - Prep.ps1,它包含在本书的可下载文件中。当脚本执行完整后,你应该在AdventureWorks2008R2数据库中有时间戳标识的Student表,以一分钟的间隔创建,类似于下面的截屏:

(译者注:可以从https://www.packtpub.com/books/content/support/10233下载该书代码。)

使用Powershell实现数据库自动化运维_https://www.tiejiang.org_Powershell_第2张

对于我们的方案,我们将恢复AdventureWorks2008R2数据库到另一个实例,KERRIGAN\SQL01,到2015-07-27 02:51:59。意味着,在基于时间点的恢复完成后,我们将只有四个时间戳标识的Student表在KERRIGAN\SQL01在恢复的数据库上:

StudentFull_201507270247
StudentDiff_201507270249
StudentTxn_201507270250
StudentTxn_201507270251

如何做…

为了使用完整、差异和一些事务日志文件恢复到一个时间点,遵循如下步骤:

1. 通过“Start | Accessories | Windows PowerShell | Windows PowerShell ISE”打开PowerShell控制台。

2. 导入SQLPS模块:

#import SQL Server module    
Import-Module SQLPS -DisableNameChecking

3. 添加如下脚本并运行:

$instanceName = "KERRIGAN\SQL01"    
$server = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Server -ArgumentList $instanceName    
#backupfilefolder    
$backupfilefolder = "C:\Backup\"    
#look for the last full backupfile    
#you can be more specific and specify filename    
$fullBackupFile =     
Get-ChildItem $backupfilefolder -Filter "*Full*" |    
Sort -Property LastWriteTime -Descending |    
Select -Last 1    
#read the filelist info within the backup file    
#so that we know which other files we need to restore    
$smoRestore = New-Object Microsoft.SqlServer.Management.Smo.Restore    
$smoRestore.Devices.AddDevice($fullBackupFile.FullName, [Microsoft.SqlServer.Management.Smo.DeviceType]::File)    
$filelist = $smoRestore.ReadFileList($server)    
#read headers of the full backup file,     
#because we are restoring to a default instance, we will    
#need to specify we want to move the files    
#to the default data directory of our KERRIGAN\SQL01 instance    
$relocateFileList = @()    
$relocatePath = "C:\Program Files\Microsoft SQL Server\MSSQL11.SQL01\MSSQL\DATA"    
#we are putting this in an array in case we have     
#multiple data and logfiles associated with the database    
foreach($file in $fileList)    
{    
#restore to different instance    
#replace default directory path for both     
$relocateFile = Join-Path $relocatePath (Split-Path $file.PhysicalName -Leaf)    
$relocateFileList += New-Object Microsoft.SqlServer.Management.Smo.RelocateFile($file.LogicalName, $relocateFile)    
}    
#let's timestamp our restored databasename    
#this is strictly for testing our recipe    
$timestamp = Get-Date -Format yyyyMMddHHmmss    
$restoredDBName = "AWRestored_$($timestamp)"    
#====================================================    
#restore the full backup to the new instance name    
#====================================================    
#note we have a NoRecovery option, because we have    
#additional files to restore    
Restore-SqlDatabase `    
-ReplaceDatabase `    
-ServerInstance $instanceName `    
-Database $restoredDBName `    
-BackupFile $fullBackupFile.FullName `    
-RelocateFile $relocateFileList `    
-NoRecovery    
#====================================================    
#restore last differential    
#note the database is still in Restoring State    
#====================================================    
#using PowerShell V2 Where syntax    
$diffBackupFile =     
Get-ChildItem $backupfilefolder -Filter "*Diff*" |    
Where {$_.LastWriteTime -ge $fullBackupFile.LastWriteTime} |    
Sort -Property LastWriteTime -Descending |    
Select -Last 1    
Restore-SqlDatabase `    
-ReplaceDatabase `    
-ServerInstance $instanceName `    
-Database $restoreddbname `    
-BackupFile $diffBackupFile.FullName `    
-NoRecovery    
#====================================================    
#restore all transaction log backups from last    
#differential up to 2015-07-27 02:51:59    
#====================================================    
#identify the last txn log backup file we need to restore    
#we need this so we can specify point in time    
$lastTxnFileName = "AdventureWorks2008R2_Txn_201507270251"    
$lastTxnBackupFile =     
Get-ChildItem $backupfilefolder -Filter "*$lastTxnFileName*"    
#restore all transaction log backups after the     
#last differential, except the last transaction    
#backup that requires the point-in-time restore    
foreach ($txnBackup in Get-ChildItem $backupfilefolder -Filter     
"*Txn*" |     
Where {$_.LastWriteTime -ge $diffBackupFile.LastWriteTime -and     
$_.LastWriteTime -lt $lastTxnBackupFile.LastWriteTime} |    
Sort -Property LastWriteTime)    
{    
Restore-SqlDatabase `    
-ReplaceDatabase `    
-ServerInstance $instanceName `    
-Database $restoreddbname `    
-BackupFile $txnBackup.FullName `    
-NoRecovery     
}     
#restore last txn backup file to point in time    
#restore only up to 2015-07-27 02:51:59    
#this time we are going to restore using with recovery    
Restore-SqlDatabase `    
-ReplaceDatabase `    
-ServerInstance $instanceName `    
-Database $restoreddbname `    
-BackupFile $lastTxnBackupFile.FullName `    
-ToPointInTime "2015-07-27 02:51:59"

如何实现…

在本方案中,我们使用Restore-SqlDatabase cmdlet,与Backup-SqlDatabase相对的cmdlet在SQL Server 2012中被介绍。

让我们从高层概览下如何实施时间点恢复,然后我们可以细化,并解释包含在本方案中的片段:

1. 收集你的备份文件。

  • 识别包含你想恢复的时间点的最后事务日志备份文件。

2. 恢复最后的好的完整备份使用NORECOVERY。

3. 恢复最后的在完整备份后的差异备份使用NORECOVERY。

4. 恢复在差异备份后的事务日志备份:

  • 使用NORECOVERY恢复,直到包含你想恢复的时间点的日志文件备份。你需要恢复最后的日志文件备份到一个时间点,也就是说,你需要指定需要恢复的时间。最后,使用WITH RECOVERY恢复数据库,使得数据库可访问并以备使用。
  • 或者,你可以使用NORECOVERY恢复所有的事务日志备份文件,在包含你想恢复到的时间点的日志备份前。接下来,使用WITH RECOVERY恢复最后的日志备份到一个时间点,那就是说,你需要指定恢复到何时。

步骤1 – 收集你的备份文件

你需要收集你的备份文件。它们不必位于相同的目录或驱动设备,但这样理想些,这样可以简化你的恢复脚本,你将有一个统一的目录或驱动设备去参照。你也需要这些文件的读许可权限。

在我们的方案,我们简化了这个步骤。我们收集了完整,差异和事务日志备份文件,存储它们到C:\Backup\目录,易于访问。如果你的备份文件位于不同的位置,你只需要适当的调整你脚本的参照目录。

一旦有了这些备份文件,假设你遵循着文件命名规范,你可以过滤你目录中的所有完整备份。在我们的示例中,我们使用命名规范databasename_type_timestamp.bak。对于这个方案,我们通过在文件名中指定关键字或匹配模式来抽取完整备份文件。我们使用Get-ChildItem过滤最新的完整备份文件:

#look for the last full backupfile
#you can be more specific and specify filename
$fullBackupFile =
Get-ChildItem $backupfilefolder -Filter "*Full*" |
Sort -Property LastWriteTime -Descending |
Select -Last 1

一旦你有了完整备份的句柄,你可以读取存储在备份文件中的文件列表。你可以使用SMO Restore对象的ReadFileList方法。读取文件列表可以帮助你通过抽取你需要恢复的数据和日志文件的文件名来实现自动化。

#read the filelist info within the backup file
#so that we know which other files we need to restore
$smoRestore = New-Object Microsoft.SqlServer.Management.Smo.Restore
$smoRestore.Devices.AddDevice($fullBackupFile.FullName, [Microsoft.
SqlServer.Management.Smo.DeviceType]::File)
$filelist = $smoRestore.ReadFileList($server)
THE END

发表评论