Database
 sql >> Datenbank >  >> RDS >> Database

Überwachung von Sicherungen über Instanzen hinweg

Einführung

In den letzten zwei oder drei Monaten wurde ich zweimal nach einer nativen Lösung für SQL Server gefragt, die einen Sicherungsbericht für mehrere SQL Server-Instanzen in einem Unternehmen konsolidiert. Diese Frage kam von Freunden, die nicht unbedingt Geld für den Kauf eines Tools ausgeben wollten, sondern eher geneigt waren, die Fähigkeiten von SQL Server zu nutzen. Ich habe über zwei Möglichkeiten nachgedacht, dies zu erreichen:

  1. Verwendung von Verbindungsservern, Katalogansichten, SQL Agent-Jobs und Datenbank-E-Mail
  2. Zentralen Verwaltungsserver verwenden

In diesem Artikel werde ich den ersten demonstrieren und hoffe, dass wir irgendwann später einen zweiten Teil des Artikels haben werden.

Szenario

Meine Umgebung besteht aus einem Satz von drei Instanzen, die auf separaten Servern auf AWS sitzen. Diese „Server“ sind eigentlich Amazon EC2s, auf denen SQL Server 2017 RTM CU5 ausgeführt wird. Wir werden auch den Amazon Simple Email Service nutzen, um Database Mail zu konfigurieren. In der Produktion können Sie auf jeden Fall Ihre lokalen E-Mail-Server verwenden und die gleichen Ziele erreichen. Sie werden später in diesem Artikel feststellen, dass der Hostname (und damit die Instanznamen) identisch sind. Dies liegt daran, dass die Server aus demselben Amazon Machine Image geklont wurden (verzeihen Sie die „Faulheit“). Dies wird in der Produktion wahrscheinlich nicht der Fall sein.

Machen Sie ein paar Backups

Beginnen wir damit, ein paar Backups von Datenbanken zu erstellen, die sich auf diesen drei Instanzen befinden. Dadurch werden die Daten generiert, mit denen wir arbeiten werden. Anschließend überprüfen wir, ob die Sicherungen in den Systemtabellen msdb.dbo.backupset erfasst werden und msdb.dbo.backupmediafamily . Die vollständigen Beschreibungen dieser Tabellen können in dieser Microsoft-Dokumentation nachgelesen werden oder Sie verwenden einfach sp_columns .

-- Listing 1: Taking Backups on the Instances
-- Backup a single DB with one stripe
backup database newdb to disk='newdb.bak'

-- Backup all DBs in the instance with timestamp in the backupset name
exec sp_MSforeachdb @command1=
'declare @path varchar(300)
set  @path=''M:\MSSQL\BACKUP\?_Backup'' + convert(varchar(10),getdate(),110) + ''.bak''
print @path
backup database [?] to [email protected]'

-- Backup a single large DB with four stripes
backup database [PieceMealDB] to
disk='M:\MSSQL\BACKUP\PieceMealDB_01.bak',
disk='M:\MSSQL\BACKUP\PieceMealDB_02.bak',
disk='M:\MSSQL\BACKUP\PieceMealDB_03.bak',
disk='M:\MSSQL\BACKUP\PieceMealDB_04.bak'
with
stats=10

Abb. 3. Beschreibung von msdb.dbo.backupset

Sicherungen prüfen

Das folgende Skript nutzt zwei Katalogansichten backupset und backupmediafamily um den Verlauf von Sicherungen zu untersuchen, die auf einer Instanz von SQL Server erstellt wurden. Der Sicherungssatzkatalog enthält eine Zeile für jeden Sicherungssatz. Ein Sicherungssatz ist als Inhalt eines Sicherungsvorgangs definiert, der einem Mediensatz hinzugefügt wird. Ein Mediensatz ist eine geordnete Sammlung von Medien, auf die eine oder mehrere Sicherungsoperationen geschrieben haben.

