定时备份redis实例并转储到OSS

本文介绍了如何利用OOS实现对Redis实例的定时备份并自动转储到OSS,以解决数据安全、运维复杂度和成本等问题。

前提条件

已开通函数计算服务,详情请参见快速创建函数

功能背景

随着企业业务数据的快速增长,Redis作为高性能的内存数据存储方案,在多种应用场景下承担着重要的角色。为确保数据安全,定时备份成为了不可或缺的一环。Redis实例定时备份是关键数据库管理任务的一个重要组成部分,它主要服务于数据的灾难恢复、历史数据查询、环境克隆等应用场景。然而,在目前的自动或手动备份中,虽然支持定时备份功能,可以根据用户的业务需求,设置备份周期进行自动备份。但此方式存在以下不足:

  1. 数据安全风险:在实例删除后,传统的定时备份无法保留备份数据,导致数据不能永久保存,存在数据丢失的风险。

  2. 运维工作繁琐:缺少自动化的备份转储机制,需要手动操作备份过程,包括下载和上传至云存储服务,这一流程不仅耗时,同时也容易出错。

  3. 运维成本增加:由于备份流程需要人工介入,过程中容易出错,需要额外的时间和资源投入,从而增加了整体的运维成本。

  4. 效率较低:在没有集中管理的备份方案前,为多个实例或跨地域实例执行备份时,效率相对偏低,管理复杂度高。

  5. 监控及告警能力不足:缺乏有效的监控和告警机制,使得备份任务的执行状态难以实时掌握,一旦出现失败或异常问题,及时响应和处理的能力受限。

针对上述不足,结合OOS的编排能力,OOS推出了定时备份Redis实例并自动转储至OSS的功能,为用户提供了一个高效、安全且自动化的备份解决方案。此方案有以下优势:

  1. 数据安全性提高:通过自动上传备份文件至OSS, 利用OSS的数据冗余存储机制, 确保硬件失效时的数据持久性和可用性;此外,及时Redis实例删除也能永久保存。

  2. 完全自动化:一旦配置完成,备份文件将自动、定时上传到OSS,无需人工干预,大大减轻了运维负担,降低了操作错误。

  3. 多实例多地域集中管理:OOS定时备份Redis任务支持一次选择多个实例。此外,OOS支持跨区域转储OSS,您可以将多个地域的Redis实例统一备份到同一OSS存储桶中。

  4. 灵活的备份策略和成本控制:用户可以根据自己的需要设置备份频率,通过OSS的生命周期管理策略,自动清理过期的备份文件,从而更有效地控制成本。

  5. 监控和告警:结合OSS和云监控,用户可以实时监控备份状态,一旦备份失败或有其他问题,可以及时收到告警,确保数据的安全性。

操作步骤

重要

