从 Cloud SQL 导入到 Spanner

本页面介绍如何将数据从 Cloud SQL for MySQL 导入到 Spanner。

该过程使用控制台上的 Google Cloud Cloud Shell 运行命令,以 配置和运行 Dataflow作业,从而将数据库从 Cloud SQL 导入到 Spanner。

过程概览

导入过程涉及以下内容:

  1. 您需要完成一个 Google Cloud 控制台工作流,在其中提供有关 源数据库和目标数据库的信息:
    • 源数据库详细信息:Cloud SQL 实例名称、数据库名称、 和您的凭据。
    • Spanner 详细信息:您的 Spanner 实例 名称和数据库名称。如果数据库尚不存在,该命令会创建数据库。
    • 输出存储空间:用于存储输出文件的 Cloud Storage 存储桶名称。
  2. Spanner 会打开 Cloud Shell 并填充一个命令。该命令会执行以下操作:
    • 迁移架构:该命令使用 Spanner 迁移工具迁移架构。此迁移在 Cloud Shell 中运行,并使用公共 IP 地址连接到您的 Cloud SQL 实例。由于 Cloud Shell 位于自己的网络上,因此需要使用公共 IP 地址访问 Cloud SQL;不过,您无需针对公共 IP 地址将任何子网列入许可名单。
    • 启动数据迁移:在工具迁移架构后,该 命令会启动 Dataflow 作业以进行数据迁移。该作业通过专用 IP 地址直接从源数据库读取数据,并写入到 Spanner。此作业使用默认的 Compute Engine 服务帐号运行。最后,该命令会输出 Dataflow 作业网址。

限制

存在以下限制:

  • 此数据导入仅支持单个 Cloud SQL for MySQL 实例。
  • 架构转换是自动进行的;在此导入期间,您无法对架构进行调整。
  • 此数据导入是一次性批量加载;它不支持持续复制。

准备工作

在导入数据库之前,请完成以下前提条件:

  1. 确保您的 Cloud SQL 实例已启用公共 IP 地址和专用 IP 地址。如需了解详情,请参阅 配置公共 IP 连接配置专用 IP

  2. 为 Cloud SQL 实例创建可用于查询数据库的用户和密码。

  3. 将密码存储在 Secret Manager 中。您需要 Secret 版本的 version ID。 如需了解详情,请参阅 创建 Secret

  4. 确保您拥有 Cloud Storage 存储桶。Dataflow 使用此存储桶来存储 Dataflow 作业的配置文件和输出。

  5. 确保 Spanner 和 Cloud SQL 位于同一 Google Cloud 项目中。

  6. 启用 Dataflow、Cloud Storage、Spanner、Cloud SQL 和 Secret Manager API。

    启用 API 所需的角色

    如需启用 API,您需要拥有 Service Usage Admin IAM 角色 (roles/serviceusage.serviceUsageAdmin),该角色包含 serviceusage.services.enable 权限。了解如何授予 角色

    启用 API

所需角色

为确保默认的 Compute Engine 服务帐号具有运行 Dataflow 作业所需的 权限, 请让您的管理员向默认的 Compute Engine 服务帐号授予项目的以下 IAM 角色:

如需获取配置导入所需的权限,请让您的管理员向您授予项目的以下 IAM 角色:

这些预定义角色包含 配置导入所需的权限。如需查看所需的确切权限,请展开所需权限部分:

所需权限

配置导入需要以下权限:

  • cloudsql.instances.connect
  • cloudsql.instances.get
  • cloudsql.instances.login
  • spanner.instances.list
  • spanner.instances.get
  • spanner.databases.create
  • spanner.databases.list
  • spanner.databases.get
  • spanner.databases.getDdl
  • spanner.databases.updateDdl
  • spanner.databases.read
  • spanner.databases.write
  • spanner.databases.select
  • secretmanager.versions.access
  • storage.objects.create
  • storage.objects.get
  • storage.buckets.get
  • dataflow.jobs.create
  • dataflow.jobs.get
  • dataflow.jobs.list
  • iam.serviceAccounts.actAs

配额要求

配额要求如下:

  • Spanner:您必须拥有足够多的计算容量 来支持您要导入的数据量。我们建议您至少从一个 Spanner 节点开始。您可能需要增加更多计算容量,以便在合理的时间内完成作业。 导入数据库架构不需要额外的计算容量。 如需了解详情,请参阅 自动扩缩概览
  • Dataflow:导入作业与其他 Dataflow 作业具有相同的 CPU、 磁盘用量和 IP 地址 Compute Engine 配额
  • Compute Engine:在运行导入作业之前,必须 设置初始配额,以供 Dataflow 使用。这些配额表示允许 Dataflow 针对作业使用的资源用量上限。 建议使用以下初始值:

    • CPU 数:200
    • 使用中的 IP 地址数:200
    • 标准永久性磁盘:50 TB

    通常情况下,您不必进行其他调整。Dataflow 提供自动扩缩功能,因此您只需支付导入期间实际使用的资源费用。如果您的作业可能会使用更多资源,Dataflow 界面会显示警告图标。出现警告图标不会影响作业的完成。

从 Cloud SQL 导入到 Spanner

如需将 Cloud SQL for MySQL 数据库导入到 Spanner,请在 控制台中执行以下 Google Cloud 操作:

  1. 前往 Spanner 实例 页面。

    转到实例页面

  2. 点击需要导入数据库的实例的名称。

  3. 点击 Import from Cloud SQL (从 Cloud SQL 导入)按钮。

  4. 在 Spanner 验证所有必需的 API 是否已启用后,点击 Next (下一步)按钮。

  5. 选择要导入的 Cloud SQL for MySQL 实例,然后点击 Next (下一步)按钮。

  6. 选择要导入的数据库,然后点击 Next (下一步)按钮。 Spanner 会验证是否已为 Cloud SQL 实例启用公共 IP。

  7. 输入用户名和 Secret,然后点击 Next (下一步)按钮。

  8. 浏览并选择 Cloud Storage 存储桶,然后点击 Next (下一步)按钮。

  9. 输入 Spanner 数据库名称,然后点击 Import (导入)按钮。Spanner 会打开 Cloud Shell 并填充一个命令。

  10. 运行自动填充的命令以开始导入:

    export SOURCE_PROJECT_NUMBER=$(gcloud projects describe \
        "SOURCE_PROJECT_ID" \
        --format="value(projectNumber)") && \
    export GSA_EMAIL="${SOURCE_PROJECT_NUMBER}-compute@developer.gserviceaccount.com" && \
    echo "Verifying permissions for ${GSA_EMAIL}..." && \
    export CURRENT_ROLES=$(gcloud projects get-iam-policy \
        "SOURCE_PROJECT_ID" \
        --flatten="bindings[].members" \
        --filter="bindings.members:serviceAccount:${GSA_EMAIL}" \
        --format="value(bindings.role)") && \
    ERR=0 && \
    for ROLE in roles/secretmanager.secretAccessor \
        roles/cloudsql.client roles/spanner.databaseAdmin \
        roles/storage.objectAdmin roles/dataflow.worker; do \
      if echo "${CURRENT_ROLES}" | awk -v r="$ROLE" '$1 == r {found=1} END {exit 1-found}'; then \
        echo "[OK] $ROLE"; \
      else \
        echo "[MISSING] $ROLE. Run: gcloud projects add-iam-policy-binding SOURCE_PROJECT_ID --member='serviceAccount:${GSA_EMAIL}' --role='${ROLE}'"; \
        ERR=1; \
      fi; \
    done && \
    [[ "$ERR" -eq 0 ]] && \
    export JOB_NAME="csql-to-spanner-$(date +%Y%m%d-%H%M%S)" && \
    export OUTPUT_DIR="gs://BUCKET_NAME/output/${JOB_NAME}" && \
    export SHARD_CONFIG_PATH="gs://BUCKET_NAME/config/${JOB_NAME}_shard_config.json" && \
    export WORKER_MACHINE_TYPE="n2-highmem-8" && \
    export TEMPLATE_PATH="gs://dataflow-templates/latest/flex/Sourcedb_to_Spanner_Flex" && \
    export SHARD_CONFIG_JSON='{
      "shardConfigurationBulk": {
        "dataShards": [
          {
            "host": "SOURCE_PRIVATE_IP",
            "port": "3306",
            "user": "SOURCE_DATABASE_USER",
            "secretManagerUri": "projects/PROJECT_ID/secrets/SECRET_ID/versions/VERSION",
            "databases": [
              {
                "dbName": "SOURCE_DATABASE_NAME",
                "databaseId": "SOURCE_DATABASE_NAME"
              }
            ]
          }
        ]
      }
    }' && \
    echo "${SHARD_CONFIG_JSON}" | gcloud storage cp - "${SHARD_CONFIG_PATH}" && \
    sudo apt-get update && \
    sudo apt-get install google-cloud-cli-spanner-migration-tool -y && \
    gcloud alpha spanner migrate schema \
        --source=mysql \
        --source-profile="project=SOURCE_PROJECT_ID,instance=SOURCE_INSTANCE_NAME,secretManagerUri=projects/PROJECT_ID/secrets/SECRET_ID/versions/VERSION,dbName=SOURCE_DATABASE_NAME,region=SOURCE_REGION,user=SOURCE_DATABASE_USER" \
        --target-profile="instance=SPANNER_INSTANCE_ID,project=SPANNER_PROJECT_ID,dbName=SPANNER_DATABASE_ID" && \
    JOB_OUTPUT=$(gcloud dataflow flex-template run "${JOB_NAME}" \
        --project="SOURCE_PROJECT_ID" \
        --region="SOURCE_REGION" \
        --template-file-gcs-location="${TEMPLATE_PATH}" \
        --network="NETWORK_NAME" \
        --subnetwork="https://www.googleapis.com/compute/v1/projects/SOURCE_PROJECT_ID/regions/SOURCE_REGION/subnetworks/SUBNETWORK_NAME" \
        --worker-machine-type="${WORKER_MACHINE_TYPE}" \
        --parameters "instanceId=SPANNER_INSTANCE_ID" \
        --parameters "databaseId=SPANNER_DATABASE_ID" \
        --parameters "projectId=SPANNER_PROJECT_ID" \
        --parameters "sourceConfigURL=${SHARD_CONFIG_PATH}" \
        --parameters "sourceDbDialect=MYSQL" \
        --parameters "jdbcDriverClassName=com.mysql.jdbc.Driver" \
        --parameters "outputDirectory=${OUTPUT_DIR}" \
        --format="get(job.id)") && \
    echo "--------------------------------------------------------" && \
    echo "Dataflow Job Submitted." && \
    echo "Monitor: https://console.cloud.google.com/dataflow/jobs/SOURCE_REGION/${JOB_OUTPUT}?project=SOURCE_PROJECT_ID" && \
    echo "--------------------------------------------------------"
    

    以下参数从 Google Cloud 控制台提供给 该命令:

    • SOURCE_DATABASE_NAME:源 Cloud SQL 数据库的名称
    • SOURCE_DATABASE_USER:源 Cloud SQL 数据库的用户名
    • PROJECT_ID:您的 Google Cloud 项目 ID
    • SECRET_ID:包含密码的 Secret 的 ID
    • VERSION:Secret 的版本
    • SOURCE_PROJECT_ID:包含源 Cloud SQL 实例的项目 ID
    • SOURCE_REGION:源 Cloud SQL 实例的区域
    • SOURCE_INSTANCE_NAME:源 Cloud SQL 实例的名称
    • SOURCE_PRIVATE_IP:Cloud SQL 实例的专用 IP 地址
    • NETWORK_NAME:源 Cloud SQL 实例的网络名称
    • SUBNETWORK_NAME:源 Cloud SQL 实例的子网名称
    • SPANNER_PROJECT_ID:包含目标 Spanner 实例的项目 ID
    • SPANNER_INSTANCE_ID:目标 Spanner 实例的 ID
    • SPANNER_DATABASE_ID:目标 Spanner 数据库的 ID,如果该数据库不存在,Spanner 会创建它
    • BUCKET_NAME:用于存储 Dataflow 输出文件和配置文件的 Cloud Storage 存储桶的名称

    该命令会验证默认的 Compute 服务帐号是否具有所需的权限,安装 Spanner 迁移工具,迁移架构,并启动 Dataflow 作业。

    该命令完成后,点击提供的链接以在控制台中监控 Dataflow 作业。 Google Cloud

后续步骤