Log shipping PowerShell scripttel

Egy hónapja ígértem meg Tibornak azt a PowerShelles log shipping megoldást, amit használtunk SQL 2000-2005 migrációra. Az alapgondolat a következő: a 2000-es szerveren csinálunk egy log backup jobot, ami már az új szerverre, UNC-n keresztül teszi le a backup fájlokat. Ez egy sima T-SQL job. A 2005-ös szerveren pedig egy Operating System jobstep lakik, ami egy powershell scriptet futtat. A jobstep maga kb. ennyi: powershell.exe D:\mssql\MigrateMyDB.ps1. Ez most egy bedrótozott verzió, de elég egyszerűen átalakítható paraméterezhetővé, és akkor egy scripttel lehet több adatbázist is tutujgatni.

A log backup script helyett a magunk log backup tárolt eljárását teszem közzé – eléggé elegem lett a maintenance planekből, úgyhogy én így mentek:

CREATE procedure [bckup].[spBackupLogDatabase]
@dbname varchar(128),
@backupdir varchar(512) = NULL -- tegyél \-t a path végére!
AS
declare @str varchar(2000)
declare @errornumber varchar(5), @errormessage varchar(1000)
BEGIN TRY
select @str = 'backup log ' + @dbname +
	' to disk = ''' + @backupdir + @dbname + '_Log_' +
	replace(replace(replace(convert(varchar(16),getdate(),120),'-',''), ' ', ''), ':', '') + 
	'.TRN'''
exec(@str)
END TRY
BEGIN CATCH
-- itt én custom error message-et használok, de lehet a sima 50001-et is raiselni
    SELECT
        @errornumber = ERROR_NUMBER(),
        @errormessage = ERROR_MESSAGE();
	SELECT @errormessage = 'Error number: ' + @errornumber + ', message: ' + @errormessage
	RAISERROR (999001,16,1, 'log', @dbname, @errormessage)
END CATCH

Ezt valami olyasmi módon hívjuk meg, hogy

EXEC [bckup].[spBackupLogDatabase] 'MyDB', '\\myserver\backups\'

A Powershell script pedig a következőket teszi: felolvassa a .trn kiterjesztésű fájlokat keletkezési sorrendben, aztán elkezdi restore-olni őket. Az éppen aktuális fájl kiterjesztését átírja .NOW-ra, és amikor kész van vele, akkor pedig .DONE-ra. így ha bukta van, akkor a .NOW kiterjesztésű fájlokat vissza kell nevezni .trn-re és lehet folytatni a probléma megoldása után a folyamatot.

Set-PSDebug -Strict

##adatbázis neve
$dbname = 'MyDB'

##ide írjuk a logot
$logfile = "D:\mssql\logs\$($dbname).log"
##ebbe a könyvtárba kerülnek a transaction log backupok
$logdir = "D:\mssql\backups\$($dbname)\'

##a secondary szerver, ahova restore-olunk
$servername = 'MYSERVER,1438'

$restore_cmd = "restore log =DBNAME=
from disk = '=DIR==FILE='
with norecovery"

$restore_cmd_orig = ($restore_cmd -replace '=DBNAME=', $dbname) -replace '=DIR=', $logdir

##felolvassuk a log backup fajlokat
$files = Get-ChildItem $logdir -Filter '*.TRN' | Sort-Object -Property "LastWriteTime"
if ($files -eq $null) {
	"No file to process"
	Exit
	} #if ($files.Length -eq 0) 

##restore-oljuk a meg nem restore-olt fajlokat
foreach ($f in $files) {
	$f.PSPath
	$f_new = rename-item -path $f.PSPath -newname ($f.Name -replace '.TRN', '.NOW') 
	$restore_cmd = $restore_cmd_orig -replace '=FILE=', ($f.Name -replace '.TRN', '.NOW')
	$restore_res = sqlcmd -E -S $servername -Q $restore_cmd

	Get-Date -Format 'yyyy-MM-dd HH:mm:ss' |out-file $logfile -Append
	$restore_cmd |out-file $logfile -Append
	$restore_res |out-file $logfile -Append

	if ($restore_res | select-string -quiet "abnormally") {
		Write-Error "Restore had problems, see the following error:"
		Write-Error ($restore_res| Out-String)
		throw $restore_res
		# stop no matter the cost
		Exit
		} #if restore abnormal
##nevezzuk at a sikeresen betoltott fajlokat
	rename-item -Path ($f.PSPath -replace '.TRN', '.NOW') -newname ($f.Name -replace '.trn', '.DONE')

	#write restore log:
	Get-Date -Format 'yyyy-MM-dd HH:mm:ss' |out-file -Append $logfile 
	} #foreach ($file in $files)

Hát ennyi. A restore után volt még egy második lépés is, szintén powershell, ami takarította a könyvtárat. Szerintem ez elég egyszerű, persze nincs is benne atombiztos hibakezelés, szóval lehet használni, de ha bedől, nem adok pénzt, ezt leszögezem.

3 Comments

  1. Béci:

    Szia Erik,

    talán nem teljesen idevaló a kérdésem,de ha nem haragudnál, megkérdezném :

    2 SQL Server 2000 Enterprise között felépítettem a LogShippinget.Ez eddig nem is baj,sőt

    A gondom az, hogy a cél adatbázis, ahova a forrásból mennek az adatok 15 percenként Loading-státuszban van, emiatt ugye nyilván nem látom a táblatartalmat, tehát nem tudom fapados módszerekkel ellenőrizni, hogy történik-e tényleges adatmozgás a 2 szerver között.

    Egy másik hasonló eljárás során a cél adatbázis Read- Only státuszban volt. Mindkét esetben a LogShipping monitor szerint a státusz In Sync, ami kissé megnyugtató, de azért én szeretném a cél szerver megfelelő adatbázisában is látni a táblákat.

    Ha a cél adatbázison kiadtam a
    restore database database_name with recovery
    parancsot, akkor visszatette online-ba a db-t, de így meg attól tartok, hogy a Log Shipping nem az igazi.

    Szóval, hogy tudnám elérni, hogy ne Loading, hanem Read Only legyen a cél DB státusza, vagy így is elhihetem, hogy visszaállásnál pont a forrás DB-vel megegyező tartalmat fogok látni?

    Egyébként a Log Shippinget a Maintenance varázslóval csináltam, minden esetben.

    Előre is köszi a gyors segítséget.

    B.

  2. Erik:

    Hah, hát lehet vmi olyasmit mondani, h a log shippingben magában ne restoring, hanem standby/readonly legyen a db, de ezt most hadd ne mondjam meg így egy 11 éves alkalmazáshoz :) Egyébként a job historyban lehet látni a sikeres restore eventeket, meg a msdb-ben is van egy tábla, ahol a restore history lakik, ha jól emlékszem. igazából azokat is nézheted, mert a siekres restore ugye azt jelenti, h van szinkron. Meg persze az is jó, amit mondasz, arra az egyre figyelj, hogy a standby undo file-ra úgy vigyázz, mint a szemed fényére, mert ha azt elveszted, akkor lehet újraépíteni az egészet.
    Erik

  3. Béci:

    Kedves Erik,

    megtiszteltél válaszoddal, amit nagyon köszönök és nagyon hasznos dolgokat tudhattam meg belőle…pölö fogalmam sem volt, hogy a standby undo file ennyire “fontos” :-(
    Most gondolom, sok vérprofi SQL-guru felhörren, hogy “ilyen ember hogy tud SQL-farmot üzemeltetni” :-)))

    Sorry, jó pap holtig tanul..

    Erik, mégegyszer köszönöm válaszodat.

    B.

Leave a comment