Ha pasado un tiempo desde mi última publicación, y quería seguir explorando algunas de las nuevas características que ofrece SQL Server 2016.
Esto técnicamente no es nuevo, pero sabes que se dice que es mejor esperar una segunda (o tercera) versión de cualquier tecnología para adoptarlo, así que me remangué y actualicé mi suscripción a Azure para crear un entorno híbrido con partes (grupos de archivos) de mi base de datos en local y otras en la nube (almacenamiento blob).
Estas técnicas se explican de alguna manera en Books online, y aunque el ejemplo proporcionado se basa en la copia de seguridad y restauración, los pasos para preparar las cosas son bastante similares, por lo que lo recomiendo encarecidamente como referencia.
Antecedentes
Para extender una base de datos de local a la nube (Azure) primero se requiere una suscripción de Azure (se puede obtener una con algo de dinero gratis en unos pocos minutos), que he explicado en otro blog post no hace mucho, por lo que voy a saltar esta parte y asumiremos que ya tenéis una.
Los archivos de base de datos se almacenan en Azure como blobs, por lo que necesitaremos crear una Cuenta de almacenamiento dentro de nuestra suscripción para poder colocar esos archivos de base de datos.
El proceso para crear nuestra propia cuenta de almacenamiento es bastante simple, podéis ver en la imagen dónde hacer clic desde Azure Dashboard para hacerlo.
En la columna de la derecha tenemos que tomar la decisión más importante, como cada vez que creamos algo en Azure, y esa es la pasta $$, perdón, quería decir el rendimiento y la disponibilidad 🙂
Cuanto más rendimiento y disponibilidad necesitemos, más dinero se nos facturará, así que tened cuidado, pero recuerdad que podéis (en teoría) incrementar o reducirlo sin tiempo de inactividad, para que podamos ajustar el rendimiento a nuestro presupuesto o viceversa.
Powershell
Yo personalmente recomendaría usar PowerShell ya que es más fácil (tan simple como copiar/pegar y cambiar algunos valores) y también proporcionará la sintaxis para crear la credencial de SQL Server requerida, que se necesita para conectarse desde nuestro servidor SQL local a la instancia en la nube.
Es posible que necesitemos instalar el módulo de PowerShell antes de ejecutar el script.
Después de algunas modificaciones en el original, el script de powershell se vería así
<# This script uses the Azure Resource model and creates a new ARM storage account. Modify this script to use an existing ARM or classic storage account using the instructions in comments within this script Original Script -> https://msdn.microsoft.com/en-us/library/dn466430.aspx Modified by -> Raul Gonzalez @SQLDoubleG #> # Define global variables for the script # # TODO: Set values # $prefixName = 'prefixName' # used as the prefix for the name for various objects, your choice $subscriptionName='My Subscription Name' # the name of subscription name you will use, look for subscriptions in your azure portal. $locationName = 'ukwest' # the data center region you will use, see Get-AzureRmLocation for choices $storageAccountName= 'storageAccountName' # the storage account name you will create or use $containerName= 'containerName' # the storage container name to which you will attach the SAS policy with its SAS token $policyName = $prefixName + 'policy' # the name of the SAS policy # Storage Tier options, more money, more performance, see full details about pricing in # https://azure.microsoft.com/en-us/pricing/details/storage/blobs/ # $storageType = 'Standard_LRS' # cheap #$storageType = 'Standard_GRS' # mid #$storageType = 'Standard_RAGRS' # expensive # # Using Azure Resource Manager deployment model. # If you want to use the classic storage account, see original script on the header # # Set a variable for the name of the resource group you will create or use $resourceGroupName= 'blbstg' # adds an authenticated Azure account for use in the session Login-AzureRmAccount # set the tenant, subscription and environment for use in the rest of Set-AzureRmContext -SubscriptionName $subscriptionName # check the existance of the resource group and create one if it does not exist if (!(Get-AzureRmResourceGroup -Name $resourceGroupName)) { New-AzureRmResourceGroup -Name $resourceGroupName -Location $locationName } # check the existance of the ARM storage account and create one if it does not exist if (!(Get-AzureRmStorageAccount -Name $storageAccountName -ResourceGroupName $resourceGroupName)){ New-AzureRmStorageAccount -Name $storageAccountName -ResourceGroupName $resourceGroupName -Type $storageType -Location $locationName } # Get the access keys for the ARM storage account $accountKeys = Get-AzureRmStorageAccountKey -ResourceGroupName $resourceGroupName -Name $storageAccountName # Create a new storage account context using an ARM storage account $storageContext = New-AzureStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $accountKeys[0].Value $container = Get-AzureStorageContainer -Context $storageContext -Name $containerName # Creates a new container in blob storage if not exists if (!$container){ $container = New-AzureStorageContainer -Context $storageContext -Name $containerName } $cbc = $container.CloudBlobContainer # Sets up a Stored Access Policy and a Shared Access Signature for the new container $permissions = $cbc.GetPermissions(); $policy = new-object 'Microsoft.WindowsAzure.Storage.Blob.SharedAccessBlobPolicy' $policy.SharedAccessStartTime = $(Get-Date).ToUniversalTime().AddMinutes(-5) $policy.SharedAccessExpiryTime = $(Get-Date).ToUniversalTime().AddYears(10) $policy.Permissions = "Read,Write,List,Delete" try{ $permissions.SharedAccessPolicies.Add($policyName, $policy) } catch{ echo 'An item with the same key has already been added. Skipping this step.' } $cbc.SetPermissions($permissions); # Gets the Shared Access Signature for the policy $policy = new-object 'Microsoft.WindowsAzure.Storage.Blob.SharedAccessBlobPolicy' $sas = $cbc.GetSharedAccessSignature($policy, $policyName) Write-Host 'Shared Access Signature= '$($sas.Substring(1))'' # Outputs the Transact SQL to the clipboard and to the screen to create the credential using the Shared Access Signature Write-Host 'Credential T-SQL' $tSql = "CREATE CREDENTIAL [{0}] WITH IDENTITY='Shared Access Signature', SECRET='{1}'" -f $cbc.Uri,$sas.Substring(1) $tSql | clip Write-Host $tSql
Crear la credencial
Si todo ha ido de acuerdo con el plan, ya deberíamos tener copiado en el portapapeles el T-SQL para crear la credencial, que debería verse como
USE master GO CREATE CREDENTIAL 'https://<mystorageaccountname>.blob.core.windows.net/<mystorageaccountcontainername>' -- this name must match the container path, start with https and must not contain a forward slash. WITH IDENTITY='SHARED ACCESS SIGNATURE' -- this is a mandatory string and do not change it. , SECRET = 'sharedaccesssignature' -- this is the shared access signature key that you by running the powershell script GO
Estirando nuestra base de datos
Si seguis el ejemplo proporcionado en Books Online, terminaréis restaurando una copia de vuestras bases de datos locales en la nube, pero en este ejemplo, para estirar mi base de datos voy a incluir una combinación de archivos almacenados en local y algunos más en la nube, probablemente aquellos que no requieran mucha chicha.
Una vez que estemos aquí, esto debería ser muy familiar para cualquier DBA.
CREATE DATABASE [stretch_test] ON PRIMARY( NAME = N'st_primary' , FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQL2016\MSSQL\DATA\stretch_test\st_primary.mdf' , SIZE=5MB, FILEGROWTH = 4MB) , FILEGROUP [USER_DATA]( NAME = N'st_user_data' , FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQL2016\MSSQL\DATA\stretch_test\st_user_data.ndf' , SIZE=4MB, FILEGROWTH = 4MB) , FILEGROUP [STRETCH_DATA] (NAME = N'st_stretch_data' , FILENAME = 'https://<mystorageaccountname>.blob.core.windows.net/<mystorageaccountcontainername>/st_stretch_data.ndf' , SIZE=4MB, FILEGROWTH = 4MB) LOG ON ( NAME = N'st_Log' , FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQL2016\MSSQL\DATA\stretch_test\st_log.ldf' , SIZE = 4MB , FILEGROWTH = 4MB ) GO
Eso es casi lo mismo, pero solo apuntando a nuestro almacenamiento de blobs para colocar allí los archivos que entendemos que estarán mejor en la nube.
Si comprobamos los metadatos de la base de datos, todo parece normal
SELECT DB_NAME(f.database_id) AS db_name , f.file_id , f.name AS logical_name , FILEGROUP_NAME(f.data_space_id) AS [filegroup] , f.type_desc , (f.size * 8 / 1024) AS size_MB , physical_name FROM sys.master_files AS f WHERE f.database_id = DB_ID('stretch_test')
Conclusión
Una vez más me he sorprendido de la rapidez con la que puedes empezar a utilizar Azure a la vieja usanza, quiero decir con solo un poco de conocimiento adicional, que siempre es algo bueno.
Solo un pequeño cambio puede abrir múltiples posibilidades y traer beneficios como la reducción del costo de nuestro almacenamiento, mejorar nuestra disponibilidad sin gastar una fortuna en equipos sofisticados y mucho más.
Realmente me está gustando esto y tengo ganas de explorar en más produndidad, porque tarde o temprano necesitaremos estar preparados para, tal vez no todos, pero seguro que algunos proyectos en la nube.
¡Gracias por leer!