-- Listing 2: Check Backups using msdb tables --
PRINT 'Checking Databases Successfully Backed Up'
use msdb
go
select bus.database_name,bus.type, case bus.type when 'D' then 'Full' when 'I' then 'Differential' when 'L' then 'Log' end backup_type, bus.backup_start_date, bus.backup_finish_date,
(((DATEPART(HH,bus.backup_finish_date))- (DATEPART(HH,bus.backup_start_date)))*3600) +
(((DATEPART(MI,bus.backup_finish_date)) - (DATEPART(MI,bus.backup_start_date)))*60) +
(((DATEPART(SS,bus.backup_finish_date)) - DATEPART(SS,bus.backup_start_date)))
[backup_time (secs)], bus.backup_size,
bmf.physical_device_name 
from backupset bus
join backupmediafamily bmf on bus.media_set_id=bmf.media_set_id
where bus.backup_start_date >= (getdate() - 7)
order by bus.backup_start_date desc

Abb. 5. Beispielausgabe von Sicherungsprüfungen

Überprüfen von Sicherungen auf anderen Instanzen

Mithilfe von Verbindungsservern können wir Daten von entfernten Instanzen extrahieren. In diesem Fall verwenden wir einen einfachen Verbindungsserver, um Sicherungsverlaufsinformationen aus den msdb-Datenbanken von zwei Remoteinstanzen zu extrahieren. Die Sicherheitskonfiguration für diese verknüpften Server hängt vollständig von Ihnen ab, aber wir haben sie hier zum Zweck unseres Ziels sehr einfach gehalten. Listing 3 zeigt das Skript, das diese verknüpften Server verwenden kann, um Backup-Verlaufsdaten zu aggregieren.

Abb. 6. Ein einfacher Verbindungsserver

Abb. 7. Verbindungsserver für zwei Remoteinstanzen

-- Listing 3: Checking Backups using msdb tables across Linked Servers
use msdb
go

with srva as (
select bus.server_name instance, bus.database_name,bus.type, 
case bus.type when 'D' then 'Full' 
when 'I' then 'Differential' 
when 'L' then 'Log' end backup_type
, bus.backup_start_date, bus.backup_finish_date,
(((DATEPART(HH,bus.backup_finish_date))- (DATEPART(HH,bus.backup_start_date)))*3600) +
(((DATEPART(MI,bus.backup_finish_date)) - (DATEPART(MI,bus.backup_start_date)))*60) +
(((DATEPART(SS,bus.backup_finish_date)) - DATEPART(SS,bus.backup_start_date)))
[backup_time (secs)], bus.backup_size,
bmf.physical_device_name 
from backupset bus
join backupmediafamily bmf on bus.media_set_id=bmf.media_set_id
where bus.backup_start_date >= (getdate() - 3)
)

, srvb as (
select bus.server_name instance, bus.database_name,bus.type, 
case bus.type when 'D' then 'Full' 
when 'I' then 'Differential' 
when 'L' then 'Log' end backup_type
, bus.backup_start_date, bus.backup_finish_date,
(((DATEPART(HH,bus.backup_finish_date))- (DATEPART(HH,bus.backup_start_date)))*3600) +
(((DATEPART(MI,bus.backup_finish_date)) - (DATEPART(MI,bus.backup_start_date)))*60) +
(((DATEPART(SS,bus.backup_finish_date)) - DATEPART(SS,bus.backup_start_date)))
[backup_time (secs)], bus.backup_size,
bmf.physical_device_name 
from [10.0.1.155].msdb.dbo.backupset bus
join [10.0.1.155].msdb.dbo.backupmediafamily bmf on bus.media_set_id=bmf.media_set_id
where bus.backup_start_date >= (getdate() - 3)
)
, srvc as (
select bus.server_name instance, bus.database_name,bus.type, 
case bus.type when 'D' then 'Full' 
when 'I' then 'Differential' 
when 'L' then 'Log' end backup_type
, bus.backup_start_date, bus.backup_finish_date,
(((DATEPART(HH,bus.backup_finish_date))- (DATEPART(HH,bus.backup_start_date)))*3600) +
(((DATEPART(MI,bus.backup_finish_date)) - (DATEPART(MI,bus.backup_start_date)))*60) +
(((DATEPART(SS,bus.backup_finish_date)) - DATEPART(SS,bus.backup_start_date)))
[backup_time (secs)], bus.backup_size,
bmf.physical_device_name 
from [10.0.1.83].msdb.dbo.backupset bus
join [10.0.1.83].msdb.dbo.backupmediafamily bmf on bus.media_set_id=bmf.media_set_id
where bus.backup_start_date >= (getdate() - 3)
)

