使用 Cloud Scheduler 安排 Memorystore for Redis 数据库导出

Last reviewed 2023-03-18 UTC

本教程介绍如何使用 Cloud SchedulerCloud Functions,自动将 Memorystore for Redis 数据库导出到 Cloud Storage。通过将数据库导出到 Cloud Storage,您可以创建可靠且多样的灾难恢复计划。例如,您可以导出到其他地区,并导入到其他 Memorystore for Redis 实例。

架构

本教程涉及以下 Google Cloud 组件:

Cloud Scheduler 作业在 Pub/Sub 主题上发布一条消息,其中包含有关 Memorystore 实例 ID、项目 ID、它所在的地区以及用于存储备份的 Cloud Storage 位置的信息。此事件会触发 Cloud Functions 函数,该函数获取此载荷并通过其 API 在 Memorystore for Redis 上启动数据库导出。数据库会生成导出并将其保存到 Cloud Storage。下图展示了此工作流。

从 Cloud Scheduler 到 Pub/Sub 的工作流,该工作流会触发启动导出的 Cloud Functions 函数。

目标

费用

在本文档中,您将使用 Google Cloud 的以下收费组件:

您可使用价格计算器根据您的预计使用情况来估算费用。 Google Cloud 新用户可能有资格申请免费试用

完成本文档中描述的任务后,您可以通过删除所创建的资源来避免继续计费。如需了解详情,请参阅清理

准备工作

  1. 在 Google Cloud Console 中的项目选择器页面上,选择或创建一个 Google Cloud 项目

    转到“项目选择器”

  2. 确保您的 Google Cloud 项目已启用结算功能

  3. 在 Google Cloud 控制台中,激活 Cloud Shell。

    激活 Cloud Shell

  4. 启用 Memorystore for Redis, Cloud Functions, Cloud Scheduler, and Cloud Build API。

    启用 API

在本教程中,您将通过 Cloud Shell 运行所有命令。

设置环境

首先,先配置环境,然后创建具有本教程所需权限的自定义角色。

  1. 在 Cloud Shell 中,配置以下环境变量:

    export PROJECT_ID=`gcloud config get-value project`
    export DEMO="mem-exporter"
    export BUCKET_NAME=${USER}-mem-$(date +%s)
    export MEM_INSTANCE="${DEMO}-instance"
    export FUNCTION_NAME="${DEMO}-gcf"
    export PUBSUB_TOPIC="${DEMO}-topic"
    export SCHEDULER_JOB="${DEMO}-job"
    export MEM_EXPORT_ROLE="memExporter"
    export STORAGE_ROLE="simpleStorageRole"
    export REGION="us-central1"
    
  2. 创建两个仅具有本教程所需权限的自定义角色:

    gcloud iam roles create ${STORAGE_ROLE} --project=${PROJECT_ID} \
        --title="Simple Storage Role" \
        --description="Grant permissions to view and create objects in Cloud Storage" \
        --permissions="storage.objects.create,storage.buckets.get"
    
    gcloud iam roles create ${MEM_EXPORT_ROLE} --project=${PROJECT_ID} \
        --title="Memorystore Exporter Role" \
        --description="Grant permissions to export data from a Memorystore instance to a Cloud Storage bucket" \
        --permissions="redis.instances.export"
    

    这些角色可以缩小 Cloud Functions 和 Memorystore 服务账号的访问权限范围,从而遵循最小权限原则

创建 Cloud Storage 存储桶和 Memorystore 实例

在本部分中,先创建 Cloud Storage 存储分区和 Memorystore for Redis 实例。然后,使用示例数据填充 Memorystore。

创建 Cloud Storage 存储分区

您将使用 gsutil 命令行工具创建 Cloud Storage 存储分区。

  • 在您要保存数据导出的位置创建 Cloud Storage 存储分区:

    gsutil mb -l ${REGION} gs://${BUCKET_NAME}
    

创建 Memorystore 实例并向其服务账号授予权限

接下来,创建 Memorystore 实例并向其服务账号授予将数据导出到 Cloud Storage 的权限。

  1. 创建一个 Memorystore for Redis 4 实例:

    gcloud redis instances create ${MEM_INSTANCE} --size=1 --region=${REGION}
    

    此操作需要几分钟时间才能完成。

  2. 验证 Memorystore 实例是否为 READY

    gcloud redis instances list --region=${REGION}
    

    输出类似于以下内容:

    INSTANCE_NAME   VERSION    REGION       TIER   SIZE_GB  HOST          PORT  NETWORK  RESERVED_IP      STATUS  CREATE_TIME
    redis-instance  REDIS_4_0  us-central1  BASIC  1        10.61.20.131  6379  default  10.61.20.128/29  READY   2020-04-23T18:38:54
    
  3. 使用您之前创建的自定义 Simple Storage 角色向您的 Memorystore 服务账号授予将数据导出到 Cloud Storage 的权限:

    export MEM_SA=$(gcloud redis instances describe ${MEM_INSTANCE} --region ${REGION} \
        --project ${PROJECT_ID} \
        --format "value(persistenceIamIdentity)")
    
    gsutil iam ch ${MEM_SA}:projects/${PROJECT_ID}/roles/${STORAGE_ROLE} gs://${BUCKET_NAME}
    

创建计划的数据导出任务

在本部分中,您将创建一个自定义服务账号并将其绑定到您创建的自定义 Redis 角色。然后,您将创建一个用于触发 Cloud Functions 函数执行的 Pub/Sub 主题。您还将创建一个 Cloud Scheduler 作业以定期执行数据导出函数。

为 Cloud Functions 函数创建服务账号

第一步是创建服务账号并将其绑定到角色。

  1. 创建 Cloud Functions 函数要使用的 IAM 服务账号并将其保存到变量中:

    gcloud iam service-accounts create ${FUNCTION_NAME} \
        --display-name="Service Account for GCF and Memorystore"
    
    export GCF_SA=$(gcloud iam service-accounts list --filter="${FUNCTION_NAME}" --format="value(email)")
    
  2. 向服务账号授予访问自定义 Memorystore Exporter 角色的权限,使其能够请求 Memorystore 导出:

    gcloud projects add-iam-policy-binding ${PROJECT_ID} \
        --member="serviceAccount:${GCF_SA}" \
        --role="projects/${PROJECT_ID}/roles/${MEM_EXPORT_ROLE}"
    
  3. 向服务账号授予自定义 Simple Storage 角色的访问权限

    gsutil iam ch \
        serviceAccount:${GCF_SA}:projects/${PROJECT_ID}/roles/${STORAGE_ROLE} \
        gs://${BUCKET_NAME}
    

创建 Pub/Sub 主题

下一步是创建一个 Pub/Sub 主题,用于触发与 Memorystore 数据库交互的 Cloud Functions 函数。

  • 创建 Pub/Sub 主题:

    gcloud pubsub topics create ${PUBSUB_TOPIC}
    

创建 Cloud Functions 函数

