功能背景
随着企业业务数据的快速增长,Redis 作为高性能的内存数据存储方案,在多种应用场景下承担着重要的角色。为确保数据安全,定时备份成为了不可或缺的一环。Redis 实例定时备份是关键数据库管理任务的一个重要组成部分,它主要服务于数据的灾难恢复、历史数据
查询、环境克隆等应用场景。
然而,在目前的 Redis 的备份方案中,虽然支持定时备份功能,可以根据用户的业务需求,设置备份周期进行自动备份。但此方式存在以下不足:
- 数据安全风险:在实例删除后,传统的定时备份无法保留备份数据,导致数据不能永久保存,存在数据丢失的风险。
- 运维工作繁琐:缺少自动化的备份转储机制,需要手动操作备份过程,包括下载和上传至云存储服务,这一流程不仅耗时,同时也容易出错。
- 运维成本增加:由于备份流程需要人工介入,过程中容易出错,需要额外的时间和资源投入,从而增加了整体的运维成本。
- 效率较低:在没有集中管理的备份方案前,为多个实例或跨地域实例执行备份时,效率相对偏低,管理复杂度高。
- 监控及告警能力不足:缺乏有效的监控和告警机制,使得备份任务的执行状态难以实时掌握,一旦出现失败或异常问题,及时响应和处理的能力受限。
针对上述不足,结合 OOS 的编排能力,OOS 推出了定时备份 Redis 实例并自动转储至 OSS 的功能,为用户提供了一个高效、安全且自动化的备份解决方案。
此方案有以下优势:
- 数据安全性提高:通过自动上传备份文件至 OSS , 利用 OSS 的数据冗余存储机制, 确保硬件失效时的数据持久性和可用性;此外,及时 Redis 实例删除也能永久保存。
- 完全自动化:一旦配置完成,备份文件将自动、定时上传到 OSS,无需人工干预,大大减轻了运维负担,降低了操作错误。
- 多实例多地域集中管理:OOS 定时备份 Redis 任务支持一次选择多个实例。此外,OOS 支持跨区域转储 OSS,您可以将多个地域的 Redis 实例统一备份到同一 OSS 存储桶中。
- 灵活的备份策略和成本控制:用户可以根据自己的需要设置备份频率,通过 OSS 的生命周期管理策略,自动清理过期的备份文件,从而更有效地控制成本。
- 监控和告警:结合 OSS 和云监控,用户可以实时监控备份状态,一旦备份失败或有其他问题,可以及时收到告警,确保数据的安全性。
操作步骤
注意事项:
此功能使用过程中可能会产生部分费用,计费详情参考 Redis 备份费用说明和函数计算计费说明
-
登录 OOS 控制台。
-
在左侧导航栏找到 "自动化任务-定时运维 ",单击创建。
-
设置定时规则 。这里定时类型有 "立即执行、仅在指定时间执行一次、周期性重复执行" 三种方式。其中 "立即执行" 会在创建任务后立即进行重启操作, "仅在指定时间执行一次" 只会在您设定的某个时间点执行一次, "周期性重复执行" 则会按照一定的规则重复执行,如每一小时执行一次。
这里我们选择 "周期性重复执行 ",可以通过 "快速选择 " 设置重复的频率,熟悉 cron 表达式的同学也可以通过 cron 表达式进行设置。本教程通过 "快速选择" 设置重复的频率,设置每小时执行一次,之后单击确定 。
设置定时任务的结束时间。
-
搜索模板 "ACS-Redis-BulkyCreateBackupAndUploadToOSS",然后进行勾选。
-
接下来选择要进行备份的实例,首先选择实例所在地域,然后选择目标实例,点击确定。
-
选择要转储的 OSS 存储桶。
-
配置执行任务所需的 RAM 角色:
-
创建 OOS 编排 OpenAPI 角色,可参考《为 OOS 服务设置 RAM 权限》配置 OOS 所需的 RAM 角色并授权,权限策略如下:
json{ "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)进行快速创建。
-
-
点击 "创建" -> "确定",定时备份转储到 OSS 的任务就创建完成了。
-
查看任务执行结果:
a. 您可以等到到达您设定的触发时间来查看备份结果。
b. 点击 "立即触发" 来执行备份转储任务查看结果。
此时任务会进入运行中,可通过执行日志查看任务执行进度。
-
查看转储至 OSS 中的备份文件:
等待执行状态变成 "已结束",可以点击执行 ID。
点击子执行 ID。
查看输出。
此时登录此输出的地址就可以查看转存到 OSS 的备份文件了。
备份文件存储目录格式为:
Backup_[实例 ID]/[日期(格式为 YYYY-MM-DD)]/[OOS 备份任务 ID]/[备份文件名称].rdb`
- 如果实例为非集群架构,则每次备份将产生 1 个 rdb 文件。
- 如果实例为集群架构,由于每个分片将会独立备份,因此每次备份将产生与分片数量一致的 rdb 文件(例如 8 分片集群则每次产生 8 个 rdb 文件)。
- 转储至 OSS 中的备份不再有自动清理时间,可根据需要保留或删除。
附录
执行流程图
整体执行流程图:
其中创建redis备份并上传到OSS流程:
模板
上述步骤中使用的模板"ACS-Redis-BulkyCreateBackupAndUploadToOSS"内容如下(模板链接):
yaml
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内容如下:
yaml
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}}/
👍 点赞 - 您的支持是我持续创作的最大动力!
⭐️ 收藏 - 您的关注是我前进的明灯!
✏️ 评论 - 您的反馈是我成长的宝贵资源!