Перенос MySQL в Базу данных Azure для MySQL в автономном режиме с помощью PowerShell и Azure Database Migration Service

В этой статье вы перенесете базу данных MySQL, восстановленную в локальном экземпляре, в Базу данных Azure для MySQL, используя возможность автономной миграции Azure Database Migration Service с помощью Microsoft Azure PowerShell. В этой статье описывается коллекция скриптов PowerShell, которые можно выполнять последовательно для автономной миграции базы данных MySQL в Azure. Полный скрипт PowerShell, описанный в этом учебнике, можно загрузить из нашего репозитория GitHub.

Примечание

В настоящее время выполнить полную миграцию базы данных с помощью модуля Az.DataMigration невозможно. В то же время пример скрипта PowerShell предоставляется на условиях "как есть", использует DMS REST API и позволяет автоматизировать миграцию. Этот скрипт будет изменен или переведен в категорию нерекомендуемых после добавления официальной поддержки в модуль Az.DataMigration и Azure CLI.

Примечание

Служба реляционной базы данных Amazon (RDS) для MySQL и Amazon Aurora (на основе MySQL) также поддерживаются в качестве источников для миграции.

Важно!

Для интерактивной миграции также можно использовать средства с открытым кодом, например MyDumper/MyLoader с репликацией входных данных.

Эта статья поможет автоматизировать миграцию в сценариях, когда имена исходной и целевой баз данных могут быть одинаковыми или разными и в процессе миграции все или несколько таблиц в целевой базе данных должны быть перенесены с теми же именами и структурами таблиц. Хотя в статьях предполагается, что источником является экземпляр базы данных MySQL, а целевым объектом — База данных Azure для MySQL, эти инструкции можно использовать для миграции из одной Базы данных Azure для MySQL в другую, просто изменив имя исходного сервера и учетные данные. Кроме того, поддерживается миграция с серверов MySQL более ранних версий (версия 5.6 и выше) в более поздние.

Важно!

Предварительные версии функций DMS доступны на уровне самообслуживания. Предварительные версии предоставляются "как есть" и "при наличии". На них не распространяются соглашения об уровне обслуживания и ограниченная гарантия. Следовательно, эти функции не предназначены для использования в рабочей среде. Дополнительные сведения см. в статье Дополнительные условия использования Предварительных версий Microsoft Azure.

Вы узнаете, как выполнять следующие задачи:

  • Миграция схемы базы данных.
  • Создайте группу ресурсов.
  • создание экземпляра Azure Database Migration Service;
  • создание проекта миграции в экземпляре Azure Database Migration Service;
  • Настройка проекта миграции для использования возможности автономной миграции для MySQL.
  • выполнение миграции.

Предварительные требования

Для выполнения этих действий вам потребуется следующее:

  • Подготовьте учетную запись Azure с активной подпиской. Создайте учетную запись бесплатно.

  • У вас должна быть локальная база данных MySQL с версией 5.6 или более поздней. Если ее нет, скачайте и установите MySQL Community Edition версии 5.6 или более поздней.

  • Создайте экземпляр в Базе данных Azure для MySQL. Ознакомьтесь со статьей Подключение и запрос данных с помощью MySQL Workbench, чтобы узнать, как подключить и создать базу данных с помощью приложения Workbench. Версия Базы данных Azure для MySQL должна быть не ниже, чем версия локальной базы данных MySQL. Например, MySQL версии 5.7 можно перенести в Базу данных Azure для MySQL версии 5.7 или 8.

  • Создайте виртуальную сеть Microsoft Azure для Azure Database Migration Service с помощью модели развертывания Azure Resource Manager, которая обеспечивает подключение "сеть — сеть" к локальным исходным серверам с помощью ExpressRoute или VPN. Дополнительные сведения о создании виртуальной сети приведены в документации по виртуальным сетям. В частности, уделите внимание кратким руководствам с пошаговыми инструкциями.

    Примечание

    Если вы используете ExpressRoute с пиринговым подключением к сети, управляемой Майкрософт, во время настройки виртуальной сети добавьте в подсеть, в которой будет подготовлена служба, конечную точку службы Microsoft.Sql. Такая конфигурация вызвана тем, что у Azure Database Migration Service нет подключения к Интернету.

  • Убедитесь, что правила группы безопасности сети для виртуальной сети не блокируют исходящий порт 443 ServiceTag для службы хранилища и Azure Monitor. См. дополнительные сведения о фильтрации трафика, предназначенного для виртуальной сети, с помощью групп безопасности сети.

  • Откройте брандмауэр Windows, чтобы разрешить подключения из виртуальной сети для Azure Database Migration Service для доступа к исходному серверу MySQL Server. По умолчанию это TCP-порт 3306.

  • Если перед исходными базами данных развернуто устройство брандмауэра, может понадобиться добавить правила брандмауэра, чтобы разрешить подключения из виртуальной сети для службы Azure Database Migration Service для доступа к исходным базам данных для выполнения миграции.

  • Создайте правило брандмауэра уровня сервера или настройте конечные точки службы виртуальной сети для целевой Базы данных Azure для MySQL, чтобы предоставить виртуальной сети службы Azure Database Migration Service доступ к целевым базам данных.

  • Исходный экземпляр MySQL должен находиться в поддерживаемой версии MySQL Community Edition. Чтобы определить версию экземпляра MySQL, в служебной программе MySQL или MySQL Workbench выполните следующую команду:

    SELECT @@version;
    
  • База данных Azure для MySQL поддерживает только таблицы InnoDB. Чтобы преобразовать таблицы MyISAM в InnoDB, ознакомьтесь со сведениями на странице о преобразовании таблиц.

  • Пользователь должен иметь права доступа для чтения данных в базе данных — источнике.

  • В этом руководстве используется PowerShell версии 7.1 с PSEdition Core, который можно установить в соответствии с руководством по установке.

  • Скачайте и установите следующие модули из коллекции PowerShell с помощью командлета установки модулей PowerShell. Откройте командное окно PowerShell от имени администратора:

    • Az.Resources
    • Az.Network
    • Az.DataMigration
