使用脚本配置链接 - Azure SQL 托管实例

适用于:Azure SQL 托管实例

本文介绍如何通过 Transact-SQL (T-SQL) 和 PowerShell 或 Azure CLI 脚本配置 SQL Server 与 Azure SQL 托管实例之间的链接。 通过该链接,初始主要副本中的数据库将近乎实时地复制到次要副本。

创建链接后,可以故障转移到次要副本以进行迁移或灾难恢复。

注意

概述

使用链接功能将初始主要副本中的数据库复制到次要副本。 对于 SQL Server 2022,初始主要副本可以是 SQL Server 或 Azure SQL 托管实例。 对于 SQL Server 2019 及更早版本,初始主要副本必须是 SQL Server。 配置链接后,将初始主要副本中的数据库复制到次要副本。

可以选择在主要副本和次要副本之间的混合环境中保留该链接的位置以便进行连续数据复制,也可以将数据库故障转移到次要副本、迁移到 Azure 或进行灾难恢复。 对于 SQL Server 2019 及更早版本,将故障转移到 Azure SQL 托管实例即可断开链接,不支持故障回复功能。 使用 SQL Server 2022,可以选择维护链接并在两个副本之间来回故障回复。

如果计划仅使用辅助托管实例进行灾难恢复,可以通过激活混合故障转移权益来节省许可成本。

使用本文中的说明手动设置 SQL Server 与 Azure SQL 托管实例之间的链接。 创建链接后,会在目标次要副本上创建源数据库的只读副本。

提示

若要简化使用具有适用于环境的正确参数的 T-SQL 脚本,强烈建议使用 SQL Server Management Studio (SSMS) 中的托管实例链接向导来生成脚本以创建链接。 在“新建托管实例链接”窗口的“摘要”页上,选择“脚本”,而不是“完成”。

先决条件

若要复制数据库,需要满足以下先决条件:

考虑以下情况:

  • 链接功能支持每个链接有一个数据库。 若要在一个实例上复制多个数据库,请为每个单独的数据库创建一个链接。 例如,若要将 10 个数据库复制到 SQL 托管实例,请创建 10 个单独链接。
  • SQL Server 和 SQL 托管实例之间的排序规则应相同。 排序规则不匹配可能会导致服务器名称大小写不匹配,并阻止从 SQL Server 到 SQL 托管实例的成功连接。
  • SQL Server 初始主要副本上的错误 1475 指示需要通过在不使用 COPY ONLY 选项的情况下创建完整备份来启动新的备份链。

权限

对于SQL Server,应具有 sysadmin 权限。

对于 Azure SQL 托管实例,你应是 SQL 托管实例参与者的一位成员,或具有自定义角色的以下权限:

Microsoft.Sql/ 资源 必要的权限
Microsoft.Sql/managedInstances /read、/write
Microsoft.Sql/managedInstances/hybridCertificate /action
Microsoft.Sql/managedInstances/databases /read、/delete、/write、/completeRestore/action、/readBackups/action、/restoreDetails/read
Microsoft.Sql/managedInstances/distributedAvailabilityGroups /read、/write、/delete、/setRole/action
Microsoft.Sql/managedInstances/endpointCertificates /read
Microsoft.Sql/managedInstances/hybridLink /read、/write、/delete
Microsoft.Sql/managedInstances/serverTrustCertificates /write、/delete、/read

术语和命名约定

在运行本用户指南中的脚本时,切勿将 SQL Server 或 SQL 托管实例名称与它们的完全限定域名 (FQDN) 混淆,这一点很重要。 下表说明了各种名称确切表示的内容,以及如何获取其值:

术语 说明 如何找出
初始主 1 最初创建链接的 SQL Server 或 SQL 托管实例,用于将数据库复制到次要副本。
主要副本 当前托管主数据库的 SQL Server 或 SQL 托管实例。
辅助副本 从当前主要副本接收近实时复制数据的 SQL Server 或 SQL 托管实例。
SQL Server 名称 简短的单字 SQL Server 名称。 例如:“sqlserver1”。 通过 T-SQL 运行 SELECT @@SERVERNAME
SQL Server FQDN SQL Server 的完全限定域名 (FQDN)。 例如:“sqlserver1.domain.com”。 查看你的本地网络 (DNS) 配置,或者服务器名称(如果使用 Azure 虚拟机 (VM))。
SQL 托管实例名称 简短的单字 SQL 托管实例名称。 例如:“managedinstance1”。 请在 Azure 门户中查看你的托管实例的名称。
SQL 托管实例 FQDN SQL 托管实例的完全限定域名 (FQDN)。 例如:managedinstance1.6d710bcf372b.database.chinacloudapi.cn 请在 Azure 门户中的 SQL 托管实例概述页上查看该主机名。
可解析域名 可解析为 IP 地址的 DNS 名称。 例如,运行 nslookup sqlserver1.domain.com 应返回一个 IP 地址,例如 10.0.0.1。 通过命令提示符运行 nslookup 命令。
SQL Server IP SQL Server 的 IP 地址。 如果 SQL Server 有多个 IP,请选择可从 Azure 访问的 IP 地址。 通过运行 SQL Server 的主机操作系统的命令提示符运行 ipconfig 命令。

1SQL Server 2022 CU10 开始,支持将 Azure SQL 托管实例配置为初始主实例。

设置数据库恢复和备份

如果 SQL Server 是初始主要副本,要通过链接复制的所有数据库必须处于完整恢复模式,并且至少有一个备份。 由于 Azure SQL 托管实例会自动执行备份,因此如果 SQL 托管实例是初始主要副本,请跳过此步骤。