select * from srva
union 
select * from srvb
union
select * from srvc;

Integrieren von SES und Datenbank-E-Mail

Der nächste Schritt, den wir unternehmen, besteht darin, diese Prüfung zu automatisieren und die Ergebnismenge per E-Mail an die Datenbankadministratoren zu senden. Die erforderlichen Schritte wären zusammengefasst wie folgt:

    1. Amazon SES konfigurieren . In der unter Amazon SES Quick Start bereitgestellten Dokumentation erfahren Sie, wie Sie schnell E-Mail auf AWS einrichten. Bei Verwendung des E-Mail-Dienstes vor Ort ist dies für den DBA nicht erforderlich.
    2. Datenbank-E-Mail konfigurieren . Dieser Artikel soll nicht Datenbank-E-Mail demonstrieren, daher geben wir nur einen Screenshot der Konfiguration des SQL-E-Mail-Kontos:

      Abb. 7. SQL Mail-Kontoeinstellungen

      • Die Portnummer bei Verwendung von SES zum Senden von E-Mails ist 587, NICHT 25
      • Amazon SES erfordert eine sichere Verbindung, daher muss das lila gekennzeichnete Kontrollkästchen (Abb. 7) aktiviert sein
      • Eine einfache Authentifizierung mit den SMTP-Anmeldeinformationen ist erforderlich (d. h. eine anonyme Authentifizierung ist nicht zulässig).

      Wir müssen nur ein paar Dinge beachten, wenn wir Amazon SES für Database Mail verwenden:

    3. SQL Agent für die Verwendung des E-Mail-Profils konfigurieren . Der SQL Server-Agent muss so konfiguriert werden, dass er das E-Mail-Profil verwendet, das während der Datenbank-E-Mail-Konfiguration erstellt wurde, damit die Agent-Jobs E-Mails auslösen. (Siehe Abb. 8)
    4. Staging-Tabelle erstellen . Eine Staging-Tabelle enthält den aggregierten Ergebnissatz für alle Backup-Verlaufsdaten von den Instanzen, die wir mithilfe von Linked Servers anvisiert haben. Die Tabellen-DDL ist in Listing 4 dargestellt.
-- Listing 4: Backup History Table DDL
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[backuphistory](
	[instance] [nvarchar](128) NULL,
	[database_name] [nvarchar](128) NULL,
	[type] [char](1) NULL,
	[backup_type] [varchar](12) NULL,
	[backup_start_date] [datetime] NULL,
	[backup_finish_date] [datetime] NULL,
	[backup_time (secs)] [int] NULL,
	[backup_size] [numeric](20, 0) NULL,
	[physical_device_name] [nvarchar](260) NULL
) ON [PRIMARY]
GO

Abb. 8. SQL Agent-Einstellungen

Wir fahren fort und planen das Skript in Listing 3 in einem SQL Agent Job ein und wir haben das vollständige Skript in Listing 5.

-- Listing 5: Complete SQL Agent Job for Backup History Notification

USE [msdb]
GO

/****** Object:  Job [Enteprise Backup History Summary]    Script Date: 9/26/2018 10:16:46 PM ******/
BEGIN TRANSACTION
DECLARE @ReturnCode INT
SELECT @ReturnCode = 0
/****** Object:  JobCategory [[Uncategorized (Local)]]    Script Date: 9/26/2018 10:16:46 PM ******/
IF NOT EXISTS (SELECT name FROM msdb.dbo.syscategories WHERE name=N'[Uncategorized (Local)]' AND category_class=1)
BEGIN
EXEC @ReturnCode = msdb.dbo.sp_add_category @class=N'JOB', @type=N'LOCAL', @name=N'[Uncategorized (Local)]'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback

END

DECLARE @jobId BINARY(16)
EXEC @ReturnCode =  msdb.dbo.sp_add_job @job_name=N'Enteprise Backup History Summary', 
		@enabled=1, 
		@notify_level_eventlog=0, 
		@notify_level_email=0, 
		@notify_level_netsend=0, 
		@notify_level_page=0, 
		@delete_level=0, 
		@description=N'No description available.', 
		@category_name=N'[Uncategorized (Local)]', 
		@owner_login_name=N'TWENTYTOWERS\Administrator', @job_id = @jobId OUTPUT
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [Aggregate Backup History]    Script Date: 9/26/2018 10:16:46 PM ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @[email protected], @step_name=N'Aggregate Backup History', 
		@step_id=1, 
		@cmdexec_success_code=0, 
		@on_success_action=3, 
		@on_success_step_id=0, 
		@on_fail_action=2, 
		@on_fail_step_id=0, 
		@retry_attempts=0, 
		@retry_interval=0, 
		@os_run_priority=0, @subsystem=N'TSQL', 
		@command=N'-- Check Backups using msdb tables --
-- Across Linked Servers
use msdb
go

truncate table [msdb].[dbo].[backuphistory];

with srva as (
select bus.server_name instance, bus.database_name,bus.type, 
case bus.type when ''D'' then ''Full'' 
when ''I'' then ''Differential'' 
when ''L'' then ''Log'' end backup_type
, bus.backup_start_date, bus.backup_finish_date,
(((DATEPART(HH,bus.backup_finish_date))- (DATEPART(HH,bus.backup_start_date)))*3600) +
(((DATEPART(MI,bus.backup_finish_date)) - (DATEPART(MI,bus.backup_start_date)))*60) +
(((DATEPART(SS,bus.backup_finish_date)) - DATEPART(SS,bus.backup_start_date)))
[backup_time (secs)], bus.backup_size,
bmf.physical_device_name 
from backupset bus
join backupmediafamily bmf on bus.media_set_id=bmf.media_set_id
where bus.backup_start_date >= (getdate() - 3)
)

, srvb as (
select bus.server_name instance, bus.database_name,bus.type, 
case bus.type when ''D'' then ''Full'' 
when ''I'' then ''Differential'' 
when ''L'' then ''Log'' end backup_type
, bus.backup_start_date, bus.backup_finish_date,
(((DATEPART(HH,bus.backup_finish_date))- (DATEPART(HH,bus.backup_start_date)))*3600) +
(((DATEPART(MI,bus.backup_finish_date)) - (DATEPART(MI,bus.backup_start_date)))*60) +
(((DATEPART(SS,bus.backup_finish_date)) - DATEPART(SS,bus.backup_start_date)))
[backup_time (secs)], bus.backup_size,
bmf.physical_device_name 
from [10.0.1.155].msdb.dbo.backupset bus
join [10.0.1.155].msdb.dbo.backupmediafamily bmf on bus.media_set_id=bmf.media_set_id
where bus.backup_start_date >= (getdate() - 3)
)
, srvc as (
select bus.server_name instance, bus.database_name,bus.type, 
case bus.type when ''D'' then ''Full'' 
when ''I'' then ''Differential'' 
when ''L'' then ''Log'' end backup_type
, bus.backup_start_date, bus.backup_finish_date,
(((DATEPART(HH,bus.backup_finish_date))- (DATEPART(HH,bus.backup_start_date)))*3600) +
(((DATEPART(MI,bus.backup_finish_date)) - (DATEPART(MI,bus.backup_start_date)))*60) +
(((DATEPART(SS,bus.backup_finish_date)) - DATEPART(SS,bus.backup_start_date)))
[backup_time (secs)], bus.backup_size,
bmf.physical_device_name 
from [10.0.1.83].msdb.dbo.backupset bus
join [10.0.1.83].msdb.dbo.backupmediafamily bmf on bus.media_set_id=bmf.media_set_id
where bus.backup_start_date >= (getdate() - 3)
)

