Crea copias de seguridad de SQL Server con instantáneas

Si los archivos de la base de datos de SQL Server están distribuidos en varios discos, puedes crear copias de seguridad de todos los discos de forma simultánea y mantener la coherencia de los datos y las aplicaciones. Puedes lograr esta copia de seguridad en un momento determinado exacto con los grupos de coherencia de instantáneas inmediatas de Compute Engine, que te permiten crear copias de seguridad de los datos en un grupo de discos.

En este instructivo, se describe cómo crear copias de seguridad de bases de datos de SQL Server con instantáneas de Compute Engine y la función de instantáneas de Transact-SQL (T-SQL) que está disponible en SQL Server 2022 y versiones posteriores. Esta solución admite implementaciones de Windows y Linux, y minimiza el impacto en el rendimiento de tus cargas de trabajo en vivo.

Cómo funciona

El flujo de trabajo consta de estos pasos principales, que se administran con una secuencia de comandos que se ejecuta en una instancia de procesamiento:

  1. Inmoviliza la base de datos: La secuencia de comandos envía un comando de T-SQL a SQL Server para suspender todas las operaciones de escritura de las bases de datos de destino. Esto garantiza que los archivos de la base de datos se encuentren en un estado coherente para la copia de seguridad.
  2. Toma instantáneas: Mientras la base de datos está inactiva, crea un grupo de instantáneas de los discos en los que residen los archivos de registro y datos de la base de datos. Este es el equivalente de Google Clouda usar un mecanismo de instantáneas a nivel de hardware o servicio.
  3. Record and thaw: La secuencia de comandos envía otro comando de T-SQL a SQL Server para registrar los metadatos de la copia de seguridad. Este comando crea un pequeño archivo de copia de seguridad que apunta al grupo de coherencia de instantáneas inmediatas y se registra en el historial de copias de seguridad msdb. Una vez completado el proceso, SQL Server descongela automáticamente la base de datos y reanuda las operaciones normales.

Por lo general, todo este proceso se completa en menos de un segundo, lo que minimiza la duración de la inmovilización de escritura en tu base de datos. Mientras la inmovilización esté vigente, se podrán leer los datos, pero no escribirlos. Puedes cancelar manualmente el estado de inmovilización configurando SUSPEND_FOR_SNAPSHOT_BACKUP=OFF para la base de datos.

Objetivos

En este instructivo, aprenderás a completar las siguientes tareas:

  • Crea una instancia de SQL Server con dos discos de datos.
  • Crea una base de datos nueva con los archivos de datos y de registro en discos separados.
  • Crea un grupo de coherencia de todos los discos de la VM que ejecuta SQL Server.
  • Crea instantáneas inmediatas del grupo de discos.
  • Crea discos nuevos a partir de las instantáneas.

Costos

En este documento, usarás los siguientes componentes facturables de Google Cloud:

Para generar una estimación de costos en función del uso previsto, usa la calculadora de precios.

Es posible que los usuarios de Google Cloud nuevos cumplan con los requisitos para acceder a una prueba gratuita.

Cuando completes las tareas que se describen en este documento, podrás borrar los recursos que creaste para evitar que se te siga facturando. Para obtener más información, consulta Realiza una limpieza.

Antes de comenzar

  1. Para este instructivo, necesitas un proyecto Google Cloud . Puedes crear uno nuevo o seleccionar un proyecto existente:

    1. En la consola de Google Cloud , en la página del selector de proyectos, selecciona o crea un proyecto de Google Cloud .

      Roles necesarios para seleccionar o crear un proyecto

      • Selecciona un proyecto: Para seleccionar un proyecto, no se requiere un rol de IAM específico. Puedes seleccionar cualquier proyecto en el que se te haya otorgado un rol.
      • Crear un proyecto: Para crear un proyecto, necesitas el rol de Creador de proyectos (roles/resourcemanager.projectCreator), que contiene el permiso resourcemanager.projects.create. Obtén más información para otorgar roles.

      Ir al selector de proyectos

    2. Verifica que la facturación esté habilitada para tu proyecto de Google Cloud .

    3. En la consola de Google Cloud , activa Cloud Shell.

      Activa Cloud Shell

  2. Asegúrate de que Microsoft SQL Server 2022 o una versión posterior esté instalado y en ejecución.

Permisos necesarios

Además del acceso de lectura estándar, asegúrate de que el administrador de SQL Server te otorgue el permiso ALTER DATABASE para la base de datos de destino.

Para obtener los permisos que necesitas para crear instancias y crear instantáneas, pídele a tu administrador que te otorgue los siguientes roles de IAM en el proyecto:

  • Administrar instancia: compute.instanceAdmin.v1
  • Crea instantáneas: compute.storageAdmin

Para obtener más información sobre cómo otorgar roles, consulta Administra el acceso a proyectos, carpetas y organizaciones.

También puedes obtener los permisos necesarios a través de roles personalizados o cualquier otro rol predefinido.

Crea una instancia de SQL de Compute Engine