Install-Module Az.Resources
Install-Module Az.Network
Install-Module Az.DataMigration
Import-Module Az.Resources
Import-Module Az.Network
Import-Module Az.DataMigration

Миграция схемы базы данных

Чтобы перенести все объекты базы данных, такие как схемы таблицы, индексы и хранимые процедуры, нам нужно извлечь схему из базы данных — источника и применить ее к целевой базе данных. Чтобы извлечь схему, можно использовать mysqldump с параметром --no-data. Для этого вам потребуется компьютер, который может подключаться как к исходной базе данных MySQL, так и к целевой Базе данных Azure для MySQL.

Чтобы экспортировать схему с помощью mysqldump, выполните следующую команду:

mysqldump -h [servername] -u [username] -p[password] --databases [db name] --no-data > [schema file path]

Пример:

mysqldump -h 10.10.123.123 -u root -p --databases migtestdb --no-data > d:\migtestdb.sql

Чтобы импортировать схему в целевую Базу данных Azure для MySQL, выполните следующую команду:

mysql.exe -h [servername] -u [username] -p[password] [database]< [schema file path]

Пример:

mysql.exe -h mysqlsstrgt.mysql.database.azure.com -u docadmin@mysqlsstrgt -p migtestdb < d:\migtestdb.sql

При наличии внешних ключей в схеме загрузка параллельных данных во время миграции будет обрабатываться задачей миграции. Удаление внешних ключей при миграции схемы не требуется.

Если у вас есть триггеры в базе данных, они будут обеспечивать целостность данных в целевом объекте до полного переноса данных из источника. Рекомендуется отключить триггеры во всех таблицах целевого объекта во время миграции, а затем включить их после завершения миграции.

Выполните следующий скрипт в MySQL Workbench в целевой базе данных, чтобы извлечь скрипт удаления триггера и скрипт добавления триггера.

SELECT
    SchemaName,
    GROUP_CONCAT(DropQuery SEPARATOR ';\n') as DropQuery,
    Concat('DELIMITER $$ \n\n', GROUP_CONCAT(AddQuery SEPARATOR '$$\n'), '$$\n\nDELIMITER ;') as AddQuery
FROM
(
SELECT 
    TRIGGER_SCHEMA as SchemaName,
    Concat('DROP TRIGGER `', TRIGGER_NAME, "`") as DropQuery,
    Concat('CREATE TRIGGER `', TRIGGER_NAME, '` ', ACTION_TIMING, ' ', EVENT_MANIPULATION, 
            '\nON `', EVENT_OBJECT_TABLE, '`\n' , 'FOR EACH ', ACTION_ORIENTATION, ' ',
            ACTION_STATEMENT) as AddQuery
FROM  
    INFORMATION_SCHEMA.TRIGGERS
ORDER BY EVENT_OBJECT_SCHEMA, EVENT_OBJECT_TABLE, ACTION_TIMING, EVENT_MANIPULATION, ACTION_ORDER ASC
) AS Queries
GROUP BY SchemaName