此功能使用过程中可能会产生部分费用,计费详情参考Redis备份费用说明函数计算费用说明

  1. 登录OOS控制台

  2. 在左侧导航栏找到自动化任务 > 定时运维,单击创建

  3. 设置定时规则

    这里定时类型有“立即执行、仅在指定时间执行一次、周期性重复执行”三种方式。其中“立即执行”会在创建任务后立即进行重启操作,“仅在指定时间执行一次”只会在您设定的某个时间点执行一次,“周期性重复执行”则会安装一定的规则重复执行,如每一小时执行一次。

    image.png

    这里我们选择周期性重复执行,可以通过快速选择设置重复的频率,熟悉Cron表达式的同学也可以通过Cron表达式进行设置。本教程通过快速选择设置重复的频率,设置每小时执行一次,之后单击确定

  4. 搜索模板ACS-Redis-BulkyCreateBackupAndUploadToOSS,然后进行勾选。

    image.png

  5. 接下来选择要进行备份的实例,首先选择实例所在地域,然后选择目标实例,单击确定。

    image.png

    image.png

  6. 选择要转储的OSS存储桶。

    image.png

  7. 配置执行任务所需的RAM角色:

    image.png

    创建OOS编排OpenAPI角色,可参考为OOS服务设置RAM权限配置 OOS 所需的 RAM 角色并授权,权限策略如下:

    {
        "Version": "1",
        "Statement": [
            {
                "Action": [
                    "kvstore:CreateBackup",
                    "kvstore:DescribeBackupTasks",
                    "kvstore:DescribeBackups",
                    "kvstore:DescribeInstances"
                ],
                "Resource": "*",
                "Effect": "Allow"
            },
            {
                "Action": [
                    "ros:CreateStack",
                    "ros:DeleteStack",
                    "ros:GetStack"
                ],
                "Resource": "*",
                "Effect": "Allow"
            },
            {
                "Action": "oos:StartExecution",
                "Resource": "*",
                "Effect": "Allow"
            },
            {
                "Action": [
                    "fc:CreateFunction",
                    "fc:CreateService",
                    "fc:DeleteFunction",
                    "fc:DeleteService",
                    "fc:GetFunction",
                    "fc:GetService",
                    "fc:InvokeFunction"
                ],
                "Resource": "*",
                "Effect": "Allow"
            },
            {
                "Condition": {
                    "StringEquals": {
                        "acs:Service": "fc.aliyuncs.com"
                    }
                },
                "Action": "ram:PassRole",
                "Resource": "*",
                "Effect": "Allow"
            }
        ]
    }

    创建一个通过函数计算下载备份文件所需要的角色,可点击角色快捷创建配置 FC 所需的 RAM 角色(AliyunFCDefaultRole)进行快速创建。image

  8. 点击“创建”->“确定”,定时备份转储到OSS的任务就创建完成了

    image.png

  1. 查看任务执行结果

    a. 您可以等到到达您设定的触发时间来查看备份结果

    b. 点击“立即触发”来执行备份转储任务查看结果

    image.png

    此时任务会进入运行中,可通过执行日志查看任务执行进度image.png

  1. 查看转储至 OSS 中的备份文件

    等待执行状态变成“已结束”,可以点击执行ID

    image.png

    点击子执行ID

    image.png

    查看输出

    image.png

    此时登录此输出的地址就可以查看转存到OSS的备份文件了

    备份文件存储目录格式为:

    Backup_[实例 ID]/[日期 (格式为 YYYY-MM-DD)]/[OOS备份任务ID]/[备份文件名称].rdb
    • 如果实例为非集群架构,则每次备份将产生 1 个 rdb 文件

    • 如果实例为集群架构,由于每个分片将会独立备份,因此每次备份将产生与分片数量一致的 rdb 文件(例如 8 分片集群则每次产生 8 个 rdb 文件)

    • 转储至 OOS 中的备份不再有自动清理时间,可根据需要保留或删除

      image.png

附录

执行流程图

整体执行流程图:

image.png

其中创建redis备份并上传到OSS流程:image.png

模板

上述步骤中使用的模板“ACS-Redis-BulkyCreateBackupAndUploadToOSS”内容如下(模板链接):

FormatVersion: OOS-2019-06-01
Description:
  en: Create Redis backups in batches and upload them to OSS. Backing up redis and using fc to upload the backup to OSS may incur charges. For billing details, please refer to <a href='https://help .aliyun.com/zh/redis/user-guide/automatic-or-manual-backup#e606eb29c7mew'>Redis Backup Fee Instructions</a> and <a href='https://help.aliyun.com/zh/ fc/product-overview/billing-overview'>Function calculation billing instructions</a>
  zh-cn: 批量创建Redis备份并上传到OSS。备份redis和使用fc将备份上传到oss都可能会产生费用,计费详情参考<a href='https://help.aliyun.com/zh/redis/user-guide/automatic-or-manual-backup#e606eb29c7mew'>Redis备份费用说明</a>和<a href='https://help.aliyun.com/zh/fc/product-overview/billing-overview'>函数计算计费说明</a>
  name-en: ACS-Redis-BulkyCreateBackupAndUploadToOSS
  name-zh-cn: 批量创建Redis备份并上传到OSS