insert into [msdb].[dbo].[backuphistory]
select * from srva
union 
select * from srvb
union
select * from srvc;
', 
		@database_name=N'msdb', 
		@flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [Query Member Servers for Backups]    Script Date: 9/26/2018 10:16:46 PM ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @[email protected], @step_name=N'Query Member Servers for Backups', 
		@step_id=2, 
		@cmdexec_success_code=0, 
		@on_success_action=3, 
		@on_success_step_id=0, 
		@on_fail_action=2, 
		@on_fail_step_id=0, 
		@retry_attempts=0, 
		@retry_interval=0, 
		@os_run_priority=0, @subsystem=N'TSQL', 
		@command=N'DECLARE @tableHTML  NVARCHAR(MAX) ;

SET @tableHTML =
    N''<H1><font face="Verdana" size="4">Enterprise Backup History Summary</H1>'' +
    N''<table border="1"><font face="Verdana" size="2">'' +
    N''<tr><th><font face="Verdana" size="2">Instance Name</th>'' +
	N''<th><font face="Verdana" size="2">Database Name</th>'' +
    N''<th><font face="Verdana" size="2">Backup Start Date</th>'' +
    N''<th><font face="Verdana" size="2">Backup Finish Date</th>'' +
	N''<th><font face="Verdana" size="2">Backup Time (secs)</th>'' +
    N''<th><font face="Verdana" size="2">Backup Size</th>'' +
    N''<th><font face="Verdana" size="2">Physical Device Name</th></tr>'' +
    CAST ( ( SELECT td = bus.instance,			'''',
					td = bus.database_name,       '''',
                    td = bus.backup_start_date, '''',
                    td = bus.backup_finish_date, '''',
                    td = (((DATEPART(HH,bus.backup_finish_date))- (DATEPART(HH,bus.backup_start_date)))*3600) +
(((DATEPART(MI,bus.backup_finish_date)) - (DATEPART(MI,bus.backup_start_date)))*60) +
(((DATEPART(SS,bus.backup_finish_date)) - DATEPART(SS,bus.backup_start_date))), '''',
                    td = bus.backup_size, '''',
                    td = bus.physical_device_name
              FROM backuphistory as bus
              WHERE bus.backup_start_date >= (getdate() - 7)
              ORDER BY bus.backup_start_date desc
              FOR XML PATH(''tr''), TYPE 
    ) AS NVARCHAR(MAX) ) +
    N''</table>'' + 	''<p style="margin-top: 0; margin-bottom: 0">&nbsp;</p>
	<p style="margin-top: 0; margin-bottom: 0"><font face="Verdana" size="2">Thanks   
	and Regards,</font></p>  &nbsp;
	<p style="margin-top: 0; margin-bottom: 0"><font face="Verdana" size="2">Enterprise Database Operations</font></p>  
	<p>&nbsp;</p>''  ;

EXEC msdb.dbo.sp_send_dbmail @recipients=''[email protected];[email protected]'',
    @subject = ''Enterprise Backup History Summary'',
    @body = @tableHTML ,
    @body_format = ''HTML'' ;', 
		@database_name=N'msdb', 
		@flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
/****** Object:  Step [Mail Complete Result Set to Support]    Script Date: 9/26/2018 10:16:46 PM ******/
EXEC @ReturnCode = msdb.dbo.sp_add_jobstep @[email protected], @step_name=N'Mail Complete Result Set to Support', 
		@step_id=3, 
		@cmdexec_success_code=0, 
		@on_success_action=1, 
		@on_success_step_id=0, 
		@on_fail_action=2, 
		@on_fail_step_id=0, 
		@retry_attempts=0, 
		@retry_interval=0, 
		@os_run_priority=0, @subsystem=N'TSQL', 
		@command=N'DECLARE @tableHTML  NVARCHAR(MAX) ;