Выполните созданный запрос на удаление триггера (столбец DropQuery) в результатах, чтобы удалить триггеры в целевой базе данных. Запрос на добавление триггера можно сохранить, чтобы использовать после завершения переноса данных.

Вход в подписку Microsoft Azure

Используйте команду PowerShell Connect-AzAccount, чтобы войти в подписку Azure с помощью PowerShell, согласно инструкциям в статье Вход в систему с помощью Azure PowerShell.

Следующий скрипт задает подписку по умолчанию для сеанса PowerShell после входа и создает вспомогательную функцию ведения журнала для форматированных журналов консоли.

[string] $SubscriptionName = "mySubscription"
$ErrorActionPreference = "Stop";

Connect-AzAccount
Set-AzContext -Subscription $SubscriptionName
$global:currentSubscriptionId = (Get-AzContext).Subscription.Id;

function LogMessage([string] $Message, [bool] $IsProcessing = $false) {
    if ($IsProcessing) {
        Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss"): $Message" -ForegroundColor Yellow
    }
    else {
        Write-Host "$(Get-Date -Format "yyyy-MM-dd HH:mm:ss"): $Message" -ForegroundColor Green
    }    
}

Регистрация поставщика ресурсов Microsoft.DataMigration

Регистрация поставщика ресурсов должна выполняться в каждой подписке Azure только один раз. Без регистрации вы не сможете создать экземпляр Azure Database Migration Service.

Зарегистрируйте поставщик ресурсов с помощью команды Register-AzResourceProvider. Следующий скрипт регистрирует поставщик ресурсов, необходимый для Azure Database Migration Service

Register-AzResourceProvider -ProviderNamespace Microsoft.DataMigration

Создание группы ресурсов

Группа ресурсов Azure является логическим контейнером, в котором происходит развертывание ресурсов Azure и управление ими. Перед созданием ресурсов DMS создайте группу ресурсов.

Создайте группу ресурсов с помощью команды New-AzResourceGroup.

В следующем примере создается группа ресурсов с именем myResourceGroup в регионе Западная часть США 2 в подписке по умолчанию mySubscription.

# Get the details of resource group
[string] $Location = "westus2"
[string] $ResourceGroupName = "myResourceGroup"

$resourceGroup = Get-AzResourceGroup -Name $ResourceGroupName
if (-not($resourceGroup)) {
    LogMessage -Message "Creating resource group $ResourceGroupName..." -IsProcessing $true
    $resourceGroup = New-AzResourceGroup -Name $ResourceGroupName -Location $Location
    LogMessage -Message "Created resource group - $($resourceGroup.ResourceId)."
}
else { LogMessage -Message "Resource group $ResourceGroupName exists." }

Создание экземпляра Azure Database Migration Service

Вы можете создать экземпляр Azure Database Migration Service, выполнив команду New-AzDataMigrationService. Для этой команды нужно передать следующие обязательные параметры:

  • ResourceGroupName. Вы можете выполнить команду New-AzResourceGroup, чтобы создать группу ресурсов Azure, как описано в предыдущем разделе, и указать ее имя в качестве параметра.
  • ServiceName. Строка, соответствующая требуемому уникальному имени службы для Azure Database Migration Service.
  • Расположение. Указывает расположение службы. Укажите расположение центра обработки данных Azure, например западная часть США или Юго-Восточная Азия.
  • Sku. Этот параметр соответствует имени SKU DMS. В настоящее время поддерживаются следующие имена SKU: Standard_1vCore, Standard_2vCores, Standard_4vCores, Premium_4vCores.
  • VirtualSubnetId. Для получения сведений о подсети можно использовать команду Get-AzVirtualNetworkSubnetConfig.

Следующий скрипт ожидает, что виртуальная сеть myVirtualNetwork существует в подсети с именем по умолчанию, а затем создает Database Migration Service с именем myDmService в группе ресурсов, созданной на шаге 3, в том же регионе.

# Get a reference to the DMS service - Create if not exists
[string] $VirtualNetworkName = "myVirtualNetwork"
[string] $SubnetName = "default"
[string] $ServiceName = "myDmService"

$dmsServiceResourceId = "/subscriptions/$($global:currentSubscriptionId)/resourceGroups/$ResourceGroupName/providers/Microsoft.DataMigration/services/$ServiceName"
$dmsService = Get-AzResource -ResourceId $dmsServiceResourceId -ErrorAction SilentlyContinue