针对要复制的所有数据库,在 SQL Server 上运行以下代码。 将 <DatabaseName> 替换为数据库的实际名称。

-- Run on SQL Server
-- Set full recovery model for all databases you want to replicate.
ALTER DATABASE [<DatabaseName>] SET RECOVERY FULL
GO

-- Execute backup for all databases you want to replicate.
BACKUP DATABASE [<DatabaseName>] TO DISK = N'<DiskPath>'
GO

有关详细信息,请参阅创建完整数据库备份

注意

该链接仅支持复制用户数据库。 不支持复制系统数据库。 要复制实例级对象(存储在 mastermsdb 数据库中),我们建议编写 T-SQL 脚本,并在目标实例上运行这些脚本。

在实例之间建立信任

首先,必须在两个实例之间建立信任,并保护用于在网络上进行数据通信和加密的终结点。 分布式可用性组使用现有的可用性组数据库镜像终结点,而不是使用自己的专用终结点。 因此需要通过可用性组数据库镜像终结点在两个实例之间配置安全性和信任。

注意

此链接基于 Always On 可用性组技术。 数据库镜像终结点是用途特殊的终结点,专门由可用性组接收来自其他实例的连接。 请不要误解数据库镜像终结点一词,它与旧版 SQL Server 数据库镜像功能不同。

基于证书的信任是用于保护 SQL Server 和 SQL 托管实例的数据库镜像终结点的唯一受支持方法。 如果现有的可用性组使用 Windows 身份验证,则需要将基于证书的信任作为辅助身份验证选项添加到现有镜像终结点。 可以使用 ALTER ENDPOINT 语句来执行此操作,如本文后面部分所示。

重要

生成的证书有过期日期和时间。 证书需要在过期之前进行续订和轮换。

以下列出了用于保护 SQL Server 和 SQL 托管实例的数据库镜像端点的过程概述:

  1. 在 SQL Server 上生成证书并获取其公钥。
  2. 获取 SQL 托管实例证书的公钥。
  3. 在 SQL Server 和 SQL 托管实例之间交换公钥。
  4. 将 Azure 受信任的根证书颁发机构密钥导入到 SQL Server

以下各部分详细介绍了这些步骤。

在 SQL Server 上创建证书并将其公钥导入 SQL 托管实例

首先,在 master 数据库中创建数据库主密钥(如果尚不存在)。 在下面的脚本中插入密码替代 <strong_password>,并将其保存在机密且安全的地方。 在 SQL Server 上运行此 T-SQL 脚本:

-- Run on SQL Server
-- Create a master key encryption password
-- Keep the password confidential and in a secure place
USE MASTER
IF NOT EXISTS (SELECT * FROM sys.symmetric_keys WHERE symmetric_key_id = 101)
BEGIN
    PRINT 'Creating master key.' + CHAR(13) + 'Keep the password confidential and in a secure place.'
    CREATE MASTER KEY ENCRYPTION BY PASSWORD = '<strong_password>'
END
ELSE
    PRINT 'Master key already exists.'
GO

然后,在 SQL Server 生成身份验证证书。 在以下代码中,进行以下替换:

  • @cert_expiry_date 替换为所需证书到期日期(未来日期)。

记录此日期并设置提醒,以便在 SQL 服务器证书到期前进行轮换(更新),从而确保链接持续运行。

重要

强烈建议使用此脚本中自动生成的证书名称。 尽管允许在 SQL Server 上自定义自己的证书名称,但名称不应包含任何 \ 字符。

-- Create the SQL Server certificate for the instance link
USE MASTER

-- Customize SQL Server certificate expiration date by adjusting the date below
DECLARE @cert_expiry_date AS varchar(max)='03/30/2025'