Parameters:
  regionId:
    Label:
      en: RegionId
      zh-cn: 地域ID
    Type: String
    AssociationProperty: RegionId
    Default: '{{ACS::RegionId}}'
  targets:
    Type: Json
    Label:
      en: TargetInstance
      zh-cn: 目标实例
    AssociationProperty: Targets
    AssociationPropertyMetadata:
      ResourceType: ALIYUN::Redis::Instance
      RegionId: regionId
  OSSRegionId:
    Label:
      en: OSSRegionId
      zh-cn: OSS Bucket所在地域ID
    Type: String
    AssociationProperty: RegionId
  OSSBucketName:
    Label:
      en: OSSBucketName
      zh-cn: OSS Bucket名称
    Type: String
    AssociationProperty: ALIYUN::OSS::Bucket::BucketName
    AssociationPropertyMetadata:
      RegionId: ${OSSRegionId}
  rateControl:
    Label:
      en: RateControl
      zh-cn: 任务执行的并发比率
    Type: Json
    AssociationProperty: RateControl
    Default:
      Mode: Concurrency
      MaxErrors: 0
      Concurrency: 10
  OOSAssumeRole:
    Label:
      en: OOSAssumeRole
      zh-cn: OOS扮演的RAM角色
    Type: String
    Default: ''
RamRole: '{{ OOSAssumeRole }}'
Tasks:
  - Name: GetInstance
    Description:
      en: Get the redis instances
      zh-cn: 获取Redis实例
    Action: ACS::SelectTargets
    Properties:
      ResourceType: ALIYUN::Redis::Instance
      RegionId: '{{ regionId }}'
      Filters:
        - '{{ targets }}'
    Outputs:
      InstanceIds:
        Type: List
        ValueSelector: Instances.Instance[].InstanceId
  - Name: CreateBackupAndUploadToOSS
    Action: ACS::Redis::CreateBackupAndUploadToOSS
    Description:
      en: Create backup and upload to OSS
      zh-cn: 创建Redis备份并上传到OSS
    Properties:
      regionId: '{{ regionId }}'
      instanceId: '{{ ACS::TaskLoopItem }}'
      OSSRegionId: '{{ OSSRegionId }}'
      OSSBucketName: '{{ OSSBucketName }}'
    Loop:
      RateControl: '{{ rateControl }}'
      Items: '{{ GetInstance.InstanceIds }}'
      Outputs:
        OSSObjectURLs:
          AggregateType: Fn::ListJoin
          AggregateField: OSSObjectURL
    Outputs:
      OSSObjectURL:
        Type: String
        ValueSelector: .OSSObjectURL + "{{ACS::ExecutionId}}/"  | split(".t0") | .[0]
Outputs:
  OSSObjectURLs:
    Type: List
    Value: '{{ CreateBackupAndUploadToOSS.OSSObjectURLs }}'

其中Action: ACS::Redis::CreateBackupAndUploadToOSS内容如下:

FormatVersion: OOS-2019-06-01
Description:
  en: Create redis backup and upload to OSS
  zh-cn: 创建Redis备份并上传到OSS
  name-en: ACS::Redis::CreateBackupAndUploadToOSS
  name-zh-cn: 创建Redis备份并上传到OSS
Parameters:
  regionId:
    Label:
      en: RegionId
      zh-cn: 地域ID
    Type: String
    AssociationProperty: RegionId
  instanceId:
    Label:
      en: InstanceId
      zh-cn: 实例ID
    Type: String
    AssociationProperty: ALIYUN::Redis::Instance::InstanceId
    AssociationPropertyMetadata:
      RegionId: ${regionId}
  OSSRegionId:
    Label:
      en: OSSRegionId
      zh-cn: OSS bucket所在地域ID
    Type: String
    AssociationProperty: RegionId
  OSSBucketName:
    Label:
      en: OSSBucketName
      zh-cn: OSS Bucket 名称
    Type: String
    AssociationProperty: ALIYUN::OSS::Bucket::BucketName
    AssociationPropertyMetadata:
      RegionId: ${OSSRegionId}
    Default: ''
Tasks:
  - Name: CreateBackup
    Action: ACS::ExecuteApi
    Description:
      en: Create backup
      zh-cn: 创建Redis备份
    Properties:
      Service: r-kvstore
      API: CreateBackup
      Parameters:
        RegionId: '{{ regionId }}'
        InstanceId: '{{ instanceId }}'
    Outputs:
      BackupJobID:
        Type: String
        ValueSelector: .BackupJobID
  - Name: WaitForBackupCreated
    Action: ACS::WaitFor
    Description:
      en: Wait for backup created
      zh-cn: 等待备份创建完成
    Retries: 30
    DelayType: Exponential
    Delay: 2
    BackOff: 2
    Properties:
      Service: r-kvstore
      API: DescribeBackupTasks
      Parameters:
        RegionId: '{{ regionId }}'
        InstanceId: '{{ instanceId }}'
        BackupJobId: '{{ CreateBackup.BackupJobID }}'
      DesiredValues:
        - Finished
      NotDesiredValues: []
      StopRetryValues: []
      PropertySelector: .BackupJobs[].BackupProgressStatus
  - Name: GetBackupDownloadUrl
    Action: ACS::ExecuteApi
    Description:
      en: Get backup download url
      zh-cn: 获取备份下载地址
    Properties:
      Service: r-kvstore
      API: DescribeBackups
      Parameters:
        RegionId: '{{ regionId }}'
        InstanceId: '{{ instanceId }}'
        BackupJobId: '{{ CreateBackup.BackupJobID }}'
        StartTime:
          Fn::FormatUTCTime:
            - Fn::AddHour:
                - '{{ ACS::CurrentUTCTime }}'
                - -1
            - '%Y-%m-%dT%H:%MZ'
        EndTime:
          Fn::FormatUTCTime:
            - '{{ ACS::CurrentUTCTime }}'
            - '%Y-%m-%dT%H:%MZ'
    Outputs:
      BackupDownloadURL:
        Type: List
        ValueSelector: .Backups.Backup[].BackupDownloadURL
  - Name: UploadBackupToOSS
    Action: ACS::FC::ExecuteScript
    Description:
      en: Upload backup to OSS
      zh-cn: 上传备份到OSS
    Properties:
      runtime: python3.10
      handler: index.handler
      role: acs:ram::{{ACS::AccountId}}:role/AliyunFcDefaultRole
      script: |-
        import oss2
        import requests

        def handler(event, context):
          auth = oss2.StsAuth(context.credentials.access_key_id, context.credentials.access_key_secret, context.credentials.security_token)
          endpoint = 'https://oss-{{OSSRegionId}}.aliyuncs.com'
          bucket = oss2.Bucket(auth, endpoint, '{{OSSBucketName}}')
          unique_identifier = '{{ACS::TaskLoopItem}}'.split('?')[0].split('/')[-1]
          execution_id = '{{ACS::ExecutionId}}'.split('.')[0]
          input = requests.get('{{ACS::TaskLoopItem}}')
          bucket.put_object(f'Backup_{{InstanceId}}/{{ACS::CurrentDate}}/{execution_id}/{unique_identifier}', input)
    Loop:
      Items: '{{ GetBackupDownloadUrl.BackupDownloadURL }}'
      RateControl:
        Mode: Concurrency
        MaxErrors: 0
        Concurrency: 20
Outputs:
  OSSObjectURL:
    Type: String
    Value: https://oss.console.aliyun.com/bucket/oss-{{OSSRegionId}}/{{OSSBucketName}}/object?path=Backup_{{InstanceId}}/{{ACS::CurrentDate}}/