Crea una instancia de SQL Server.

  1. En la Google Cloud consola, haz clic en el botón Activar Cloud Shell Activar Cloud Shell. para abrir Cloud Shell.

    Ir a la consola de Google Cloud

  2. Crea una instancia de SQL Server. Pega el siguiente 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

Reemplaza lo siguiente:

  • Región: Es la región en la que se implementará tu instancia nueva.
  • VM_NAME: Es el nombre de tu nueva instancia de SQL Server.

Crea un grupo de coherencia de discos

  1. Crea un grupo de coherencia.

    gcloud compute resource-policies create disk-consistency-group $VM_NAME-snap-grp \
        --region=$REGION
    
  2. Agrega los discos de la VM al grupo de coherencia.

    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
    

Crear una base de datos nueva

  1. Crea un nombre de usuario y una contraseña para la instancia de VM.
  2. Conéctate a la VM mediante el escritorio remoto y accede con el nombre de usuario y la contraseña que creaste en el paso anterior.
  3. Haz clic con el botón derecho en el botón Iniciar (o presiona Win+X) y, luego, en Terminal (Admin).
  4. Para confirmar el símbolo de elevación, haz clic en .
  5. Ejecuta la siguiente secuencia de comandos de PowerShell en la ventana de la terminal que se abrió. Este secuencia de comandos inicializa el disco de datos, lo formatea con un tamaño de bloque de 64 KB y le asigna una letra de unidad.

    $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. Abre SQL Server Management Studio (SSMS). Ejecútalo como administrador.

  7. En el cuadro de diálogo Conectar al servidor, verifica que el nombre del servidor esté configurado como localhost y selecciona Conectar.

  8. En el menú de archivo, selecciona Archivo > Nuevo > Consulta con la conexión actual.

  9. Copia el siguiente código en la ventana de consulta que se abrió recientemente.

    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
    );
    

Implementa la secuencia de comandos de instantáneas

Esta secuencia de comandos automatiza el proceso completo necesario para tomar instantáneas coherentes con la aplicación de los discos conectados a la VM que ejecuta SQL Server.

  1. En la misma sesión de Escritorio remoto, abre el Bloc de notas.
  2. Copia el contenido de la siguiente secuencia de comandos y pégalo en la ventana del Bloc de notas que se abrió.
  3. Guarda el archivo como take-snapshot.ps1 en 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. Haz clic con el botón derecho en el botón Iniciar (o presiona Win+X) y, luego, en Terminal (Admin).

  5. Para confirmar el símbolo de elevación, haz clic en .

  6. Ejecuta la secuencia de comandos con el siguiente comando.

        C:\scripts\take-snapshot.ps1
    

Verifica que se hayan creado las instantáneas

Ejecuta los siguientes comandos en Cloud Shell

  1. Verifica que la secuencia de comandos haya creado las instantáneas.

        gcloud compute instant-snapshots list --filter="name:$VM_NAME*"
    
  2. Enumera los grupos de instantáneas inmediatas.

        gcloud compute instant-snapshot-groups list --zones $ZONE
    
  3. Consulta los detalles del grupo de instantáneas inmediatas.

        gcloud compute instant-snapshot-groups describe  \
        INSTANT_SNAPSHOT_NAME --zone=$ZONE
    
  4. Copia el valor de selfLink para usarlo en la siguiente sección.

Restablece las Instant Snapshots en discos nuevos

Ejecuta los siguientes comandos en la ventana de la consola Google Cloud .

  1. Crea discos a partir del grupo de coherencia de instantáneas inmediatas.

        gcloud compute disks bulk create --source-instant-snapshot-group \
        INSTANT_SNAPSHOT_NAME_URL \
        --source-instant-snapshot-group-region $REGION --zone=$ZONE
    
  2. Para confirmar que se restablecieron tus instantáneas, enumera los discos de la zona.

        gcloud compute disks list --zones=$ZONE --filter="name:$VM_NAME-*"
    
  3. Crea una VM nueva a partir de los discos recién creados.

    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
    

Reemplaza lo siguiente:

  • Región: Es la región en la que se implementará tu instancia nueva.
  • VM_NAME: Es el nombre de tu nueva instancia de SQL.
  • BOOT_DISK_NAME: Es el nombre del disco de arranque que se creó en el paso anterior.
  • DATA_DISK_1_NAME: Es el nombre del primer disco de datos creado en el paso anterior.
  • DATA_DISK_2_NAME: Es el nombre del segundo disco de datos creado en el paso anterior.

Ahora puedes conectar los discos a una VM nueva o existente.

Realiza una limpieza

Para evitar que se apliquen cargos a tu cuenta de Google Cloud por los recursos que usaste en este instructivo, borra el proyecto.

Borra el proyecto

  1. En la Google Cloud consola, ve a la página Administrar recursos.

    Ir a Administrar recursos

  2. En la lista de proyectos, elige el proyecto que quieres borrar y haz clic en Borrar.
  3. En el diálogo, escribe el ID del proyecto y, luego, haz clic en Cerrar para borrar el proyecto.

¿Qué sigue?

  • Explora arquitecturas de referencia, diagramas y prácticas recomendadas sobre Google Cloud. Consulta nuestro Cloud Architecture Center.