-- Build the query to generate the certificate
DECLARE @sqlserver_certificate_name NVARCHAR(MAX) = N'Cert_' + @@servername  + N'_endpoint'
DECLARE @sqlserver_certificate_subject NVARCHAR(MAX) = N'Certificate for ' + @sqlserver_certificate_name
DECLARE @create_sqlserver_certificate_command NVARCHAR(MAX) = N'CREATE CERTIFICATE [' + @sqlserver_certificate_name + '] ' + char (13) +
'    WITH SUBJECT = ''' + @sqlserver_certificate_subject + ''',' + char (13) +
'    EXPIRY_DATE = '''+ @cert_expiry_date + ''''+ char (13)
IF NOT EXISTS (SELECT name from sys.certificates WHERE name = @sqlserver_certificate_name)
BEGIN
    PRINT (@create_sqlserver_certificate_command)
    -- Execute the query to create SQL Server certificate for the instance link
    EXEC sp_executesql @stmt = @create_sqlserver_certificate_command
END
ELSE
    PRINT 'Certificate ' + @sqlserver_certificate_name + ' already exists.'
GO

然后,在 SQL Server 上使用以下 T-SQL 查询来验证是否已创建该证书:

-- Run on SQL Server
USE MASTER
GO
SELECT * FROM sys.certificates WHERE pvt_key_encryption_type = 'MK'

在查询结果中,你将看到该证书已用主密钥进行了加密。

现在,可以在 SQL Server 上获取生成的证书的公钥:

-- Run on SQL Server
-- Show the name and the public key of generated SQL Server certificate
USE MASTER
GO
DECLARE @sqlserver_certificate_name NVARCHAR(MAX) = N'Cert_' + @@servername  + N'_endpoint'
DECLARE @PUBLICKEYENC VARBINARY(MAX) = CERTENCODED(CERT_ID(@sqlserver_certificate_name));
SELECT @sqlserver_certificate_name as 'SQLServerCertName'
SELECT @PUBLICKEYENC AS SQLServerPublicKey;

保存来自输出的 SQLServerCertNameSQLServerPublicKey 的值,因为导入证书的下一步需要用到。

首先,请确保已登录到 Azure,并且已选择托管实例所在的订阅。 如果帐户上有多个 Azure 订阅,则务必选择适当的订阅。

<SubscriptionID> 替换为你的 Azure 订阅 ID。

# Enter your Azure subscription ID
$SubscriptionID = "<SubscriptionID>"

# Login to Azure and select subscription ID
if ((Get-AzContext ) -eq $null)
{
    echo "Logging to Azure subscription"
    Login-AzAccount -Environment AzureChinaCloud
}
Select-AzSubscription -SubscriptionName $SubscriptionID

然后使用 New-AzSqlInstanceServerTrustCertificate PowerShell 或 az sql mi partner-cert create Azure CLI 命令将身份验证证书的公钥从 SQL Server 上传到 Azure,例如以下 PowerShell 示例。

填写必要的用户信息,复制、粘贴信息,然后运行脚本。 将:

  • <SQLServerPublicKey> 替换为在上一步骤中记录的二进制格式的 SQL Server 证书的公共部分。 它是以 0x 开头的长字符串值。
  • <SQLServerCertName> 替换为在上一步中记录的 SQL Server 证书名称。
  • <ManagedInstanceName> 替换为你的托管实例的短名称。
# POWERSHELL SCRIPT TO IMPORT SQL SERVER PUBLIC CERTIFICATE TO SQL MANAGED INSTANCE
# ===== Enter user variables here ====

# Enter the name for the server SQLServerCertName certificate – for example, "Cert_sqlserver1_endpoint"
$CertificateName = "<SQLServerCertName>"

# Insert the certificate public key blob that you got from SQL Server – for example, "0x1234567..."
$PublicKeyEncoded = "<SQLServerPublicKey>"

# Enter your managed instance short name – for example, "sqlmi"
$ManagedInstanceName = "<ManagedInstanceName>"

# ==== Do not customize the below cmdlets====

# Find out the resource group name
$ResourceGroup = (Get-AzSqlInstance -InstanceName $ManagedInstanceName).ResourceGroupName

# Upload the public key of the authentication certificate from SQL Server to Azure.
New-AzSqlInstanceServerTrustCertificate -ResourceGroupName $ResourceGroup -InstanceName $ManagedInstanceName -Name $CertificateName -PublicKey $PublicKeyEncoded 

此操作会生成上传到 Azure 的 SQL Server 证书的摘要。

如果需要查看所有上传到托管实例的 SQL Server 证书,请使用 Get-AzSqlInstanceServerTrustCertificate PowerShell 或 az sql mi partner-cert list Azure CLI 命令。 若要删除上传到 SQL 托管实例的 SQL Server 证书,请使用 Remove-AzSqlInstanceServerTrustCertificate PowerShell 或 az sql mi partner-cert delete Azure CLI 命令。

获取 SQL 托管实例的证书公钥并将其导入到 SQL Server

用于保护链接终结点的证书将在 Azure SQL 托管实例上自动生成。 从 SQL 托管实例获取证书公钥,并使用 Get-AzSqlInstanceEndpointCertificate PowerShell 或 az sql mi endpoint-cert show Azure CLI 命令将其导入到 SQL Server,例如以下 PowerShell 示例。

注意

使用 Azure CLI 时,若要在后续步骤中使用 PublicKey 输出,则需要将 0x 手动添加到 PublicKey 输出的前面。 例如,PublicKey 将类似于“0x3082033E30...”。

运行以下脚本。 将:

  • <SubscriptionID> 替换为 Azure 订阅 ID。
  • <ManagedInstanceName> 替换为你的托管实例的短名称。
# POWERSHELL SCRIPT TO EXPORT MANAGED INSTANCE PUBLIC CERTIFICATE
# ===== Enter user variables here ====

# Enter your managed instance short name – for example, "sqlmi"
$ManagedInstanceName = "<ManagedInstanceName>"

# ==== Do not customize the following cmdlet ====

# Find out the resource group name
$ResourceGroup = (Get-AzSqlInstance -InstanceName $ManagedInstanceName).ResourceGroupName

# Fetch the public key of the authentication certificate from Managed Instance. Outputs a binary key in the property PublicKey.
Get-AzSqlInstanceEndpointCertificate -ResourceGroupName $ResourceGroup -InstanceName $ManagedInstanceName -EndpointType "DATABASE_MIRRORING" | out-string   

复制整个 PublicKey 输出(以 0x 开头),下一步将需要它。

或者,如果在复制粘贴 PublicKey 时遇到问题,还可以在托管实例上运行 T-SQL 命令 EXEC sp_get_endpoint_certificate 4 以获取其用于链接终结点的公钥。

接下来,将已获取的托管实例安全证书公钥导入 SQL Server。 在 SQL Server 上运行以下查询,以创建 MI 终结点证书。 将:

  • <ManagedInstanceFQDN> 替换为托管实例的完全限定的域名。
  • <PublicKey> 替换为上一步中获取的 PublicKey 值(从 0x 开始)。 无需使用引号。

重要

证书名称必须是 SQL 托管实例 FQDN,并且不应修改。 如果使用自定义名称,则链接将不起作用。

-- Run on SQL Server
USE MASTER
CREATE CERTIFICATE [<ManagedInstanceFQDN>]
FROM BINARY = <PublicKey> 

将 Azure 受信任的根证书颁发机构密钥导入到 SQL Server

需要将 Microsoft 和 DigiCert 证书颁发机构 (CA) 的公共根证书密钥导入 SQL Server,以便 SQL Server 信任 Azure 为 database.chinacloudapi.cn 域颁发的证书。

注意

确保 PublicKey 以 0x 开头。 如果 PublicKey 尚不存在,则可能需要将其手动添加到 PublicKey 的开头。

首先,在 SQL Server 上导入 Microsoft PKI 根证书颁发机构证书:

-- Run on SQL Server
-- Import Microsoft PKI root-authority certificate (trusted by Azure), if not already present
IF NOT EXISTS (SELECT name FROM sys.certificates WHERE name = N'MicrosoftPKI')
BEGIN
    PRINT 'Creating MicrosoftPKI certificate.'
    CREATE CERTIFICATE [MicrosoftPKI] FROM BINARY = 0x308205A830820390A00302010202101ED397095FD8B4B347701EAABE7F45B3300D06092A864886F70D01010C05003065310B3009060355040613025553311E301C060355040A13154D6963726F736F667420436F72706F726174696F6E313630340603550403132D4D6963726F736F66742052534120526F6F7420436572746966696361746520417574686F726974792032303137301E170D3139313231383232353132325A170D3432303731383233303032335A3065310B3009060355040613025553311E301C060355040A13154D6963726F736F667420436F72706F726174696F6E313630340603550403132D4D6963726F736F66742052534120526F6F7420436572746966696361746520417574686F72697479203230313730820222300D06092A864886F70D01010105000382020F003082020A0282020100CA5BBE94338C299591160A95BD4762C189F39936DF4690C9A5ED786A6F479168F8276750331DA1A6FBE0E543A3840257015D9C4840825310BCBFC73B6890B6822DE5F465D0CC6D19CC95F97BAC4A94AD0EDE4B431D8707921390808364353904FCE5E96CB3B61F50943865505C1746B9B685B51CB517E8D6459DD8B226B0CAC4704AAE60A4DDB3D9ECFC3BD55772BC3FC8C9B2DE4B6BF8236C03C005BD95C7CD733B668064E31AAC2EF94705F206B69B73F578335BC7A1FB272AA1B49A918C91D33A823E7640B4CD52615170283FC5C55AF2C98C49BB145B4DC8FF674D4C1296ADF5FE78A89787D7FD5E2080DCA14B22FBD489ADBACE479747557B8F45C8672884951C6830EFEF49E0357B64E798B094DA4D853B3E55C428AF57F39E13DB46279F1EA25E4483A4A5CAD513B34B3FC4E3C2E68661A45230B97A204F6F0F3853CB330C132B8FD69ABD2AC82DB11C7D4B51CA47D14827725D87EBD545E648659DAF5290BA5BA2186557129F68B9D4156B94C4692298F433E0EDF9518E4150C9344F7690ACFC38C1D8E17BB9E3E394E14669CB0E0A506B13BAAC0F375AB712B590811E56AE572286D9C9D2D1D751E3AB3BC655FD1E0ED3740AD1DAAAEA69B897288F48C407F852433AF4CA55352CB0A66AC09CF9F281E1126AC045D967B3CEFF23A2890A54D414B92AA8D7ECF9ABCD255832798F905B9839C40806C1AC7F0E3D00A50203010001A3543052300E0603551D0F0101FF040403020186300F0603551D130101FF040530030101FF301D0603551D0E0416041409CB597F86B2708F1AC339E3C0D9E9BFBB4DB223301006092B06010401823715010403020100300D06092A864886F70D01010C05000382020100ACAF3E5DC21196898EA3E792D69715B813A2A6422E02CD16055927CA20E8BAB8E81AEC4DA89756AE6543B18F009B52CD55CD53396D624C8B0D5B7C2E44BF83108FF3538280C34F3AC76E113FE6E3169184FB6D847F3474AD89A7CEB9D7D79F846492BE95A1AD095333DDEE0AEA4A518E6F55ABBAB59446AE8C7FD8A2502565608046DB3304AE6CB598745425DC93E4F8E355153DB86DC30AA412C169856EDF64F15399E14A75209D950FE4D6DC03F15918E84789B2575A94B6A9D8172B1749E576CBC156993A37B1FF692C919193E1DF4CA337764DA19FF86D1E1DD3FAECFBF4451D136DCFF759E52227722B86F357BB30ED244DDC7D56BBA3B3F8347989C1E0F20261F7A6FC0FBB1C170BAE41D97CBD27A3FD2E3AD19394B1731D248BAF5B2089ADB7676679F53AC6A69633FE5392C846B11191C6997F8FC9D66631204110872D0CD6C1AF3498CA6483FB1357D1C1F03C7A8CA5C1FD9521A071C193677112EA8F880A691964992356FBAC2A2E70BE66C40C84EFE58BF39301F86A9093674BB268A3B5628FE93F8C7A3B5E0FE78CB8C67CEF37FD74E2C84F3372E194396DBD12AFBE0C4E707C1B6F8DB332937344166DE8F4F7E095808F965D38A4F4ABDE0A308793D84D00716245274B3A42845B7F65B76734522D9C166BAAA8D87BA3424C71C70CCA3E83E4A6EFB701305E51A379F57069A641440F86B02C91C63DEAAE0F84

    --Trust certificates issued by Microsoft PKI root authority for Azure database.chinacloudapi.cn domains
    DECLARE @CERTID int
    SELECT @CERTID = CERT_ID('MicrosoftPKI')
    EXEC sp_certificate_add_issuer @CERTID, N'*.database.chinacloudapi.cn'
END
ELSE
    PRINT 'Certificate MicrosoftPKI already exists.'
GO

然后,在 SQL Server 上导入 DigiCert PKI 根颁发机构证书:

-- Run on SQL Server
-- Import DigiCert PKI root-authority certificate trusted by Azure to SQL Server, if not already present
IF NOT EXISTS (SELECT name FROM sys.certificates WHERE name = N'DigiCertPKI')
BEGIN
    PRINT 'Creating DigiCertPKI certificate.'
    CREATE CERTIFICATE [DigiCertPKI] FROM BINARY = 0x3082038E30820276A0030201020210033AF1E6A711A9A0BB2864B11D09FAE5300D06092A864886F70D01010B05003061310B300906035504061302555331153013060355040A130C446967694365727420496E6331193017060355040B13107777772E64696769636572742E636F6D3120301E06035504031317446967694365727420476C6F62616C20526F6F74204732301E170D3133303830313132303030305A170D3338303131353132303030305A3061310B300906035504061302555331153013060355040A130C446967694365727420496E6331193017060355040B13107777772E64696769636572742E636F6D3120301E06035504031317446967694365727420476C6F62616C20526F6F7420473230820122300D06092A864886F70D01010105000382010F003082010A0282010100BB37CD34DC7B6BC9B26890AD4A75FF46BA210A088DF51954C9FB88DBF3AEF23A89913C7AE6AB061A6BCFAC2DE85E092444BA629A7ED6A3A87EE054752005AC50B79C631A6C30DCDA1F19B1D71EDEFDD7E0CB948337AEEC1F434EDD7B2CD2BD2EA52FE4A9B8AD3AD499A4B625E99B6B00609260FF4F214918F76790AB61069C8FF2BAE9B4E992326BB5F357E85D1BCD8C1DAB95049549F3352D96E3496DDD77E3FB494BB4AC5507A98F95B3B423BB4C6D45F0F6A9B29530B4FD4C558C274A57147C829DCD7392D3164A060C8C50D18F1E09BE17A1E621CAFD83E510BC83A50AC46728F67314143D4676C387148921344DAF0F450CA649A1BABB9CC5B1338329850203010001A3423040300F0603551D130101FF040530030101FF300E0603551D0F0101FF040403020186301D0603551D0E041604144E2254201895E6E36EE60FFAFAB912ED06178F39300D06092A864886F70D01010B05000382010100606728946F0E4863EB31DDEA6718D5897D3CC58B4A7FE9BEDB2B17DFB05F73772A3213398167428423F2456735EC88BFF88FB0610C34A4AE204C84C6DBF835E176D9DFA642BBC74408867F3674245ADA6C0D145935BDF249DDB61FC9B30D472A3D992FBB5CBBB5D420E1995F534615DB689BF0F330D53E31E28D849EE38ADADA963E3513A55FF0F970507047411157194EC08FAE06C49513172F1B259F75F2B18E99A16F13B14171FE882AC84F102055D7F31445E5E044F4EA879532930EFE5346FA2C9DFF8B22B94BD90945A4DEA4B89A58DD1B7D529F8E59438881A49E26D56FADDD0DC6377DED03921BE5775F76EE3C8DC45D565BA2D9666EB33537E532B6

    --Trust certificates issued by DigiCert PKI root authority for Azure database.chinacloudapi.cn domains
    DECLARE @CERTID int
    SELECT @CERTID = CERT_ID('DigiCertPKI')
    EXEC sp_certificate_add_issuer @CERTID, N'*.database.chinacloudapi.cn'
END
ELSE
    PRINT 'Certificate DigiCertPKI already exists.'
GO

最后,通过使用以下动态管理视图 (DMV) 验证所有已创建的证书:

-- Run on SQL Server
SELECT * FROM sys.certificates

验证证书

创建证书后,验证是否已正确配置 MI 终结点证书。

首先,通过替换 certificate_id 的值,然后在 SQL Server 上运行以下查询,来确定已导出 MI 证书的 <ManagedInstanceFQDN>

-- Run on SQL Server 
USE MASTER 
GO 

SELECT name, subject, certificate_id, start_date, expiry_date 
FROM sys.certificates 
WHERE issuer_name LIKE '%Microsoft Corporation%' AND name = '<ManagedInstanceFQDN>' 
GO 

接下来,通过替换上一个查询结果中的 <certificate_id> 值,然后在 SQL Server 上运行以下查询,来验证证书:

-- Run on SQL Server 

USE MASTER 
GO 

EXEC sp_validate_certificate_ca_chain <certificate_id> 
GO 

指示 MI 终结点证书已成功通过验证的 Commands completed successfully. Completion time: … 响应。

如果遇到错误,请删除该证书,然后按照从 SQL 托管实例获取证书公钥并将其导入 SQL Server 部分中的步骤进行操作。

要删除该证书,请在 SQL Server 上运行以下查询:

-- Run on SQL Server 

USE MASTER 
GO 

DROP CERTIFICATE [<ManagedInstanceFQDN>] 
GO 

保护数据库镜像终结点

如果 SQL Server 上既没有现有的可用性组,也没有数据库镜像终结点,则下一步需要在 SQL Server 上创建数据库镜像终结点,并使用之前生成的 SQL Server 证书对其进行保护。 如果确实有现有的可用性组或镜像终结点,请跳转到更改现有终结点部分。

在 SQL Server 上创建和保护数据库镜像终结点

若要验证现有数据库镜像终结点是否未创建,请使用以下脚本:

-- Run on SQL Server
-- View database mirroring endpoints on SQL Server
SELECT * FROM sys.database_mirroring_endpoints WHERE type_desc = 'DATABASE_MIRRORING'

如果上述查询未显示现有数据库镜像终结点,请在 SQL Server 上运行以下脚本以获取之前生成的 SQL Server 证书的名称。

-- Run on SQL Server
-- Show the name and the public key of generated SQL Server certificate
USE MASTER
GO
DECLARE @sqlserver_certificate_name NVARCHAR(MAX) = N'Cert_' + @@servername  + N'_endpoint'
SELECT @sqlserver_certificate_name as 'SQLServerCertName'

从输出中保存 SQLServerCertName,下一步中将需要它。

使用以下脚本在端口 5022 上创建新的数据库镜像终结点,并使用 SQL Server 证书保护该终结点。 将:

  • <SQL_SERVER_CERTIFICATE> 替换为上一步中获取的 SQLServerCertName 的名称。
-- Run on SQL Server
-- Create a connection endpoint listener on SQL Server
USE MASTER
CREATE ENDPOINT database_mirroring_endpoint
    STATE=STARTED   
    AS TCP (LISTENER_PORT=5022, LISTENER_IP = ALL)
    FOR DATABASE_MIRRORING (
        ROLE=ALL,
        AUTHENTICATION = CERTIFICATE [<SQL_SERVER_CERTIFICATE>],
        ENCRYPTION = REQUIRED ALGORITHM AES
    )  
GO

通过在 SQL Server 上运行以下脚本来验证镜像终结点是否已创建:

-- Run on SQL Server
-- View database mirroring endpoints on SQL Server
SELECT
    name, type_desc, state_desc, role_desc,
    connection_auth_desc, is_encryption_enabled, encryption_algorithm_desc
FROM 
    sys.database_mirroring_endpoints

成功创建的终结点 state_desc 列应显示为 STARTED

新的镜像终结点是通过 CERTIFICATE 身份验证创建的,并且已启用 AES 加密。

更改现有终结点

注意

如果刚创建了一个新的镜像终结点,请跳过此步骤。 仅当使用现有的可用性组和现有的数据库镜像终结点时,才使用此步骤。

如果将现有可用性组用于链接,或者存在现有的数据库镜像终结点,请先验证它是否满足链接的以下必要条件:

  • 类型必须为 DATABASE_MIRRORING
  • 连接身份验证必须为 CERTIFICATE
  • 必须启用加密。
  • 加密算法必须是 AES

在 SQL Server 上运行以下查询,以查看现有数据库镜像终结点的详细信息:

-- Run on SQL Server
-- View database mirroring endpoints on SQL Server
SELECT
    name, type_desc, state_desc, role_desc, connection_auth_desc,
    is_encryption_enabled, encryption_algorithm_desc
FROM
    sys.database_mirroring_endpoints

如果输出显示现有 DATABASE_MIRRORING 终结点的 connection_auth_desc 不是 CERTIFICATE,或者 encryption_algorthm_desc 不是 AES,则需要更改终结点以满足要求。

在 SQL Server 上,同一个数据库镜像终结点既用于可用性组,又用于分布式可用性组。 如果 connection_auth_desc 终结点是 NTLM(Windows 身份验证)或 KERBEROS,并且需要对现有可用性组进行 Windows 身份验证,则有可能可以通过将身份验证选项切换为 NEGOTIATE CERTIFICATE,将终结点更改为使用多种身份验证方法。 此更改将在对 SQL 托管实例使用证书身份验证的同时允许现有可用性组使用 Windows 身份验证。

同样,如果加密不包含 AES 并且你需要 RC4 加密,也有可能可以将终结点更改为使用这两种算法。 有关更改终结点的可能选项的详细信息,请参阅 sys.database_mirroring_endpoints

以下脚本是如何在 SQL Server 上更改现有数据库镜像终结点的示例。 将:

  • <YourExistingEndpointName> 替换为现有的终结点名称。
  • <SQLServerCertName> 替换为生成的 SQL Server 证书的名称(在上述的先前某一步骤中获得)。

根据你的特定配置,可能需要进一步自定义脚本。 还可以使用 SELECT * FROM sys.certificates 来获取 SQL Server 上创建的证书的名称。

-- Run on SQL Server
-- Alter the existing database mirroring endpoint to use CERTIFICATE for authentication and AES for encryption
USE MASTER
ALTER ENDPOINT [<YourExistingEndpointName>]   
    STATE=STARTED   
    AS TCP (LISTENER_PORT=5022, LISTENER_IP = ALL)
    FOR DATABASE_MIRRORING (
        ROLE=ALL,
        AUTHENTICATION = WINDOWS NEGOTIATE CERTIFICATE [<SQLServerCertName>],
        ENCRYPTION = REQUIRED ALGORITHM AES
    )
GO

运行 ALTER 终结点查询并将双重身份验证模式设置为 Windows 和 Certificate 后,再次在 SQL Server 上使用此查询来显示数据库镜像终结点的详细信息:

-- Run on SQL Server
-- View database mirroring endpoints on SQL Server
SELECT
    name, type_desc, state_desc, role_desc, connection_auth_desc,
    is_encryption_enabled, encryption_algorithm_desc
FROM
    sys.database_mirroring_endpoints

你已成功修改了 SQL 托管实例链接的数据库镜像终结点。

在 SQL Server 上创建可用性组

如果没有现有的可用性组,下一步就是在 SQL Server 上创建一个,无论哪个可用性组将是初始主要副本。

注意

如果已有可用性组,请跳过此部分。

如果 SQL 托管实例为初始主要副本,则用于创建可用性组的命令有所不同,仅从 SQL Server 2022 CU10 开始才支持该功能。

虽然可以为同一数据库建立多个链接,但该链接仅支持每个链接复制一个数据库。 如果要为同一数据库创建多个链接,请对所有链接使用相同的可用性组,然后为 SQL Server 和 SQL 托管实例之间的每个数据库链接创建一个新的分布式可用性组。

如果 SQL Server 是初始主要副本,请使用链接的以下参数创建可用性组:

  • 初始主服务器名称
  • 数据库名称
  • 故障转移模式 MANUAL
  • 种子设定模式 AUTOMATIC

首先,通过运行以下 T-SQL 语句找出 SQL Server 名称:

-- Run on the initial primary
SELECT @@SERVERNAME AS SQLServerName 

使用以下脚本在 SQL Server 上创建可用性组。 将:

  • <AGNameOnSQLServer> 替换为 SQL Server 上的可用性组的名称。 托管实例链接需要每个可用性组有一个数据库。 对于多个数据库,需要创建多个可用性组。 请考虑命名每个可用性组,使其名称反映相应的数据库 - 例如 AG_<db_name>
  • <DatabaseName> 替换为要复制的数据库的名称。
  • <SQLServerName> 替换为在上一步中获取的 SQL Server 实例的名称。
  • <SQLServerIP> 替换为 SQL Server IP 地址。 或者,可以使用可解析的 SQL Server 主机名,但需确保名称可从 SQL 托管实例虚拟网络进行解析。
-- Run on SQL Server
-- Create the primary availability group on SQL Server
USE MASTER
CREATE AVAILABILITY GROUP [<AGNameOnSQLServer>]
WITH (CLUSTER_TYPE = NONE) -- <- Delete this line for SQL Server 2016 only. Leave as-is for all higher versions.
    FOR database [<DatabaseName>]  
    REPLICA ON   
        N'<SQLServerName>' WITH   
            (  
            ENDPOINT_URL = 'TCP://<SQLServerIP>:5022',
            AVAILABILITY_MODE = SYNCHRONOUS_COMMIT,
            FAILOVER_MODE = MANUAL,
            SEEDING_MODE = AUTOMATIC
            );
GO

重要

对于 SQL Server 2016,请从上述 T-SQL 语句中删除 WITH (CLUSTER_TYPE = NONE)。 对于所有更高版本的 SQL Server,请保留原样。

接下来,在 SQL Server 上创建分布式可用性组。 如果计划创建多个链接,则需要为每个链接创建分布式可用性组,即使要为同一数据库建立多个链接也是如此。

替换以下值,然后运行 T-SQL 脚本来创建分布式可用性组。

  • <DAGName> 替换为分布式可用性组的名称。 由于可以通过为每个链接创建分布式可用性组来为同一数据库配置多个链接,因此请考虑相应地命名每个分布式可用性组,例如 DAG1_<db_name>DAG2_<db_name>
  • <AGNameOnSQLServer> 替换为上一步中创建的可用性组的名称。
  • <AGNameOnSQLMI> 替换为 SQL 托管实例上的可用性组的名称。 该名称在 SQL MI 上必须是唯一的。 请考虑命名每个可用性组,使其名称反映相应的数据库 - 例如 AG_<db_name>_MI
  • <SQLServerIP> 替换为来自上一步骤的 SQL Server IP 地址。 或者,可以使用可解析的 SQL Server 主机名,但请确保名称可通过 SQL 托管实例虚拟网络进行解析(这需要为托管实例的子网配置自定义 Azure DNS)。
  • <ManagedInstanceName> 替换为你的托管实例的短名称。
  • <ManagedInstanceFQDN> 替换为托管实例的完全限定域名。
-- Run on SQL Server
-- Create a distributed availability group for the availability group and database
-- ManagedInstanceName example: 'sqlmi1'
-- ManagedInstanceFQDN example: 'sqlmi1.73d19f36a420a.database.chinacloudapi.cn'
USE MASTER
CREATE AVAILABILITY GROUP [<DAGName>]
WITH (DISTRIBUTED) 
    AVAILABILITY GROUP ON  
    N'<AGNameOnSQLServer>' WITH 
    (
      LISTENER_URL = 'TCP://<SQLServerIP>:5022',
      AVAILABILITY_MODE = ASYNCHRONOUS_COMMIT,
      FAILOVER_MODE = MANUAL,
      SEEDING_MODE = AUTOMATIC,
      SESSION_TIMEOUT = 20
    ),
    N'<AGNameOnSQLMI>' WITH
    (
      LISTENER_URL = 'tcp://<ManagedInstanceFQDN>:5022;Server=[<ManagedInstanceName>]',
      AVAILABILITY_MODE = ASYNCHRONOUS_COMMIT,
      FAILOVER_MODE = MANUAL,
      SEEDING_MODE = AUTOMATIC
    );
GO

验证可用性组

使用以下脚本列出 SQL Server 实例上所有可用的可用性组和分布式可用性组。 此时,可用性组状态需要是 connected,并且分布式可用性组状态需要是 disconnected。 分布式可用性组的状态只有在它与 SQL 托管实例联接后才会转换为 connected

-- Run on SQL Server
-- This will show that the availability group and distributed availability group have been created on SQL Server.
SELECT * FROM sys.availability_groups

或者,可以使用 SSMS 对象资源管理器来查找可用性组和分布式可用性组。 依次展开“Always On 高可用性”文件夹和“可用性组”文件夹。

最后,可以创建链接。 根据哪个实例为初始主要副本,这些命令会有所不同。 使用 New-AzSqlInstanceLink PowerShell 或 az sql mi link create Azure CLI 命令创建链接,例如本部分中的 PowerShell 示例。 Azure CLI 当前不支持从 SQL 托管实例主要副本创建链接。

如果需要查看托管实例上的所有链接,请使用 Get-AzSqlInstanceLink PowerShell 或 az sql mi link show Azure CLI 命令。

若要简化该过程,请登录到 Azure 门户并运行以下脚本。 将:

  • <ManagedInstanceName> 替换为你的托管实例的短名称。
  • <AGNameOnSQLServer> 替换为 SQL Server 上创建的可用性组的名称。
  • <AGNameOnSQLMI> 替换为 SQL 托管实例上创建的可用性组的名称。
  • <DAGName> 替换为 SQL Server 上创建的分布式可用性组的名称。
  • <DatabaseName> 替换为 SQL Server 上可用性组中复制的数据库。
  • <SQLServerIP> 替换为 SQL Server 的 IP 地址。 托管实例必须可以访问提供的 IP 地址。

注意

如果要建立指向已存在的可用性组的链接,请在提供 <SQLServerIP> 参数时提供侦听器的 IP 地址。

# POWERSHELL SCRIPT TO CREATE MANAGED INSTANCE LINK
# Instructs Managed Instance to join distributed availability group on SQL Server
# ===== Enter user variables here ====

# Enter your managed instance name – for example, "sqlmi1"
$ManagedInstanceName = "<ManagedInstanceName>"

# Enter the availability group name that was created on SQL Server
$AGNameOnSQLServer = "<AGNameOnSQLServer>"

# Enter the availability group name that was created on SQL Managed Instance
$AGNameOnSQLMI = "<AGNameOnSQLMI>"

# Enter the distributed availability group name that was created on SQL Server
$DAGName = "<DAGName>"

# Enter the database name that was placed in the availability group for replication
$DatabaseName = "<DatabaseName>"

# Enter the SQL Server IP
$SQLServerIP = "<SQLServerIP>"

# ==== Do not customize the following cmdlet ====

# Find out the resource group name
$ResourceGroup = (Get-AzSqlInstance -InstanceName $ManagedInstanceName).ResourceGroupName

# Build properly formatted connection endpoint
$SourceIP = "TCP://" + $SQLServerIP + ":5022"

# Create link on managed instance. Join distributed availability group on SQL Server.
New-AzSqlInstanceLink -ResourceGroupName $ResourceGroup -InstanceName $ManagedInstanceName -Name $DAGName |
-PrimaryAvailabilityGroupName $AGNameOnSQLServer -SecondaryAvailabilityGroupName $AGNameOnSQLMI |
-TargetDatabase $DatabaseName -SourceEndpoint $SourceIP

此操作的结果会是成功执行创建链接请求时的时间戳。

若要验证是否已在 SQL 托管实例和 SQL Server 之间建立连接,请在 SQL Server 上运行以下查询。 连接为非即时连接。 最多可能需要一分钟的时间,DMV 才会开始显示成功的连接。 请持续刷新 DMV,直到 SQL 托管实例副本的连接显示为 CONNECTED。

-- Run on SQL Server
SELECT
    r.replica_server_name AS [Replica],
    r.endpoint_url AS [Endpoint],
    rs.connected_state_desc AS [Connected state],
    rs.last_connect_error_description AS [Last connection error],
    rs.last_connect_error_number AS [Last connection error No],
    rs.last_connect_error_timestamp AS [Last error timestamp]
FROM
    sys.dm_hadr_availability_replica_states rs
    JOIN sys.availability_replicas r
    ON rs.replica_id = r.replica_id

建立连接后,SSMS 中的对象资源管理器最初会将在次要副本上复制的数据库显示为正在还原状态,因为初始种子设定阶段移动并还原数据库的完整备份。 数据库还原后,复制必须跟上,使两个数据库保持同步状态。 初始种子设定完成后,该数据库将不再处于“正在还原”。 种子设定小型数据库可能会很快,以至于在 SSMS 中看不到初始的“正在还原”状态。

重要

  • 除非 SQL Server 和 SQL 托管实例之间存在网络连接,否则此链接将不起作用。 若要解决网络连接问题,请按照测试网络连接中的步骤操作。
  • 定期备份 SQL Server 上的日志文件。 如果使用的日志空间达到 100%,则复制到 SQL 托管实例将会停止,直到空间使用率降低。 强烈建议通过设置每日作业来自动执行日志备份。 有关详细信息,请参阅在 SQL Server 上备份日志文件

进行第一次事务日志备份

如果 SQL Server 是初始主要副本,则在初始种子设定完成,当 Azure SQL 托管实例上的数据库不再处于正在还原...状态时,必须在 SQL Server 上进行第一次事务日志备份。 然后定期进行 SQL Server 事务日志备份,以在 SQL Server 处于主要角色时最大限度地减少日志增长过多的情况。

如果 SQL 托管实例是主要副本,则您无需执行任何操作,因为 Azure SQL 托管实例会自动进行日志备份。

如果想删除链接,无论是因为不再需要它,还是因为它处于无法修复的状态并需要重新创建,则都可以使用 PowerShell 和 T-SQL 来执行此操作。

首先,使用 Remove-AzSqlInstanceLink PowerShell 命令删除链接,如以下示例:

Remove-AzSqlInstanceLink -ResourceGroupName $ResourceGroup -InstanceName $managedInstanceName -Name $DAGName -Force 

然后,在 SQL Server 上运行以下 T-SQL 脚本来删除分布式可用性组。 将 <DAGName> 替换为用于创建链接的分布式可用性组的名称:

USE MASTER 
GO 

DROP AVAILABILITY GROUP <DAGName>  
GO 

最后,如果不再需要可用性组,则可以选择将其删除。 为此,请将 <AGName> 替换为可用性组的名称,然后在相应的实例上运行它:

DROP AVAILABILITY GROUP <AGName>  
GO 

疑难解答

如果在创建链接时遇到错误消息,请查看查询输出窗口中的错误消息以了解详细信息。

要使用该链接,请参阅以下内容:

要了解有关该链接的详细信息,请参阅以下内容:

对于其他复制和迁移方案,请考虑: