Esegui il backup di SQL Server utilizzando gli snapshot istantanei

Se i file di database SQL Server sono distribuiti su più dischi, puoi eseguire il backup di tutti i dischi contemporaneamente, mantenendo la coerenza di applicazioni e dati. Puoi ottenere questo backup point-in-time esatto con i gruppi di coerenza di snapshot istantanei di Compute Engine, che ti consentono di eseguire il backup dei dati su un gruppo di dischi.

Questo tutorial descrive come eseguire il backup dei database SQL Server con gli snapshot di Compute Engine e la funzionalità di snapshot Transact-SQL (T-SQL) disponibile in SQL Server 2022 e versioni successive. Questa soluzione supporta i deployment Windows e Linux e riduce al minimo l'impatto sulle prestazioni dei workload live.

Come funziona

Il flusso di lavoro è costituito da questi passaggi principali, gestiti da uno script in esecuzione su un'istanza di Compute:

  1. Blocca il database: lo script invia un comando T-SQL a SQL Server per sospendere tutte le operazioni di scrittura per i database di destinazione. In questo modo, i file di database si trovano in uno stato coerente per il backup.
  2. Acquisisci snapshot istantanei: mentre il database è bloccato, crea un gruppo di snapshot istantanei di i dischi in cui risiedono i file di dati e di log del database. Questo è l' Google Cloud equivalente dell'utilizzo di un meccanismo di snapshot a livello di hardware o di servizio.
  3. Registra e sblocca: lo script invia un altro comando T-SQL a SQL Server per registrare i metadati di backup. Questo comando crea un piccolo file di backup che rimanda al gruppo di coerenza degli snapshot istantanei e viene registrato nella cronologia dei backup msdb. Al termine, SQL Server sblocca automaticamente il database e riprende le normali operazioni.

In genere, l'intero processo viene completato in meno di un secondo, riducendo al minimo la durata del blocco di scrittura sul database. Durante il blocco, i dati possono essere letti, ma non scritti. Puoi annullare manualmente lo stato di blocco impostando SUSPEND_FOR_SNAPSHOT_BACKUP=OFF per il database.

Obiettivi

In questo tutorial imparerai a completare le seguenti attività:

  • Crea un'istanza SQL Server con due dischi dati.
  • Crea un nuovo database con i file di dati e di log su dischi separati.
  • Crea un gruppo di coerenza di tutti i dischi della VM che esegue SQL Server.
  • Crea snapshot istantanei del gruppo di dischi.
  • Crea nuovi dischi dagli snapshot istantanei.

Costi

In questo documento vengono utilizzati i seguenti componenti fatturabili di Google Cloud:

Per generare una stima dei costi in base all'utilizzo previsto, utilizza il calcolatore prezzi.

I nuovi Google Cloud utenti potrebbero avere diritto a una prova senza costi.

Al termine delle attività descritte in questo documento, puoi evitare l'addebito di ulteriori costi eliminando le risorse che hai creato. Per saperne di più, consulta Esegui la pulizia.

Prima di iniziare

  1. Per questo tutorial, è necessario un Google Cloud progetto. Puoi crearne uno nuovo o selezionarne uno esistente:

    1. Nella Google Cloud console, nella pagina di selezione del progetto, seleziona o crea un Google Cloud progetto.

      Ruoli necessari per selezionare o creare un progetto

      • Seleziona un progetto: la selezione di un progetto non richiede un ruolo IAM specifico. Puoi selezionare qualsiasi progetto su cui ti è stato concesso un ruolo.
      • Crea un progetto: per creare un progetto, devi disporre del ruolo Autore progetto (roles/resourcemanager.projectCreator), che contiene l' resourcemanager.projects.create autorizzazione. Scopri come concedere i ruoli.

      Vai al selettore di progetti

    2. Verifica che la fatturazione sia attivata per il tuo Google Cloud progetto.

    3. Nella Google Cloud console, attiva Cloud Shell.

      Attiva Cloud Shell

  2. Assicurati che Microsoft SQL Server 2022 o versioni successive sia installato e in esecuzione.

Autorizzazioni obbligatorie

Oltre all'accesso in lettura standard, assicurati che l'amministratore di SQL Server ti conceda l'autorizzazione ALTER DATABASE per il database di destinazione.

Per ottenere le autorizzazioni necessarie per creare un'istanza e creare snapshot, chiedi all'amministratore di concederti i seguenti ruoli IAM nel progetto:

  • Gestisci istanza: compute.instanceAdmin.v1
  • Crea snapshot: compute.storageAdmin

Per saperne di più sulla concessione dei ruoli, consulta Gestisci l'accesso a progetti, cartelle e organizzazioni.

Potresti anche riuscire a ottenere le autorizzazioni richieste tramite i ruoli personalizzati o altri ruoli predefiniti.

