SQL Server实例级别迁移上云

RDS SQL Server提供了实例级别的数据库迁移上云方案,支持将自建SQL Server多库或所有库的全量数据迁移至阿里云RDS SQL Server。您只需先备份自建SQL Server的所有数据库,并将完整备份文件上传到OSS Bucket(存储空间)的同一文件夹中,然后执行迁移上云脚本即可。

说明

如果您的上云迁移级别为数据库,即每次只需完成一个数据库迁移上云,请参见全量备份数据上云增量备份数据上云

前提条件

  • 源端需为自建SQL Server数据库。

  • 目标端RDS SQL Server实例需满足如下条件:

    • 实例剩余空间需大于待上云的数据文件。若空间不足,请提前升级实例空间

    • 2008 R2版本:需确保实例中已创建与待迁移数据库名称相同的数据库(其他版本无需执行本操作)。

  • 如果通过RAM用户登录,需满足以下条件:

    • RAM账号具备AliyunOSSFullAccess权限和AliyunRDSFullAccess权限。如何为RAM用户授权,请参见通过RAMOSS进行权限管理通过RAMRDS进行权限管理

    • 阿里云账号(主账号)已授权RDS官方服务账号可以访问您OSS的权限。

      点击展开查看授权方法

      1. 前往RDS实例详情页备份恢复页面,单击OSS备份数据恢复上云按钮。

      2. 数据导入向导页面单击两次下一步,进入3. 数据导入步骤。

        若该页面左下角显示您已授权RDS官方服务账号可以访问您OSS的权限,则表示已授权。否则表示还未授权,单击该页面的授权地址同意授权即可。

        image

    • 所在阿里云账号(主账号)需手动创建权限策略,然后将权限添加到RAM账号中。

      点击展开查看策略内容

      {
          "Version": "1",
          "Statement": [
              {
                  "Action": [
                      "ram:GetRole"
                  ],
                  "Resource": "acs:ram:*:*:role/AliyunRDSImportRole",
                  "Effect": "Allow"
              }
          ]
      }

限制条件

本方案仅支持全量迁移上云,暂不支持增量迁移上云。

费用说明

本方案中仅会产生OSS的相关费用,详情如下图所示。

image

场景

费用说明

将本地数据备份文件上传至OSS

不产生费用。

备份文件存储在OSS

会产生OSS的存储费用,计费详情请参见OSS定价

将备份文件从OSS迁移至RDS

  • 通过内网迁移至RDS,不产生费用。

  • 通过外网迁移至RDS,OSS会产生外网流出流量的费用,计费详情请参见OSS定价

准备工作

1. 安装Python 3

访问Python官网选择3.12及以上版本)下载并安装适合业务系统的安装包。

  • Windows:安装过程中建议勾选Add python.exe to PATH,避免后续手动配置环境变量。

  • macOS/Linux:可通过官网安装包安装,或使用系统包管理器(如Homebrew、apt、dnf等)部署,以官网为准。

2. 验证Python安装与版本

不同系统与发行方式的可执行名可能不同(python、python3、py)。建议按顺序尝试,并以实际输出为准。

Windows(命令行或PowerShell)

python --version
python3 --version
py --version
  • 若输出为Python 3.12.x或更高版本,表示Python已正确安装并可正常使用。

  • 若提示不是内部或外部命令…,则需将Python安装路径手动添加至系统PATH环境变量(Windows)。

macOS/Linux(终端)

python --version
python3 --version

在部分系统中,Python命令可能仍指向旧版本,建议优先使用Python 3命令。请以实际输出为准,确认已安装Python 3.12或更高版本。

3. 安装SDK依赖包

pip install alibabacloud_rds20140815
pip install alibabacloud-oss-v2

1. 备份自建SQL Server所有数据库

重要
  • 为保障数据一致性,在执行全量备份期间,请勿写入新的数据,请提前安排以免影响业务运行。

  • 如果您不使用备份脚本来执行备份,备份文件必须按照数据库名称_备份类型_备份时间.bak的格式来命名,例如Testdb_FULL_20180518153544.bak,否则会导致备份报错。

  1. 下载备份脚本

  2. 双击备份脚本,使用Microsoft SQL Server Management Studio(SSMS)客户端打开。SSMS的连接方法,请参见官方文档

  3. 根据业务需求,修改如下参数。

    点击展开查看示例

    SELECT
        /**
        * Databases list needed to backup, delimiter is : or ,
        * empty('') or null: means all databases excluding system database
        * example: '[testdb]: TestDR, Test, readonly'
        **/
        @backup_databases_list = N'[dtstestdata],[testdb]'
        @backup_type = N'FULL',                    -- Backup Type? FULL: FULL backup; DIFF: Differential backup; LOG: Log backup
        @backup_folder = N'C:\BACKUP'              -- Backup folder to store backup files.
        @is_run = 1                                -- Check or run? 1, run directly; 0, just check

    配置项

    说明

    @backup_databases_list

    需要备份的数据库,多个数据库以分号(;)或者半角逗号(,)分隔。

    @backup_type

    备份类型,取值如下:

    • FULL:全量备份。

    • DIFF:差异备份。

    • LOG:日志备份。

    重要

    本方案中,取值需为FULL

    @backup_folder

    备份文件所在的本地目录。如不存在,会自动创建。

    @is_run

    是否执行备份,取值:

    • 1:执行备份。

    • 0:仅执行检查,不执行备份。

  4. 运行备份脚本,数据库将备份至指定的目录中。

    备份脚本执行结果

2. 上传备份文件到OSS

  1. 将备份文件上传至OSS前,您需先在OSS中创建存储空间Bucket。

    • OSS中已存在Bucket,请确保该Bucket满足以下要求:

      • Bucket存储类型存储类型为标准存储。不能是低频访问存储、归档存储、冷归档存储、深度冷归档存储。

      • Bucket未开启服务器端加密

    • OSS中没有Bucket,需要先行创建。(请确保已开通OSS服务

      1. 登录OSS管理控制台,单击Bucket列表,然后单击创建Bucket

      2. 配置如下关键参数,其他参数可以保持默认。

        重要
        • 创建的存储空间主要用于本次数据上云,只需配置关键参数即可,上云完成后可以及时删除以避免数据泄露及产生相关费用。

        • 创建Bucket时请勿开启服务器端加密

        参数

        说明

        取值示例

        Bucket 名称

        存储空间名称,全局唯一,设置后无法修改。

        命名规则:

        • 只能包括小写字母、数字和短划线(-)。

        • 必须以小写字母或者数字开头和结尾。

        • 长度必须在3~63字符之间。

        migratetest

        地域

        Bucket所属的地域,如果您通过ECS内网上传数据至Bucket中,且通过内网将数据恢复至RDS中,则需要三者地域保持一致。

        华东1(杭州)

        存储类型

        选择标准存储。本文上云操作不支持其他存储类型的Bucket。

        标准存储

  2. 上传备份文件到OSS。

    本地数据库备份完成后,请将备份文件上传到与您的RDS实例同地域OSS Bucket中,两者处于同一地域时可通过内网互通(不会产生外网流量费用),且数据上传速度更快。您可以采用如下方法之一:

    使用ossbrowser工具上传(推荐)

    1. 下载ossbrowser

    2. Windows x64操作系统为例,解压下载的oss-browser-win32-x64.zip压缩包,双击运行oss-browser.exe应用程序。

    3. 使用AK登录方式,配置参数AccessKeyIdAccessKeySecret,其他参数保持默认,然后单击登入

      说明

      AccessKey用于身份验证,确保数据安全,请妥善保管。

      登录ossbrowser

    4. 单击目标Bucket,进入存储空间。进入bucket中

    5. 单击上传图标,选择需要上传的备份文件,然后单击打开,即可将本地文件上传至OSS中。

    使用OSS控制台上传

    说明

    如果备份文件小于5 GB,建议您直接通过OSS控制台上传备份文件。

    1. 登录OSS管理控制台

    2. 单击Bucket列表,然后单击目标Bucket名称。网页进入bucket

    3. 文件列表中,单击上传文件网页上传文件

    4. 您可以将备份文件拖拽至待上传文件区域,也可以单击扫描文件,选择需要上传的备份文件。网页扫描文件

    5. 单击页面下方的上传文件,即可将本地备份文件上传至OSS中。

    使用OSS API分片上传(以Python 3项目为例)

    说明

    如果备份文件大于5 GB,建议您调用OSS API采用分片上传的方式将备份文件上传到OSS Bucket中。

    # -*- coding: utf-8 -*-
    """
    Alibaba Cloud OSS Python SDK v2
    依赖:pip install alibabacloud-oss-v2
    """
    
    import os
    import sys
    from pathlib import Path
    import alibabacloud_oss_v2 as oss
    from alibabacloud_oss_v2 import exceptions as oss_ex
    
    
    def get_client_from_env(region: str, endpoint: str | None = None) -> oss.Client:
        """
        从环境变量创建 v2 客户端。
        - 优先使用 Region(推荐),也支持自定义 Endpoint(可选)。
        - 同时兼容 AK 与 STS:
            * AK: 需要 OSS_ACCESS_KEY_ID / OSS_ACCESS_KEY_SECRET
            * STS: 另需 OSS_SESSION_TOKEN(兼容旧变量 OSS_SECURITY_TOKEN)
        """
        # 兼容:如果用户使用了老变量 OSS_SECURITY_TOKEN,则映射到 v2 期望的 OSS_SESSION_TOKEN
        sec_token_legacy = os.getenv("OSS_SECURITY_TOKEN")
        if sec_token_legacy and not os.getenv("OSS_SESSION_TOKEN"):
            os.environ["OSS_SESSION_TOKEN"] = sec_token_legacy
    
        ak = os.getenv("OSS_ACCESS_KEY_ID")
        sk = os.getenv("OSS_ACCESS_KEY_SECRET")
        st = os.getenv("OSS_SESSION_TOKEN")  # STS Token(可选)
    
        if not (ak and sk):
            raise ValueError("未找到有效的 AK,请设置环境变量 OSS_ACCESS_KEY_ID 和 OSS_ACCESS_KEY_SECRET。"
                             "如使用 STS,请同时设置 OSS_SESSION_TOKEN(或旧名 OSS_SECURITY_TOKEN)。")
    
        # 提示所用凭据类型
        if st:
            print("检测到 STS Token(OSS_SESSION_TOKEN),使用 STS 凭证。")
        else:
            print("未检测到 STS Token,使用 AccessKey (AK) 凭证。")
    
        credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
        cfg = oss.config.load_default()
        cfg.credentials_provider = credentials_provider
    
        # 基本网络配置
        cfg.region = region  # 例如:'cn-hangzhou'
        if endpoint:
            # 可选:自定义 Endpoint(如内网、加速、专有域)
            cfg.endpoint = endpoint
    
        # 也可以在此添加其它配置,如:cfg.use_accelerate_endpoint = True
        return oss.Client(cfg)
    
    
    def resumable_upload_file_v2(
        client: oss.Client,
        bucket_name: str,
        object_key: str,
        file_path: str,
        part_size: int = 1 * 1024 * 1024,
        parallel_num: int = 4,
        checkpoint_dir: str | None = None,
    ):
        """
        实现分片并发 + 断点续传上传。
    
        :param client: 已初始化的 oss.Client
        :param bucket_name: 目标 Bucket 名称
        :param object_key: 目标 Object Key(不包含 Bucket 名)
        :param file_path: 本地文件完整路径
        :param part_size: 分片大小(单位:字节),默认 1MB
        :param parallel_num: 并发上传线程数,默认 4
        :param checkpoint_dir: 断点信息存储目录;若为 None,则不启用断点续传
        """
        file_path = str(file_path)
        if not Path(file_path).exists():
            raise FileNotFoundError(f"错误: 本地文件未找到,请检查 file_path 配置: {file_path}")
    
        # 构造 Uploader;根据是否传入checkpoint_dir来启用断点续传
        if checkpoint_dir:
            uploader = client.uploader(
                enable_checkpoint=True,
                checkpoint_dir=checkpoint_dir,
                part_size=part_size,
                parallel_num=parallel_num,
            )
        else:
            uploader = client.uploader(
                part_size=part_size,
                parallel_num=parallel_num,
            )
    
        print(f"开始上传文件: {file_path}")
        print(f"目标 Bucket: {bucket_name}")
        print(f"目标 Object: {object_key}")
        print(f"分片大小: {part_size} 字节, 并发数: {parallel_num}")
        if checkpoint_dir:
            print(f"断点续传: 已启用(checkpoint_dir={checkpoint_dir})")
        else:
            print("断点续传: 未启用(如需启用请设置 checkpoint_dir)")
    
        # 执行上传(Uploader 会自动根据大小选择多/单分片并发上传)
        result = uploader.upload_file(
            oss.PutObjectRequest(bucket=bucket_name, key=object_key),
            filepath=file_path,
        )
    
        print("-" * 30)
        print("文件上传成功!")
        print(f"HTTP Status: {result.status_code}")
        print(f"ETag: {result.etag}")
        print(f"请求 ID: {result.request_id}")
        # CRC64 校验值;v2 默认启用数据校验
        print(f"CRC64: {result.hash_crc64}")
        print("-" * 30)
    
    
    def main():
        # 运行代码示例之前,请确保已设置相应的环境变量。
        # macOS/Linux:
        #   AK方式:
        #     export OSS_ACCESS_KEY_ID=YOUR_AK_ID
        #     export OSS_ACCESS_KEY_SECRET=YOUR_AK_SECRET
        #   STS方式:
        #     export OSS_ACCESS_KEY_ID=YOUR_STS_ID
        #     export OSS_ACCESS_KEY_SECRET=YOUR_STS_SECRET
        #     export OSS_SECURITY_TOKEN=YOUR_STS_TOKEN
        #
        # Windows:
        #   Powershell: $env:OSS_ACCESS_KEY_ID="YOUR_AK_ID"
        #   cmd: set OSS_ACCESS_KEY_ID=YOUR_AK_ID
    
        # ===================== 参数区(按需修改) =====================
        # Region 示例:'cn-hangzhou';建议优先使用 Region
        region = "cn-hangzhou"
    
        # 可选:自定义 Endpoint(如需内网、专有域、加速域名等)
        # 例如:'https://oss-cn-hangzhou.aliyuncs.com'
        endpoint = 'https://oss-cn-hangzhou.aliyuncs.com'  
    
        # Bucket 与 Object
        bucket_name = "examplebucket"
        object_key = "test.bak"
    
        # 待上传的本地文件完整路径。
        # Windows示例: r'D:\localpath\examplefile.txt'  (注意前面的 r)
        # macOS/Linux示例: '/Users/test/examplefile.txt'
        file_path = r"D:\oss\test.bak"
    
        # 分片与并发
        part_size = 1 * 1024 * 1024  # 默认 1MB;OSS 要求单片最小 100KB
        parallel_num = 4
    
        # 断点续传目录(传 None 则不启用;建议指定到一个可写目录)
        checkpoint_dir = str(Path.cwd() / ".oss_checkpoints")
        # =================== 参数区结束 ===================
    
        print("脚本开始执行...")
        try:
            client = get_client_from_env(region=region, endpoint=endpoint)
            # 若启用断点续传,确保目录存在
            if checkpoint_dir:
                Path(checkpoint_dir).mkdir(parents=True, exist_ok=True)
    
            resumable_upload_file_v2(
                client=client,
                bucket_name=bucket_name,
                object_key=object_key,
                file_path=file_path,
                part_size=part_size,
                parallel_num=parallel_num,
                checkpoint_dir=checkpoint_dir,
            )
        except FileNotFoundError as e:
            print(e)
        except oss_ex.ServiceError as e:
            # OSS 服务端返回的错误
            print("\n发生 OSS 服务端错误。")
            print(f"HTTP Status: {getattr(e, 'status_code', 'N/A')}")
            print(f"Error Code: {getattr(e, 'code', 'N/A')}")
            print(f"Message: {getattr(e, 'message', 'N/A')}")
            print(f"Request ID: {getattr(e, 'request_id', 'N/A')}")
            print(f"Endpoint: {getattr(e, 'request_target', 'N/A')}")
        except oss_ex.BaseError as e:
            # SDK 本地/序列化/反序列化/凭据等错误
            print("\n发生 OSS SDK 客户端错误。")
            print(str(e))
        except Exception as e:
            print(f"\n发生未知错误: {e}")
    
    
    if __name__ == "__main__":
        main()

3. 执行上云脚本将数据库迁移至RDS

  1. 下载SQL Server迁移上云脚本

  2. 解压后执行如下命令,了解该脚本需要传入的参数信息。

    python ~/Downloads/RDSSQLCreateMigrateTasksBatchly.py -h

    结果如下:

    RDSSQLCreateMigrateTasksBatchly.py -k <access_key_id> -s <access_key_secret> -i <rds_instance_id> -e <oss_endpoint> -b <oss_bucket> -d <directory>

    参数说明如下:

    参数

    说明

    access_key_id

    目标RDS实例所属的阿里云账号的AccessKey ID。

    access_key_secret

    目标RDS实例所属的阿里云账号的AccessKey Secret。

    rds_instance_id

    目标RDS实例ID。

    oss_endpoint

    备份文件所属的存储空间的Endpoint地址

    oss_bucket

    备份文件所属的存储空间名称。

    directory

    备份文件在OSS存储空间中的目录。如果是根目录,请传入/

  3. 执行迁移上云脚本,完成迁移任务。

    本示例以将OSS存储空间(名称为testdatabucket)的Migrationdata目录中所有满足条件的备份文件,全量迁移到RDS SQL Server实例(实例IDrm-2zesz5774ud8s****)为例。

    python ~/Downloads/RDSSQLCreateMigrateTasksBatchly.py -k yourAccessKeyID -s yourAccessKeySecret -i rm-2zesz5774ud8s**** -e oss-cn-beijing.aliyuncs.com -b testdatabucket -d Migrationdata

4. 查看迁移任务进度

请根据RDS SQL Server实例版本,选择对应方案。

2012及以上版本

访问RDS实例左侧导航栏备份恢复页面,在备份数据上云记录页签内查看备份上云记录,包括任务状态、任务开始和结束时间等。默认展示最近一周的记录,可按需调整时间区间。

image

说明

任务状态失败时,请查看任务描述或单击目标迁移任务后面的查看文件详情,确认任务失败的原因并修复,然后重新执行数据迁移。

2008 R2

访问RDS实例左侧导航栏数据上云页面,然后找到目标迁移任务来查看数据迁移的进度。

说明

任务状态失败时,请查看任务描述或单击目标迁移任务后面的查看文件详情,确认任务失败的原因并修复,然后重新执行数据迁移。

视频演示

常见错误

错误提示

原因

解决方法

HTTP Status: 404 Error:InvalidAccessKeyId.NotFound Specified access key is not found. RequestID: XXXXXXXXXXXXXXXXX

调用OpenAPI时使用的AccessKey ID不正确。

传入正确的AccessKey IDAccessKey Secret

HTTP Status: 400 Error:IncompleteSignature The request signature does not conform to Aliyun standards. server string to sign is:......

调用OpenAPI时使用的AccessKey Secret不正确。

RDS engine doesn't support, this is only for RDS SQL Server engine.

本方案仅支持RDS SQL Server,不支持其他引擎。

RDS SQL Server作为迁移的目标实例。

Couldn't find specify RDS [XXX].

RDS实例ID不存在。

检查传入的RDS实例ID是否正确。

{'status': -2, 'request-id': '', 'details': "RequestError: HTTPConnectionPool(host='xxxxxxxxxxxxxxxxx', port=80): Max retries exceeded with url: /?bucketInfo= (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x10e996490>: Failed to establish a new connection: [Errno 8] nodename nor servname provided, or not known',))"}

Endpoint错误,导致连接失败。

检查传入的Endpoint是否正确。

{'status': 404,'-id': 'xxxxxxxxx', 'details': {'HostId': 'xxxxxxxxx', 'Message': 'The specified bucket does not exist.', 'Code': 'NoSuchBucket', 'RequestId': 'xxxxxxxx', 'BucketName': 'aaaatp-test-on-ecs'}}

OSS Bucket(存储空间)不存在。

检查传入的OSS Bucket是否正确。

There is no backup file on OSS Bucket [xxxxxx] under [xxxxxxxxx] folder, check please.

OSS Bucket中对应的文件夹不存在或文件夹中没有满足条件的数据库备份文件。

检查OSS Bucket中文件夹是否存在,同时检查该文件夹中是否存在满足条件的数据库备份文件。

Warning!!!!!, [autotest_2005_ent_broken_full_dbcc_failed.bak] is not backup file, filtered.

备份文件的名称不符合规范。

如果您不使用备份脚本来执行备份,备份文件必须按照数据库名称_备份类型_备份时间.bak的格式来命名,例如Testdb_FULL_20180518153544.bak

HTTP Status: 403 Error:Forbidden.RAM The user is not authorized to operate the specified resource, or this operation does not support RAM. RequestID: xxxxx{'status': 403, 'request-id': 'xxxx', 'details': {'HostId': 'atp-test-on-ecs.oss-cn-beijing.aliyuncs.com', 'Message': 'The bucket you visit is not belong to you.', 'Code': 'AccessDenied', 'RequestId': 'xxxx'}}

子账号权限不足。

需要为子账号授予OSSRDS的使用权限(即AliyunOSSFullAccessAliyunRDSFullAccess权限)。

OPENAPI Response Error !!!!! : HTTP Status: <Http Status Code> Error:<Error> <Description>. RequestID: 32BB6886-775E-4BB7-A054-635664****

调用OpenAPI返回了错误信息。

根据错误码和错误信息来分析具体原因。

OpenAPI错误码

HTTP Status Code

Error

Description

说明

403

InvalidDBName

The specified database name is not allowed.

非法的数据库名字,不允许使用系统数据库名。

403

IncorrectDBInstanceState

Current DB instance state does not support this operation.

RDS实例状态不正确。例如,实例状态为创建中

400

IncorrectDBInstanceType

Current DB instance type does not support this operation.

不支持的引擎,该功能仅支持RDS SQL Server。

400

IncorrectDBInstanceLockMode

Current DB instance lock mode does not support this operation.

数据库锁定状态不正确。

400

InvalidDBName.NotFound

Specified one or more DB name does not exist or DB status does not support.

数据库不存在。

  • RDS SQL Server 2008 R2需要先创建同名数据库。

  • RDS SQL Server 2012及以上版本,要求不能存在同名的数据库。

400

IncorrectDBType

Current DB type does not support this operation.

数据库类型不支持该操作。

400

IncorrectDBState

Current DB state does not support this operation.

数据库状态不正确,例如,数据库在创建中或者正在上云任务中。

400

UploadLimitExceeded

UploadTimesQuotaExceeded: Exceeding the daily upload times of this DB.

上云次数超过限制,每个实例每个库每天不超过20次上云操作。

400

ConcurrentTaskExceeded

Concurrent task exceeding the allowed amount.

上云次数超过限制,每个实例每天上云总次数不超过500次。

400

IncorrectFileExtension

The file extension does not support.

备份文件的后缀名错误。

400

InvalidOssUrl

Specified oss url is not valid.

提供的OSS下载链接地址不可用。

400

BakFileSizeExceeded

Exceeding the allowed bak file size.

数据库备份文件超过限制,最大不超过3TB。

400

FileSizeExceeded

Exceeding the allowed file size of DB instance.

还原备份文件后将超过当前实例的存储空间。

相关API

API

描述

CreateMigrateTask

OSS上的备份文件还原到RDS SQL Server实例,创建数据上云任务。

CreateOnlineDatabaseTask

打开RDS SQL Server备份数据上云任务的数据库。

DescribeMigrateTasks

查询RDS SQL Server实例备份数据上云任务列表。

DescribeOssDownloads

查询RDS SQL Server备份数据上云任务的文件详情。