接下来,您将创建 Cloud Functions 函数。

  1. 为 Cloud Functions 函数代码创建文件夹:

    mkdir scheduler_gcf_code && cd scheduler_gcf_code
    
  2. 通过将以下内容粘贴到 Cloud Shell 中来创建 main.py 文件:

    cat <<EOF  > main.py
    
    import base64
    import logging
    import json
    
    from datetime import datetime
    from httplib2 import Http
    
    from googleapiclient import discovery
    from googleapiclient.errors import HttpError
    from oauth2client.client import GoogleCredentials
    
    def main(event, context):
        pubsub_message = json.loads(base64.b64decode(event['data']).decode('utf-8'))
        credentials = GoogleCredentials.get_application_default()
    
        service = discovery.build('redis', 'v1beta1', http=credentials.authorize(Http()), cache_discovery=False)
    
        datestamp = datetime.now().strftime("%Y%m%d%H%M") # format timestamp: YearMonthDayHourMinute
        instance_name=pubsub_message['name'].split("/")[-1]
        uri = f"{pubsub_message['gs']}/backup-{instance_name}-{datestamp}.rdb"
    
        request_body = {
            "outputConfig": {
                "gcsDestination" : {
                    "uri": uri
                }
            }
        }
    
        try:
            request = service.projects().locations().instances().export(
                name=pubsub_message['name'],
                body=request_body
            )
    
            response = request.execute()
        except HttpError as err:
            logging.error(f"Could NOT run backup. Reason: {err}")
        else:
            logging.info(f"Backup task status: {response}")
    EOF
    
  3. 通过将以下内容粘贴到 Cloud Shell 中来创建 requirements.txt 文件:

    cat <<EOF > requirements.txt
    
    google-api-python-client
    Oauth2client
    EOF
    
  4. 部署代码。

    gcloud functions deploy ${FUNCTION_NAME} \
        --trigger-topic=${PUBSUB_TOPIC} \
        --runtime=python37 \
        --entry-point=main \
        --service-account=${FUNCTION_NAME}@${PROJECT_ID}.iam.gserviceaccount.com \
        --ingress-settings=internal-and-gclb
    

创建 Cloud Scheduler 作业

最后,您将创建一个 Cloud Scheduler 作业以定期执行数据导出函数。

  1. 将 Memorystore 完整名称保存到变量中:

    export MEM_NAME=$(gcloud redis instances describe ${MEM_INSTANCE} --region ${REGION} --format "value(name)")
    
  2. 创建一个 Cloud Scheduler 作业以定期执行数据导出函数:

    gcloud scheduler jobs create pubsub ${SCHEDULER_JOB} \
        --schedule='0 23 * * *' --topic=${PUBSUB_TOPIC} \
        --message-body='{"name":'\"${MEM_NAME}\"',"gs":'\"gs://${BUCKET_NAME}\"'}' \
        --time-zone='America/Los_Angeles' --location=${REGION}
    

    此作业安排在每天晚上 11 点(太平洋时间)运行。

    消息正文包含要导出的 Memorystore 实例的名称,以及目标 Cloud Storage 存储桶。

测试您的解决方案

最后一步是测试您的解决方案。首先,您需要运行 Cloud Scheduler 作业。

  1. 手动运行 Cloud Scheduler 作业以触发数据库的 Memorystore 导出。

    gcloud scheduler jobs run ${SCHEDULER_JOB} --location=${REGION}
    
  2. 列出在 Memorystore 实例上执行的操作,并验证是否存在类型为 EXPORT 的操作:

    gcloud redis operations list --region=${REGION} --filter="${MEM_INSTANCE}"
    

    以下输出示例显示 DONE 状态为 True 的导出作业,以指示其已完成。如果 DONE 状态显示 False,则表示作业仍在处理;请等待一分钟,然后重新运行上一个命令。

    OPERATION_NAME                                           REGION       TYPE    TARGET                 DONE  CREATE_TIME          DURATION
    operation-1592329364987-5a837122a600c-b22c2703-5077c6b7  us-central1  export  mem-exporter-instance  True  2020-06-16T17:42:45  16S
    
  3. 检查 Cloud Storage 存储分区,以查看导出文件是否已创建:

    gsutil ls -l gs://${BUCKET_NAME}/*.rdb
    

    您会看到一个名为 backup-INSTANCE_NAME-TIMESTAMP.rdb 的文件。

清理

您可以按照以下步骤操作,以避免系统因本教程中使用的资源而向您的 Google Cloud 账号收取费用。为避免支付费用,最简单的方法是删除您为本教程创建的项目。

  1. 在 Google Cloud 控制台中,进入管理资源页面。

    转到“管理资源”

  2. 在项目列表中,选择要删除的项目,然后点击删除
  3. 在对话框中输入项目 ID,然后点击关闭以删除项目。

后续步骤