Crea un'istanza SQL di Compute Engine

Crea un'istanza SQL Server.

  1. Nella console Google Cloud , apri Cloud Shell facendo clic sul pulsante Attiva Cloud Shell Attiva Cloud Shell..

    Vai alla Google Cloud console

  2. Crea un'istanza SQL Server. Incolla il seguente comando:

  REGION=REGION
  ZONE=$REGION-a
  VM_NAME=VM_NAME
  gcloud compute instances create $VM_NAME \
    --boot-disk-auto-delete \
    --boot-disk-size 100 \
    --boot-disk-type hyperdisk-balanced \
    --image-family sql-std-2022-win-2025 \
    --image-project windows-sql-cloud \
    --machine-type c4-highmem-4 \
    --zone $ZONE \
    --network-interface subnet=default \
    --tags sql-server-instant-snapshot \
    --scopes=cloud-platform,service-control,service-management,monitoring-write,logging-write,storage-rw \
    --create-disk=device-name=$VM_NAME-data-disk1,mode=rw,name=$VM_NAME-data-disk1,size=100,type=hyperdisk-balanced \
    --create-disk=device-name=$VM_NAME-data-disk2,mode=rw,name=$VM_NAME-data-disk2,size=100,type=hyperdisk-balanced

Sostituisci quanto segue:

  • Regione: la regione in cui verrà eseguito il deployment della nuova istanza.
  • VM_NAME: il nome della nuova istanza SQL Server.

Crea un gruppo di coerenza dei dischi

  1. Crea un gruppo di coerenza.

    gcloud compute resource-policies create disk-consistency-group $VM_NAME-snap-grp \
        --region=$REGION
    
  2. Aggiungi i dischi della VM al gruppo di coerenza.

    gcloud compute disks add-resource-policies $VM_NAME \
        --zone=$ZONE \
        --resource-policies=$VM_NAME-snap-grp
    
    gcloud compute disks add-resource-policies $VM_NAME-data-disk1 \
        --zone=$ZONE \
        --resource-policies=$VM_NAME-snap-grp
    
    gcloud compute disks add-resource-policies $VM_NAME-data-disk2 \
        --zone=$ZONE \
        --resource-policies=$VM_NAME-snap-grp
    

Crea un nuovo database

  1. Crea un nome utente e una password per l'istanza VM.
  2. Connettiti alla VM utilizzando Remote Desktop e accedi con il nome utente e la password creati nel passaggio precedente.
  3. Fai clic con il tasto destro del mouse sul pulsante Start (o premi Win+X) e poi fai clic su Terminale (Amministratore).
  4. Conferma la richiesta di elevazione facendo clic su .
  5. Esegui il seguente script PowerShell nella finestra del terminale aperta. Questo script inizializza il disco dati, lo formatta con una dimensione del blocco di 64 KB e assegna una lettera di unità.

    $availableDisks = Get-PhysicalDisk -CanPool $True
    $diskLetters = [char[]] (68..72) | Where-Object { !(Get-PSDrive $_ -ErrorAction SilentlyContinue) }
    $diskCount = 0
    foreach ($disk in $availableDisks) {
        $diskLetter = $diskLetters[$diskCount]
        $diskLabel = "$diskLetter-DataDisk"
        Initialize-Disk -Number $disk.DeviceId -PartitionStyle MBR -PassThru
    
        New-Partition -DiskNumber $disk.DeviceId -UseMaximumSize `
        -DriveLetter $diskLetter | Format-Volume -FileSystem NTFS `
        -NewFileSystemLabel $diskLabel -AllocationUnitSize 65536 -Confirm:$false
    
        New-Item -ItemType Directory -Path "$($diskLetter):\MSSQL"
        $diskCount = $diskCount +1
    }
    
  6. Apri SQL Server Management Studio (SSMS). Eseguilo come amministratore.

  7. Nella finestra di dialogo Connettiti al server, verifica che il nome del server sia impostato su localhost e seleziona Connetti.

  8. Nel menu File, seleziona File > Nuovo > Query con la connessione attuale.

  9. Copia il seguente codice nella finestra di query appena aperta.

    USE Master;
    GO
    CREATE DATABASE SnapBackupDB
    ON PRIMARY
    (
        NAME = 'SnapBackupDB_Data',
        FILENAME = 'D:\MSSQL\SnapBackupDB.mdf',
        SIZE = 500MB,
        MAXSIZE = UNLIMITED,
        FILEGROWTH = 64MB
    )
    LOG ON
    (
        NAME = 'SnapBackupDB_Log',
        FILENAME = 'E:\MSSQL\SnapBackupDB_log.ldf',
        SIZE = 250MB,
        MAXSIZE = 2GB,
        FILEGROWTH = 64MB
    );
    

Esegui il deployment dello script di snapshot

Questo script automatizza l'intero processo necessario per acquisire snapshot coerenti con l'applicazione dei dischi collegati alla VM che esegue SQL Server.

  1. Utilizzando la stessa sessione di Remote Desktop, apri Blocco note.
  2. Copia i contenuti dello script seguente e incollali nella finestra del Blocco note aperta.
  3. Salva il file come take-snapshot.ps1 in c:\scripts

    # Import Modules
    Import-Module -Name SQLPS
    
    # Set variables
    $formattedTimestamp = Get-Date -Format 'yyyyMMdd-HHmmss'
    $backupLocation = 'D:\MSSQL\Backup'
    $dbName = 'SnapBackupDB'
    $bkmFile = Join-Path -Path $backupLocation  -ChildPath ("${dbName}_${formattedTimestamp}.bkm")
    $sqlServer = 'localhost'
    
    # SQL Commands
    $suspendDbCmd = "ALTER DATABASE [$dbName] SET SUSPEND_FOR_SNAPSHOT_BACKUP=ON WITH NO_WAIT;"
    $backupMetadataCmd = "BACKUP DATABASE [$dbName] TO DISK='$bkmFile' WITH METADATA_ONLY, FORMAT;"
    $unsuspendDbCmd = "ALTER DATABASE [$dbName] SET SUSPEND_FOR_SNAPSHOT_BACKUP=OFF;"
    
    # --- Helper Function for SQL Execution ---
    function Invoke-MySqlCommand {
        param(
            [Parameter(Mandatory=$true)]
            [string]$CommandText,
            [Parameter(Mandatory=$true)]
            [System.Data.SqlClient.SqlConnection]$SqlConnection
        )
        Write-Host "Executing SQL Command: $($CommandText)"
        try {
            $Command = New-Object System.Data.SqlClient.SqlCommand($CommandText, $SqlConnection)
            $Result = $Command.ExecuteNonQuery()
            return $true
        }
        catch {
            Write-Host "Error executing SQL Command: $($CommandText)`n$($_.Exception.Message)" -ForegroundColor Red
            return $false
        }
    }
    
    $sqlConn = New-Object System.Data.SqlClient.SqlConnection
    $sqlConn.ConnectionString = "server='$sqlServer';database='$dbName';Integrated Security=True;"
    $databaseSuspended = $false
    
    if (-not(Test-Path $backupLocation)) {
        New-Item -Path $backupLocation -ItemType directory -Force
    }
    
    try {
        $instanceName = (Invoke-RestMethod -Headers @{"Metadata-Flavor"="Google"} -Uri "http://metadata.google.internal/computeMetadata/v1/instance/name")
        $vmConfigString = (gcloud compute instances list --filter="name=('$instanceName')" --format=json --quiet)
        if ($LASTEXITCODE -ne 0) {
            Write-Host "Error querying gcloud for VM instances (exit code: $LASTEXITCODE). Exiting." -ForegroundColor Red
            exit 1
        }
        $vmConfig = $vmConfigString | ConvertFrom-Json
    
        # Open SQL Server connection
        $sqlConn.Open()
    
        # Suspend Database
        Write-Host "Suspending database '$dbName' for snapshot..."
        if (-not (Invoke-MySqlCommand -CommandText $suspendDbCmd -SqlConnection $sqlConn)) {
            Write-Host "Failed to suspend database. Exiting." -ForegroundColor Red
            exit 1
        }
        $databaseSuspended = $true
    
        # Take a disk snapshot
        try {
            $consistencyGroupListStr = (gcloud compute resource-policies list --filter='name:*-snap-grp' --format=json --quiet)
            if ($LASTEXITCODE -ne 0) { throw "gcloud resource-policies list failed (exit code: $LASTEXITCODE)." }
            $consistencyGroupList = $consistencyGroupListStr | ConvertFrom-Json
    
            if (@($consistencyGroupList).Count -eq 0) { throw "No consistency group found matching '*-snap-grp'." }
            if (@($consistencyGroupList).Count -gt 1) { Write-Warning "More than one consistency group found, using the first one." }
    
            $consistencyGroupSelfLink = $consistencyGroupList[0].selfLink
            $zoneName = Split-Path $vmConfig[0].zone -Leaf
            $snapshotName = "$($vmConfig.Name)-${formattedTimestamp}"
    
            $snapshotCmd = "gcloud compute instant-snapshot-groups create $snapshotName --source-consistency-group=$consistencyGroupSelfLink --zone=$zoneName --quiet"
            Invoke-Expression $snapshotCmd
            if ($LASTEXITCODE -ne 0) { throw "gcloud compute instant-snapshot-groups create failed (exit code: $LASTEXITCODE)." }
            Write-Host "Instant snapshot group created successfully."
        }
        catch {
            Write-Host "Error during snapshot creation: $($_.Exception.Message)" -ForegroundColor Red
            exit 1 # Exit after handling in finally
        }
    
        # Backup database metadata
        if (-not (Invoke-MySqlCommand -CommandText $backupMetadataCmd -SqlConnection $sqlConn)) {
            Write-Host "Failed to backup database metadata." -ForegroundColor Red
            exit 1
        }
    
        # Unsuspend Database
        Write-Host "Unsuspending database '$dbName'..."
        if (-not (Invoke-MySqlCommand -CommandText $unsuspendDbCmd -SqlConnection $sqlConn)) {
            Write-Host "Failed to unsuspend database after successful snapshot and metadata backup. Manual intervention may be required." -ForegroundColor Red
            exit 1
        }
        $databaseSuspended = $false # Successfully unsuspended
    
    }
    catch {
        Write-Host "An unhandled error occurred: $($_.Exception.Message)" -ForegroundColor Red
        exit 1
    }
    finally {
        if ($databaseSuspended -and ($sqlConn.State -eq [System.Data.ConnectionState]::Open)) {
            if (-not (Invoke-MySqlCommand -CommandText $unsuspendDbCmd -SqlConnection $sqlConn)) {
                Write-Host "Failed to unsuspend database in finally block. Manual intervention may be required." -ForegroundColor Red
            }
        }
    
        # Ensure SQL connection is closed
        if ($sqlConn.State -eq [System.Data.ConnectionState]::Open) {
            $sqlConn.Close()
        }
    }
    
    
  4. Fai clic con il tasto destro del mouse sul pulsante Start (o premi Win+X) e poi fai clic su Terminale (Amministratore).

  5. Conferma la richiesta di elevazione facendo clic su .

  6. Esegui lo script eseguendo il comando seguente.

        C:\scripts\take-snapshot.ps1
    

