|
| 1 | +--- |
| 2 | +title: Fail over database with link feature with T-SQL and PowerShell scripts |
| 3 | +titleSuffix: Azure SQL Managed Instance |
| 4 | +description: This guide teaches you how to use the SQL Managed Instance link with scripts to fail over database from SQL Server to Azure SQL Managed Instance. |
| 5 | +services: sql-database |
| 6 | +ms.service: sql-managed-instance |
| 7 | +ms.subservice: data-movement |
| 8 | +ms.custom: |
| 9 | +ms.devlang: |
| 10 | +ms.topic: guide |
| 11 | +author: sasapopo |
| 12 | +ms.author: sasapopo |
| 13 | +ms.reviewer: mathoma |
| 14 | +ms.date: 03/15/2022 |
| 15 | +--- |
| 16 | + |
| 17 | +# Failover (migrate) database with Azure SQL Managed Instance link feature with T-SQL and PowerShell scripts |
| 18 | + |
| 19 | +[!INCLUDE[appliesto-sqlmi](../includes/appliesto-sqlmi.md)] |
| 20 | + |
| 21 | +This article teaches you to use T-SQL and PowerShell scripts for [Managed Instance link feature](link-feature.md) to fail over (migrate) your database from SQL Server to Azure SQL Managed Instance. |
| 22 | + |
| 23 | +> [!NOTE] |
| 24 | +> The link feature for Azure SQL Managed Instance is currently in preview. |
| 25 | +
|
| 26 | +> [!NOTE] |
| 27 | +> Configuration on Azure side is done with PowerShell that calls SQL Managed Instance REST API. Support for Azure PowerShell and CLI will be released in the upcomming weeks. At that point this article will be updated with the simplified PowerShell scripts. |
| 28 | +
|
| 29 | +> [!TIP] |
| 30 | +> SQL Managed Instance link database failover can be set up with [SSMS wizard](managed-instance-link-use-ssms-to-failover-database.md). |
| 31 | +
|
| 32 | +Database failover from SQL Server instance to SQL Managed Instance breaks the link between the two databases. Failover stops replication and leaves both databases in an independent state, ready for individual read-write workloads. |
| 33 | + |
| 34 | +To start migrating database to the SQL Managed Instance, first stop the application workload to the SQL Server during your maintenance hours. This is required to enable SQL Managed Instance to catchup with the database replication and make migration to Azure without any data loss. |
| 35 | + |
| 36 | +While database is a part of Always On Availability Group, it isn't possible to set it to read-only mode. You'll need to ensure that your application(s) aren't committing transactions to SQL Server. |
| 37 | + |
| 38 | +## Switch the replication mode from asynchronous to synchronous |
| 39 | + |
| 40 | +The replication between SQL Server and SQL Managed Instance is asynchronous by default. Before you perform database migration to Azure, the link needs to be switched to synchronous mode. Synchronous replication across distances might slow down transactions on the primary SQL Server. |
| 41 | +Switching from async to sync mode requires replication mode change on SQL Managed Instance and SQL Server. |
| 42 | + |
| 43 | +## Switch replication mode on Managed Instance |
| 44 | + |
| 45 | +Use the following PowerShell script to call REST API that changes the replication mode from asynchronous to synchronous on SQL Managed Instance. We suggest you execute the REST API call using Azure Cloud Shell in Azure portal. |
| 46 | + |
| 47 | +Replace `<YourSubscriptionID>` with your subscription ID and replace `<ManagedInstanceName>` with the name of your managed instance. Replace `<DAGName>` with the name of Distributed Availability Group link for which you’d like to get the status. |
| 48 | + |
| 49 | +```powershell |
| 50 | +# ==================================================================================== |
| 51 | +# POWERSHELL SCRIPT TO SWITCH REPLICATION MODE SYNC-ASYNC ON MANAGED INSTANCE |
| 52 | +# USER CONFIGURABLE VALUES |
| 53 | +# (C) 2021-2022 SQL Managed Instance product group |
| 54 | +# ==================================================================================== |
| 55 | +# Enter your Azure Subscription ID |
| 56 | +$SubscriptionID = "<SubscriptionID>" |
| 57 | +# Enter your Managed Instance name – example "sqlmi1" |
| 58 | +$ManagedInstanceName = "<ManagedInstanceName>" |
| 59 | +# Enter the Distributed Availability Group name |
| 60 | +$DAGName = "<DAGName>" |
| 61 | +
|
| 62 | +# ==================================================================================== |
| 63 | +# INVOKING THE API CALL -- THIS PART IS NOT USER CONFIGURABLE |
| 64 | +# ==================================================================================== |
| 65 | +# Log in and select subscription if needed |
| 66 | +if ((Get-AzContext ) -eq $null) |
| 67 | +{ |
| 68 | + echo "Logging to Azure subscription" |
| 69 | + Login-AzAccount |
| 70 | +} |
| 71 | +Select-AzSubscription -SubscriptionName $SubscriptionID |
| 72 | +
|
| 73 | +# Build URI for the API call |
| 74 | +# |
| 75 | +$miRG = (Get-AzSqlInstance -InstanceName $ManagedInstanceName).ResourceGroupName |
| 76 | +$uriFull = "https://management.azure.com/subscriptions/" + $SubscriptionID + "/resourceGroups/" + $miRG+ "/providers/Microsoft.Sql/managedInstances/" + $ManagedInstanceName + "/distributedAvailabilityGroups/" + $DAGName + "?api-version=2021-05-01-preview" |
| 77 | +echo $uriFull |
| 78 | +
|
| 79 | +# Build API request body |
| 80 | +# |
| 81 | +
|
| 82 | +$bodyFull = @" |
| 83 | +{ |
| 84 | + "properties":{ |
| 85 | + "ReplicationMode":"sync" |
| 86 | + } |
| 87 | +}"@ |
| 88 | +
|
| 89 | +echo $bodyFull |
| 90 | +
|
| 91 | +# Get auth token and build the header |
| 92 | +# |
| 93 | +$azProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile |
| 94 | +$currentAzureContext = Get-AzContext |
| 95 | +$profileClient = New-Object Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient($azProfile) |
| 96 | +$token = $profileClient.AcquireAccessToken($currentAzureContext.Tenant.TenantId) |
| 97 | +$authToken = $token.AccessToken |
| 98 | +$headers = @{} |
| 99 | +$headers.Add("Authorization", "Bearer "+"$authToken") |
| 100 | +
|
| 101 | +# Invoke API call |
| 102 | +# |
| 103 | +echo "Invoking API call switch Async-Sync replication mode on Managed Instance" |
| 104 | +Invoke-WebRequest -Method PATCH -Headers $headers -Uri $uriFull -ContentType "application/json" -Body $bodyFull |
| 105 | +``` |
| 106 | + |
| 107 | +## Switch replication mode on SQL Server |
| 108 | + |
| 109 | +Use the following T-SQL script to change the replication mode of Distributed Availability Group on SQL Server from async to sync. Replace `<DAGName>` with the name of Distributed Availability Group, and replace `<AGName>` with the name of Availability Group created on SQL Server. In addition, replace `<ManagedInstanceName>` with the name of your SQL Managed Instance. |
| 110 | +With this step, the migration of the database from SQL Server to SQL Managed Instance is completed. |
| 111 | + |
| 112 | +```sql |
| 113 | +-- Sets the Distributed Availability Group to synchronous commit. |
| 114 | +-- ManagedInstanceName example 'sqlmi1' |
| 115 | +USE master |
| 116 | +GO |
| 117 | +ALTER AVAILABILITY GROUP [<DAGName>] |
| 118 | +MODIFY |
| 119 | +AVAILABILITY GROUP ON |
| 120 | + '<AGName>' WITH |
| 121 | + (AVAILABILITY_MODE = SYNCHRONOUS_COMMIT), |
| 122 | + '<ManagedInstanceName>' WITH |
| 123 | + (AVAILABILITY_MODE = SYNCHRONOUS_COMMIT); |
| 124 | +``` |
| 125 | + |
| 126 | +To validate change of the link replication, execute the following DMV, and expected results are shown below. They're indicating SYNCHRONOUS_COMIT state. |
| 127 | + |
| 128 | +```sql |
| 129 | +-- Verifies the state of the distributed availability group |
| 130 | +SELECT |
| 131 | + ag.name, ag.is_distributed, ar.replica_server_name, |
| 132 | + ar.availability_mode_desc, ars.connected_state_desc, ars.role_desc, |
| 133 | + ars.operational_state_desc, ars.synchronization_health_desc |
| 134 | +FROM |
| 135 | + sys.availability_groups ag |
| 136 | + join sys.availability_replicas ar |
| 137 | + on ag.group_id=ar.group_id |
| 138 | + left join sys.dm_hadr_availability_replica_states ars |
| 139 | + on ars.replica_id=ar.replica_id |
| 140 | +WHERE |
| 141 | + ag.is_distributed=1 |
| 142 | +``` |
| 143 | + |
| 144 | +With both SQL Managed Instance, and SQL Server being switched to Sync mode, the replication between the two entities is now synchronous. If you require to reverse this state, follow the same steps and set async state for both SQL Server and SQL Managed Instance. |
| 145 | + |
| 146 | +## Check LSN values on both SQL Server and Managed Instance |
| 147 | + |
| 148 | +To complete the migration, we need to ensure that the replication has completed. For this, you need to ensure that LSNs (Log Sequence Numbers) indicating the log records written for both SQL Server and SQL Managed Instance are the same. Initially, it's expected that SQL Server LSN will be higher than LSN number on SQL Managed Instance. The difference is caused by the fact that SQL Managed Instance might be lagging somewhat behind the primary SQL Server due to network latency. After some time, LSNs on SQL Managed Instance and SQL Server should match and stop changing, as the workload on SQL Server should be stopped. |
| 149 | + |
| 150 | +Use the following T-SQL query on SQL Server to read the LSN number of the last recorded transaction log. Replace `<DatabaseName>` with your database name and look for the last hardened LSN number, as shown below. |
| 151 | + |
| 152 | +```sql |
| 153 | +-- Obtain last hardened LSN for a database on SQL Server. |
| 154 | +SELECT |
| 155 | + ag.name AS [Replication group], |
| 156 | + db.name AS [Database name], |
| 157 | + drs.database_id AS [Database ID], |
| 158 | + drs.group_id, |
| 159 | + drs.replica_id, |
| 160 | + drs.synchronization_state_desc AS [Sync state], |
| 161 | + drs.end_of_log_lsn AS [End of log LSN], |
| 162 | + drs.last_hardened_lsn AS [Last hardened LSN] |
| 163 | +FROM |
| 164 | + sys.dm_hadr_database_replica_states drs |
| 165 | + inner join sys.databases db on db.database_id = drs.database_id |
| 166 | + inner join sys.availability_groups ag on drs.group_id = ag.group_id |
| 167 | +WHERE |
| 168 | + ag.is_distributed = 1 and db.name = '<DatabaseName>' |
| 169 | +``` |
| 170 | + |
| 171 | +Use the following T-SQL query on SQL Managed Instance to read the LSN number of the last hardened LSN number for your database. Replace `<DatabaseName>` with your database name. |
| 172 | + |
| 173 | +Query shown below will work on General Purpose SQL Managed Instance. For Business Critical Managed Instance, you will need to uncomment `and drs.is_primary_replica = 1` at the end of the script. On Business Critical, this filter will make sure that only primary replica details are read. |
| 174 | + |
| 175 | +```sql |
| 176 | +-- Obtain LSN for a database on SQL Managed Instance. |
| 177 | +SELECT |
| 178 | + db.name AS [Database name], |
| 179 | + drs.database_id AS [Database ID], |
| 180 | + drs.group_id, |
| 181 | + drs.replica_id, |
| 182 | + drs.synchronization_state_desc AS [Sync state], |
| 183 | + drs.end_of_log_lsn AS [End of log LSN], |
| 184 | + drs.last_hardened_lsn AS [Last hardened LSN] |
| 185 | +FROM |
| 186 | + sys.dm_hadr_database_replica_states drs |
| 187 | + inner join sys.databases db on db.database_id = drs.database_id |
| 188 | +WHERE |
| 189 | + db.name = '<DatabaseName>' |
| 190 | + -- for BC add the following as well |
| 191 | + -- AND drs.is_primary_replica = 1 |
| 192 | +``` |
| 193 | + |
| 194 | +Verify once again that your workload is stopped on SQL Server. Check that LSNs on both SQL Server and SQL Managed Instance match, and that they remain matched and unchanged for some time. Stable LSN numbers on both ends indicate that tail log has been replicated to SQL Managed Instance and workload is effectively stopped. Proceed to the next step to initiate database failover and migration to Azure. |
| 195 | + |
| 196 | +## Initiate database failover and migration to Azure |
| 197 | + |
| 198 | +SQL Managed Instance link database failover and migration to Azure is accomplished by invoking REST API call. This will close the link and complete the replication on SQL Managed Instance. Replicated database will become read-write on SQL Managed Instance. |
| 199 | + |
| 200 | +Use the following API to initiate database failover to Azure. Replace `<YourSubscriptionID>` with your actual Azure subscription ID. Replace `<RG>` with the resource group where your SQL Managed Instance is deployed and replace `<ManagedInstanceName>` with the name of our SQL Managed Instance. In addition, replace `<DAGName>` with the name of Distributed Availability Group made on SQL Server. |
| 201 | + |
| 202 | +```PowerShell |
| 203 | +# ==================================================================================== |
| 204 | +# POWERSHELL SCRIPT TO FAILOVER AND MIGRATE DATABASE WITH SQL MANAGED INSTANCE LINK |
| 205 | +# USER CONFIGURABLE VALUES |
| 206 | +# (C) 2021-2022 SQL Managed Instance product group |
| 207 | +# ==================================================================================== |
| 208 | +# Enter your Azure Subscription ID |
| 209 | +$SubscriptionID = "<SubscriptionID>" |
| 210 | +# Enter your Managed Instance name – example "sqlmi1" |
| 211 | +$ManagedInstanceName = "<ManagedInstanceName>" |
| 212 | +# Enter the Distributed Availability Group link name |
| 213 | +$DAGName = "<DAGName>" |
| 214 | +
|
| 215 | +# ==================================================================================== |
| 216 | +# INVOKING THE API CALL -- THIS PART IS NOT USER CONFIGURABLE. |
| 217 | +# ==================================================================================== |
| 218 | +# Log in and select subscription if needed |
| 219 | +if ((Get-AzContext ) -eq $null) |
| 220 | +{ |
| 221 | + echo "Logging to Azure subscription" |
| 222 | + Login-AzAccount |
| 223 | +} |
| 224 | +Select-AzSubscription -SubscriptionName $SubscriptionID |
| 225 | +
|
| 226 | +# Build URI for the API call |
| 227 | +# |
| 228 | +$miRG = (Get-AzSqlInstance -InstanceName $ManagedInstanceName).ResourceGroupName |
| 229 | +$uriFull = "https://management.azure.com/subscriptions/" + $SubscriptionID + "/resourceGroups/" + $miRG+ "/providers/Microsoft.Sql/managedInstances/" + $ManagedInstanceName + "/distributedAvailabilityGroups/" + $DAGName + "?api-version=2021-05-01-preview" |
| 230 | +echo $uriFull |
| 231 | +
|
| 232 | +# Get auth token and build the header |
| 233 | +# |
| 234 | +$azProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile |
| 235 | +$currentAzureContext = Get-AzContext |
| 236 | +$profileClient = New-Object Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient($azProfile) |
| 237 | +$token = $profileClient.AcquireAccessToken($currentAzureContext.Tenant.TenantId) |
| 238 | +$authToken = $token.AccessToken |
| 239 | +$headers = @{} |
| 240 | +$headers.Add("Authorization", "Bearer "+"$authToken") |
| 241 | +
|
| 242 | +# Invoke API call |
| 243 | +# |
| 244 | +Invoke-WebRequest -Method DELETE -Headers $headers -Uri $uriFull -ContentType "application/json" |
| 245 | +``` |
| 246 | + |
| 247 | +## Cleanup Availability Group and Distributed Availability Group on SQL Server |
| 248 | + |
| 249 | +After breaking the link and migrating database to Azure SQL Managed Instance, consider cleaning up Availability Group and Distributed Availability Group on SQL Server if they aren't used otherwise. |
| 250 | +Replace `<DAGName>` with the name of the Distributed Availability Group on SQL Server and replace `<AGName>` with Availability Group name on the SQL Server. |
| 251 | + |
| 252 | +``` sql |
| 253 | +DROP AVAILABILITY GROUP <DAGName> |
| 254 | +GO |
| 255 | +DROP AVAILABILITY GROUP <AGName> |
| 256 | +GO |
| 257 | +``` |
| 258 | + |
| 259 | +With this step, the migration of the database from SQL Server to Managed Instance has been completed. |
| 260 | + |
| 261 | +## Next steps |
| 262 | + |
| 263 | +For more information on the link feature, see the following resources: |
| 264 | + |
| 265 | +- [Managed Instance link – connecting SQL Server to Azure reimagined](https://aka.ms/mi-link-techblog). |
| 266 | +- [Prepare for SQL Managed Instance link](./managed-instance-link-preparation.md). |
| 267 | +- [Use SQL Managed Instance link with scripts to replicate database](./managed-instance-link-use-scripts-to-replicate-database.md). |
| 268 | +- [Use SQL Managed Instance link via SSMS to replicate database](./managed-instance-link-use-ssms-to-replicate-database.md). |
| 269 | +- [Use SQL Managed Instance link via SSMS to migrate database](./managed-instance-link-use-ssms-to-failover-database.md). |
0 commit comments