SET @tableHTML =
    N''<H1><font face="Verdana" size="4">Enterprise Backup History Summary</H1>'' +
    N''<table border="1"><font face="Verdana" size="2">'' +
    N''<tr><th><font face="Verdana" size="2">Instance Name</th>'' +
	N''<th><font face="Verdana" size="2">Database Name</th>'' +
    N''<th><font face="Verdana" size="2">Backup Start Date</th>'' +
    N''<th><font face="Verdana" size="2">Backup Finish Date</th>'' +
	N''<th><font face="Verdana" size="2">Backup Time (secs)</th>'' +
    N''<th><font face="Verdana" size="2">Backup Size</th>'' +
    N''<th><font face="Verdana" size="2">Physical Device Name</th></tr>'' +
    CAST ( ( SELECT td = bus.instance,			'''',
					td = bus.database_name,       '''',
                    td = bus.backup_start_date, '''',
                    td = bus.backup_finish_date, '''',
                    td = (((DATEPART(HH,bus.backup_finish_date))- (DATEPART(HH,bus.backup_start_date)))*3600) +
(((DATEPART(MI,bus.backup_finish_date)) - (DATEPART(MI,bus.backup_start_date)))*60) +
(((DATEPART(SS,bus.backup_finish_date)) - DATEPART(SS,bus.backup_start_date))), '''',
                    td = bus.backup_size, '''',
                    td = bus.physical_device_name
              FROM backuphistory as bus
              WHERE bus.backup_start_date >= (getdate() - 7)
              ORDER BY bus.backup_start_date desc
              FOR XML PATH(''tr''), TYPE 
    ) AS NVARCHAR(MAX) ) +
    N''</table>'' + 	''<p style="margin-top: 0; margin-bottom: 0">&nbsp;</p>
	<p style="margin-top: 0; margin-bottom: 0"><font face="Verdana" size="2">Thanks   
	and Regards,</font></p>  &nbsp;
	<p style="margin-top: 0; margin-bottom: 0"><font face="Verdana" size="2">Enterprise Database Operations</font></p>  
	<p>&nbsp;</p>''  ;

EXEC msdb.dbo.sp_send_dbmail @recipients=''[email protected];[email protected]'',
    @subject = ''Enterprise Backup History Summary'',
    @body = @tableHTML ,
    @body_format = ''HTML'' ;', 
		@database_name=N'msdb', 
		@flags=0
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_update_job @job_id = @jobId, @start_step_id = 1
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)'
IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback
COMMIT TRANSACTION
GOTO EndSave
QuitWithRollback:
    IF (@@TRANCOUNT > 0) ROLLBACK TRANSACTION
EndSave:
GO

Die Ausführung dieses Jobs führt zu der in Abb. 9 gezeigten Ausgabe. Die Tabelle wird mit sehr einfachem HTML erstellt und kann Ihren Anforderungen entsprechend weiterentwickelt werden.

Abb. 9. E-Mail-Ausgabe der SQL Agent-Auftragsausführung

Schlussfolgerung

Wir haben eine einfache Methode zum Sammeln von Backup-Verlaufsinformationen (und möglicherweise aller anderen Daten, die in Systemdatenbanken enthalten sind) unter Verwendung von Verbindungsservern durchlaufen. Wir haben diesen Prozess weiter automatisiert, indem wir SQL Agent, Database Mail und ein wenig HTML verwendet haben. Diese Methode mag ein wenig grob erscheinen, und ich bin sicher, dass es Tools gibt, die viel besser können, aber dies wäre ein Serverzweck für diejenigen, die gerade mit SQL Server oder Umgebungen mit geringem Budget beginnen. Mit ein wenig Kreativität können Sie die Skripte weiter anpassen und an andere Verwendungszwecke anpassen.

Referenzen

  1. Datenbank-E-Mail konfigurieren
  2. Erste Schritte mit Amazon SES
  3. Verknüpfte Server
  4. Backup-Verlauf und Header-Informationen