Verifica che gli snapshot istantanei siano stati creati

Esegui questi comandi in Cloud Shell:

  1. Verifica che lo script abbia creato gli snapshot.

        gcloud compute instant-snapshots list --filter="name:$VM_NAME*"
    
  2. Elenca i gruppi di snapshot istantanei.

        gcloud compute instant-snapshot-groups list --zones $ZONE
    
  3. Visualizza i dettagli del gruppo di snapshot istantanei.

        gcloud compute instant-snapshot-groups describe  \
        INSTANT_SNAPSHOT_NAME --zone=$ZONE
    
  4. Copia il valore selfLink da utilizzare nella sezione successiva.

Ripristina gli snapshot istantanei su nuovi dischi

Esegui questi comandi nella Google Cloud finestra della console:

  1. Crea dischi dal gruppo di coerenza degli snapshot istantanei.

        gcloud compute disks bulk create --source-instant-snapshot-group \
        INSTANT_SNAPSHOT_NAME_URL \
        --source-instant-snapshot-group-region $REGION --zone=$ZONE
    
  2. Verifica che gli snapshot siano stati ripristinati elencando i dischi nella zona.

        gcloud compute disks list --zones=$ZONE --filter="name:$VM_NAME-*"
    
  3. Crea una nuova VM dai dischi appena creati.

    REGION=REGION
    ZONE=$REGION-a
    VM_NAME=VM_NAME
    gcloud compute instances create $VM_NAME \
        --machine-type c4-highmem-4 \
        --zone $ZONE \
        --network-interface subnet=default \
        --tags sql-server-instant-snapshot \
        --disk=name=BOOT_DISK_NAME,boot=yes,auto-delete=no \
        --disk=name=DATA_DISK_1_NAME,mode=rw,auto-delete=no \
        --disk=name=DATA_DISK_2_NAME,mode=rw,auto-delete=no
    

Sostituisci quanto segue:

  • Regione: la regione in cui verrà eseguito il deployment della nuova istanza.
  • VM_NAME: il nome della nuova istanza SQL.
  • BOOT_DISK_NAME: il nome del disco di avvio creato nel passaggio precedente.
  • DATA_DISK_1_NAME: il nome del primo disco dati creato nel passaggio precedente.
  • DATA_DISK_2_NAME: il nome del secondo disco dati creato nel passaggio precedente.

Ora puoi collegare i dischi a una VM nuova o esistente.

Libera spazio

Per evitare che al tuo Google Cloud account vengano addebitati costi relativi alle risorse utilizzate in questo tutorial, elimina il progetto.

Elimina il progetto

  1. Nella Google Cloud console, vai alla pagina Gestisci risorse.

    Vai a Gestisci risorse

  2. Nell'elenco dei progetti, seleziona il progetto che vuoi eliminare, quindi fai clic su Elimina.
  3. Nella finestra di dialogo, digita l'ID progetto, quindi fai clic su Chiudi per eliminare il progetto.

Passaggi successivi

  • Esplora architetture di riferimento, diagrammi e best practice su Google Cloud. Consulta il nostro Cloud Architecture Center.