# Create Azure DMS service if not existing
# Possible values for SKU currently are Standard_1vCore,Standard_2vCores,Standard_4vCores,Premium_4vCores
if (-not($dmsService)) {   
    $virtualNetwork = Get-AzVirtualNetwork -ResourceGroupName $ResourceGroupName -Name $VirtualNetworkName
    if (-not ($virtualNetwork)) { throw "ERROR: Virtual Network $VirtualNetworkName does not exists" }

    $subnet = Get-AzVirtualNetworkSubnetConfig -VirtualNetwork $virtualNetwork -Name $SubnetName
    if (-not ($subnet)) { throw "ERROR: Virtual Network $VirtualNetworkName does not contains Subnet $SubnetName" }

    LogMessage -Message "Creating Azure Data Migration Service $ServiceName..." -IsProcessing $true
    $dmsService = New-AzDataMigrationService `
        -ResourceGroupName $ResourceGroupName `
        -Name $ServiceName `
        -Location $resourceGroup.Location `
        -Sku Premium_4vCores `
        -VirtualSubnetId $Subnet.Id
    
    $dmsService = Get-AzResource -ResourceId $dmsServiceResourceId
    LogMessage -Message "Created Azure Data Migration Service - $($dmsService.ResourceId)."
}
else { LogMessage -Message "Azure Data Migration Service $ServiceName exists." }

Создание проекта миграции

Создав экземпляр Azure Database Migration Service, создайте проект миграции. Проект миграции определяет тип миграции, который необходимо выполнить.

Следующий скрипт создает проект миграции с именем myfirstmysqlofflineproject для автономной миграции из MySQL в Базу данных Azure для MySQL в экземпляре Database Migration Service, созданном на шаге 4, в том же регионе.

# Get a reference to the DMS project - Create if not exists
[string] $ProjectName = "myfirstmysqlofflineproject"

$dmsProjectResourceId = "/subscriptions/$($global:currentSubscriptionId)/resourceGroups/$($dmsService.ResourceGroupName)/providers/Microsoft.DataMigration/services/$($dmsService.Name)/projects/$projectName"
$dmsProject = Get-AzResource -ResourceId $dmsProjectResourceId -ErrorAction SilentlyContinue

# Create Azure DMS Project if not existing
if (-not($dmsProject)) {
    LogMessage -Message "Creating Azure DMS project $projectName for MySQL migration ..." -IsProcessing $true

    $newProjectProperties = @{"sourcePlatform" = "MySQL"; "targetPlatform" = "AzureDbForMySQL" }
    $dmsProject = New-AzResource `
        -ApiVersion 2018-03-31-preview `
        -Location $dmsService.Location `
        -ResourceId $dmsProjectResourceId `
        -Properties $newProjectProperties `
        -Force

    LogMessage -Message "Created Azure DMS project $projectName - $($dmsProject.ResourceId)."
}
else { LogMessage -Message "Azure DMS project $projectName exists." }

Создание объекта сведений о подключении к базе данных для исходных и целевых подключений

После создания проекта миграции будут созданы сведения о подключении к базе данных. Эти сведения о подключении будут использоваться для подключения к исходным и целевым серверам в процессе миграции.

Следующий скрипт принимает имя сервера, имя пользователя и пароль для исходного и целевого экземпляров MySQL и создает объекты сведений о подключении. Скрипт предлагает пользователю ввести пароль для исходного и целевого экземпляров MySQL. Для автоматических скриптов учетные данные можно получить из Azure Key Vault.

# Initialize the source and target database server connections
[string] $SourceServerName = "13.66.136.192"
[string] $SourceUserName = "docadmin@mysqlserver"
[securestring] $SourcePassword = Read-Host "Enter MySQL Source Server Password" -AsSecureString

[string] $TargetServerName = "migdocdevwus2mysqlsstrgt.mysql.database.azure.com"
[string] $TargetUserName = "docadmin@migdocdevwus2mysqlsstrgt"
[securestring] $TargetPassword = Read-Host "Enter MySQL Target Server Password" -AsSecureString

function InitConnection(
    [string] $ServerName,
    [string] $UserName,
    [securestring] $Password) {
    $connectionInfo = @{
        "dataSource"             = "";
        "serverName"             = "";
        "port"                   = 3306;
        "userName"               = "";
        "password"               = "";
        "authentication"         = "SqlAuthentication";
        "encryptConnection"      = $true;
        "trustServerCertificate" = $true;
        "additionalSettings"     = "";
        "type"                   = "MySqlConnectionInfo" 
    }

    $connectionInfo.dataSource = $ServerName;
    $connectionInfo.serverName = $ServerName;
    $connectionInfo.userName = $UserName;
    $connectionInfo.password = (ConvertFrom-SecureString -AsPlainText $password).ToString();
    $connectionInfo;
}

# Initialize the source and target connections
LogMessage -Message "Initializing source and target connection objects ..." -IsProcessing $true
$sourceConnInfo = InitConnection `
    $SourceServerName `
    $SourceUserName `
    $SourcePassword;

$targetConnInfo = InitConnection `
    $TargetServerName `
    $TargetUserName `
    $TargetPassword;

LogMessage -Message "Source and target connection object initialization complete."

Извлечение списка имен таблиц из целевой базы данных

Список таблиц базы данных можно извлечь с помощью задачи миграции и сведений о подключении. Список таблиц будет извлечен из исходной и целевой баз данных, чтобы можно было выполнить правильное сопоставление и проверку.

Следующий скрипт принимает имена исходной и целевой баз данных, а затем извлекает список таблиц из баз данных с помощью задачи миграции GetUserTablesMySql.

# Run scenario to get the tables from the target database to build
# the migration table mapping
[string] $TargetDatabaseName = "migtargetdb"
[string] $SourceDatabaseName = "migsourcedb"

function RunScenario([object] $MigrationService, 
    [object] $MigrationProject, 
    [string] $ScenarioTaskName, 
    [object] $TaskProperties, 
    [bool] $WaitForScenario = $true) {
    # Check if the scenario task already exists, if so remove it
    LogMessage -Message "Removing scenario if already exists..." -IsProcessing $true
    Remove-AzDataMigrationTask `
        -ResourceGroupName $MigrationService.ResourceGroupName `
        -ServiceName $MigrationService.Name `
        -ProjectName $MigrationProject.Name `
        -TaskName $ScenarioTaskName `
        -Force;

    # Start the new scenario task using the provided properties
    LogMessage -Message "Initializing scenario..." -IsProcessing $true
    New-AzResource `
        -ApiVersion 2018-03-31-preview `
        -Location $MigrationService.Location `
        -ResourceId "/subscriptions/$($global:currentSubscriptionId)/resourceGroups/$($MigrationService.ResourceGroupName)/providers/Microsoft.DataMigration/services/$($MigrationService.Name)/projects/$($MigrationProject.Name)/tasks/$($ScenarioTaskName)" `
        -Properties $TaskProperties `
        -Force | Out-Null;
    
    LogMessage -Message "Waiting for $ScenarioTaskName scenario to complete..." -IsProcessing $true
    if ($WaitForScenario) {
        $progressCounter = 0;
        do {
            if ($null -ne $scenarioTask) {
                Start-Sleep 10;
            }

            # Get calls can time out and will return a cancellation exception in that case
            $scenarioTask = Get-AzDataMigrationTask `
                -ResourceGroupName $MigrationService.ResourceGroupName `
                -ServiceName $MigrationService.Name `
                -ProjectName $MigrationProject.Name `
                -TaskName $ScenarioTaskName `
                -Expand `
                -ErrorAction Ignore;

            Write-Progress -Activity "Scenario Run $ScenarioTaskName  (Marquee Progress Bar)" `
                -Status $scenarioTask.ProjectTask.Properties.State `
                -PercentComplete $progressCounter
            
            $progressCounter += 10;
            if ($progressCounter -gt 100) { $progressCounter = 10 }
        }
        while (($null -eq $scenarioTask) -or ($scenarioTask.ProjectTask.Properties.State -eq "Running") -or ($scenarioTask.ProjectTask.Properties.State -eq "Queued"))
    }
    Write-Progress -Activity "Scenario Run $ScenarioTaskName" `
        -Status $scenarioTask.ProjectTask.Properties.State `
        -Completed
                 
    # Now get it using REST APIs so we can expand the output  
    LogMessage -Message "Getting expanded task results ..." -IsProcessing $true  
    $psToken = (Get-AzAccessToken -ResourceUrl https://management.azure.com).Token;
    $token = ConvertTo-SecureString -String $psToken -AsPlainText -Force;
    $taskResource = Invoke-RestMethod `
        -Method GET `
        -Uri "https://management.azure.com$($scenarioTask.ProjectTask.Id)?api-version=2018-03-31-preview&`$expand=output" `
        -ContentType "application/json" `
        -Authentication Bearer `
        -Token $token;
    
    $taskResource.properties;
}

# create the get table task properties by initializing the connection and 
# database name
$getTablesTaskProperties = @{
    "input"    = @{
        "connectionInfo"    = $null;
        "selectedDatabases" = $null;
    };
    "taskType" = "GetUserTablesMySql";
};

LogMessage -Message "Running scenario to get the list of tables from the target database..." -IsProcessing $true
$getTablesTaskProperties.input.connectionInfo = $targetConnInfo;
$getTablesTaskProperties.input.selectedDatabases = @($TargetDatabaseName);
# Create a name for the task
$getTableTaskName = "$($TargetDatabaseName)GetUserTables"
# Get the list of tables from the source
$getTargetTablesTask = RunScenario -MigrationService $dmsService `
    -MigrationProject $dmsProject `
    -ScenarioTaskName $getTableTaskName `
    -TaskProperties $getTablesTaskProperties;

if (-not ($getTargetTablesTask)) { throw "ERROR: Could not get target database $TargetDatabaseName table information." }
LogMessage -Message "List of tables from the target database acquired."

LogMessage -Message "Running scenario to get the list of tables from the source database..." -IsProcessing $true
$getTablesTaskProperties.input.connectionInfo = $sourceConnInfo;
$getTablesTaskProperties.input.selectedDatabases = @($SourceDatabaseName);
# Create a name for the task
$getTableTaskName = "$($SourceDatabaseName)GetUserTables"
# Get the list of tables from the source
$getSourceTablesTask = RunScenario -MigrationService $dmsService `
    -MigrationProject $dmsProject `
    -ScenarioTaskName $getTableTaskName `
    -TaskProperties $getTablesTaskProperties;

if (-not ($getSourceTablesTask)) { throw "ERROR: Could not get source database $SourceDatabaseName table information." }
LogMessage -Message "List of tables from the source database acquired."

Создание сопоставления таблиц на основе пользовательской конфигурации

В рамках настройки задачи миграции будет создано сопоставление между исходной и целевой таблицами. Сопоставление выполняется на уровне имени таблицы, но предполагается, что структура таблицы (количество столбцов, имена столбцов, типы данных и т. д.) для сопоставленных таблиц совпадают.

Следующий скрипт создает сопоставление на основе списка целевых и исходных таблиц, извлеченных на шаге 7. Для частичной загрузки данных пользователь может предоставить список таблиц для фильтрации. Если пользователь не указывает никакие данные, сопоставляются все целевые таблицы. Скрипт также проверяет, существует ли в источнике таблица с тем же именем. Если имя таблицы не существует в источнике, целевая таблица игнорируется и не переносится.

# Create the source to target table map
# Optional table settings
# DEFAULT: $IncludeTables = $null => include all tables for migration
# DEFAULT: $ExcludeTables = $null => exclude no tables from migration
# Exclude list has higher priority than include list
# Array of qualified source table names which should be migrated
[string[]] $IncludeTables = @("migsourcedb.coupons", "migsourcedb.daily_cash_sheets");
[string[]] $ExcludeTables = $null;

LogMessage -Message "Creating the table map based on the user input and database table information ..." `
    -IsProcessing $true

$targetTables = $getTargetTablesTask.Output.DatabasesToTables."$TargetDatabaseName";
$sourceTables = $getSourceTablesTask.Output.DatabasesToTables."$SourceDatabaseName";
$tableMap = New-Object 'system.collections.generic.dictionary[string,string]';

$schemaPrefixLength = $($SourceDatabaseName + ".").Length;
$tableMappingError = $false
foreach ($srcTable in $sourceTables) {
    # Removing the database name prefix from the table name so that comparison
    # can be done in cases where database name given are different
    $tableName = $srcTable.Name.Substring($schemaPrefixLength, `
            $srcTable.Name.Length - $schemaPrefixLength)

    # In case the table is part of exclusion list then ignore the table
    if ($null -ne $ExcludeTables -and $ExcludeTables -contains $srcTable.Name) {
        continue;
    }

    # Either the include list is null or the table is part of the include list then add it in the mapping
    if ($null -eq $IncludeTables -or $IncludeTables -contains $srcTable.Name) {
        # Check if the table exists in the target. If not then log TABLE MAPPING ERROR
        if (-not ($targetTables | Where-Object { $_.name -ieq "$($TargetDatabaseName).$tableName" })) {
            $tableMappingError = $true
            Write-Host "TABLE MAPPING ERROR: $($targetTables.name) does not exists in target." -ForegroundColor Red
            continue;
        }  

        $tableMap.Add("$($SourceDatabaseName).$tableName", "$($TargetDatabaseName).$tableName");
    }     
}

# In case of any table mapping errors identified, throw an error and stop the process
if ($tableMappingError) { throw "ERROR: One or more table mapping errors were identified. Please see previous messages." }
# In case no tables are in the mapping then throw error
if ($tableMap.Count -le 0) { throw "ERROR: Could not create table mapping." }
LogMessage -Message "Migration table mapping created for $($tableMap.Count) tables."

Создание и настройка входных данных задачи миграции

После создания сопоставления таблиц вы создадите входные данные для задачи миграции типа Migrate.MySql.AzureDbForMySql и настроите свойства.

Следующий скрипт создает задачу миграции и задает подключения, имена баз данных и сопоставление таблиц.

# Create and configure the migration scenario based on the connections
# and the table mapping
$offlineMigTaskProperties = @{
    "input"    = @{
        "sourceConnectionInfo"  = $null;
        "targetConnectionInfo"  = $null;
        "selectedDatabases"     = $null;
        "optionalAgentSettings" = @{
            "EnableCacheBatchesInMemory"         = $true;
            "DisableIncrementalRowStatusUpdates" = $true;
        };
        "startedOn"             = $null;
    };
    "taskType" = "Migrate.MySql.AzureDbForMySql";
};
$offlineSelectedDatabase = @{
    "name"               = $null;
    "targetDatabaseName" = $null;
    "tableMap"           = $null;
};

LogMessage -Message "Preparing migration scenario configuration ..." -IsProcessing $true

# Select the database to be migrated
$offlineSelectedDatabase.name = $SourceDatabaseName;
$offlineSelectedDatabase.tableMap = New-Object PSObject -Property $tableMap;
$offlineSelectedDatabase.targetDatabaseName = $TargetDatabaseName;

# Set connection info and the database mapping
$offlineMigTaskProperties.input.sourceConnectionInfo = $sourceConnInfo;
$offlineMigTaskProperties.input.targetConnectionInfo = $targetConnInfo;
$offlineMigTaskProperties.input.selectedDatabases = @($offlineSelectedDatabase);
$offlineMigTaskProperties.input.startedOn = [System.DateTimeOffset]::UtcNow.ToString("O");

Конфигурация параметров настройки производительности

Для модуля PowerShell доступно несколько необязательных параметров, которые можно настроить в зависимости от среды. Эти параметры можно использовать для повышения производительности задачи миграции. Все эти параметры являются необязательными, и их значение по умолчанию — NULL.

Примечание

В следующих конфигурациях производительности показана увеличенная пропускная способность во время миграции в номере SKU "Премиум".

  • WriteDataRangeBatchTaskCount = 12
  • DelayProgressUpdatesInStorageInterval = 30 с
  • ThrottleQueryTableDataRangeTaskAtBatchCount = 36

Следующий скрипт принимает значения параметров пользователя и задает параметры в свойствах задачи миграции.

# Setting optional parameters from fine tuning the data transfer rate during migration
# DEFAULT values for all the configurations is $null
LogMessage -Message "Adding optional migration performance tuning configuration ..." -IsProcessing $true
# Partitioning settings
# Optional setting that configures the maximum number of parallel reads on tables located on the source database.
[object] $DesiredRangesCount = 4
# Optional setting that configures that size of the largest batch that will be committed to the target server.
[object] $MaxBatchSizeKb = 4096
# Optional setting that configures the minimum number of rows in each batch written to the target.
[object] $MinBatchRows = $null
# Task count settings
# Optional setting that configures the number of databases that will be prepared for migration in parallel.
[object] $PrepareDatabaseForBulkImportTaskCount = $null
# Optional setting that configures the number of tables that will be prepared for migration in parallel.
[object] $PrepareTableForBulkImportTaskCount = $null
# Optional setting that configures the number of threads available to read ranges on the source.
[object] $QueryTableDataRangeTaskCount = 8
# Optional setting that configures the number of threads available to write batches to the target.
[object] $WriteDataRangeBatchTaskCount = 12
# Batch cache settings
# Optional setting that configures how much memory will be used to cache batches in memory before reads on the source are throttled.
[object] $MaxBatchCacheSizeMb = $null
# Optional setting that configures the amount of available memory at which point reads on the source will be throttled.
[object] $ThrottleQueryTableDataRangeTaskAtAvailableMemoryMb = $null
# Optional setting that configures the number of batches cached in memory that will trigger read throttling on the source.
[object] $ThrottleQueryTableDataRangeTaskAtBatchCount = 36
# Performance settings
# Optional setting that configures the delay between updates of result objects in Azure Table Storage.
[object] $DelayProgressUpdatesInStorageInterval = "00:00:30"

function AddOptionalSetting($optionalAgentSettings, $settingName, $settingValue) {
    # If no value specified for the setting, don't bother adding it to the input
    if ($null -eq $settingValue) {
        return;
    }

    # Add a new property to the JSON object to capture the setting which will be customized
    $optionalAgentSettings | add-member -MemberType NoteProperty -Name $settingName -Value $settingValue
}

# Set any optional settings in the input based on parameters to this cmdlet
AddOptionalSetting $offlineMigTaskProperties.input.optionalAgentSettings "DesiredRangesCount" $DesiredRangesCount;
AddOptionalSetting $offlineMigTaskProperties.input.optionalAgentSettings "MaxBatchSizeKb" $MaxBatchSizeKb;
AddOptionalSetting $offlineMigTaskProperties.input.optionalAgentSettings "MinBatchRows" $MinBatchRows;
AddOptionalSetting $offlineMigTaskProperties.input.optionalAgentSettings "PrepareDatabaseForBulkImportTaskCount" $PrepareDatabaseForBulkImportTaskCount;
AddOptionalSetting $offlineMigTaskProperties.input.optionalAgentSettings "PrepareTableForBulkImportTaskCount" $PrepareTableForBulkImportTaskCount;
AddOptionalSetting $offlineMigTaskProperties.input.optionalAgentSettings "QueryTableDataRangeTaskCount" $QueryTableDataRangeTaskCount;
AddOptionalSetting $offlineMigTaskProperties.input.optionalAgentSettings "WriteDataRangeBatchTaskCount" $WriteDataRangeBatchTaskCount;
AddOptionalSetting $offlineMigTaskProperties.input.optionalAgentSettings "MaxBatchCacheSizeMb" $MaxBatchCacheSizeMb;
AddOptionalSetting $offlineMigTaskProperties.input.optionalAgentSettings "ThrottleQueryTableDataRangeTaskAtAvailableMemoryMb" $ThrottleQueryTableDataRangeTaskAtAvailableMemoryMb;
AddOptionalSetting $offlineMigTaskProperties.input.optionalAgentSettings "ThrottleQueryTableDataRangeTaskAtBatchCount" $ThrottleQueryTableDataRangeTaskAtBatchCount;
AddOptionalSetting $offlineMigTaskProperties.input.optionalAgentSettings "DelayProgressUpdatesInStorageInterval" $DelayProgressUpdatesInStorageInterval;

Создание и запуск задачи миграции

После настройки входных данных для задачи она будет создана и выполнена на агенте. Скрипт запускает выполнение задачи и ожидает завершения миграции.

Следующий скрипт вызывает настроенную задачу миграции и ожидает ее завершения.

# Running the migration scenario
[string] $TaskName = "mysqlofflinemigrate"

LogMessage -Message "Running data migration scenario ..." -IsProcessing $true
$summary = @{
    "SourceServer"   = $SourceServerName;
    "SourceDatabase" = $SourceDatabaseName;
    "TargetServer"   = $TargetServerName;
    "TargetDatabase" = $TargetDatabaseName;
    "TableCount"     = $tableMap.Count;
    "StartedOn"      = $offlineMigTaskProperties.input.startedOn;
}

Write-Host "Job Summary:" -ForegroundColor Yellow
Write-Host $(ConvertTo-Json $summary) -ForegroundColor Yellow

$migrationResult = RunScenario -MigrationService $dmsService `
    -MigrationProject $dmsProject `
    -ScenarioTaskName $TaskName `
    -TaskProperties $offlineMigTaskProperties

LogMessage -Message "Migration completed with status - $($migrationResult.state)"
#Checking for any errors or warnings captured by the task during migration
$dbLevelResult = $migrationResult.output | Where-Object { $_.resultType -eq "DatabaseLevelOutput" } 
$migrationLevelResult = $migrationResult.output | Where-Object { $_.resultType -eq "MigrationLevelOutput" }
if ($dbLevelResult.exceptionsAndWarnings) {
    Write-Host "Following database errors were captured: $($dbLevelResult.exceptionsAndWarnings)" -ForegroundColor Red
}
if ($migrationLevelResult.exceptionsAndWarnings) {
    Write-Host "Following migration errors were captured: $($migrationLevelResult.exceptionsAndWarnings)" -ForegroundColor Red
}
if ($migrationResult.errors.details) {
    Write-Host "Following task level migration errors were captured: $($migrationResult.errors.details)" -ForegroundColor Red
}

Удаление Database Migration Service

Один и тот же созданный экземпляр Database Migration Service можно использовать для нескольких операций миграции. Если вы не собираетесь дальше использовать Database Migration Service, можно удалить службу с помощью команды Remove-AzDataMigrationService.

Следующий скрипт удаляет экземпляр Azure Database Migration Service и связанные с ним проекты.

Remove-AzDataMigrationService -ResourceId $($dmsService.ResourceId)

Дальнейшие действия