上传用户自动备份数据
本文介绍在使用数据灾备(DBS)的用户自动备份功能进行备份上云时,如何将本地备份文件上传到对应数据源中。本文包含上传所需完整脚本以及脚本内容讲解。
准备工作
使用限制
目前仅支持MySQL 5.5版本的数据源。
环境依赖
命令工具:Bash、Python3。
Python相关:oss2、alibabacloud_openapi_util、alibabacloud_tea_openapi、alibabacloud_tea_util。
## 安装阿里云OpenAPI SDK
pip3 install --upgrade pip
pip3 install -i https://mirrors.aliyun.com/pypi/simple/ oss2 alibabacloud_openapi_util alibabacloud_tea_openapi alibabacloud_tea_util
Bash脚本处理流程
配置阿里云AccessKeyId和AccessKeySecret、DBS OpenAPI Endpoint,以及对应的数据源ID。
#!/bin/bash ## 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维 ## 强烈建议不要把 AccessKey 和 AccessKeySecret 保存到代码里,会存在密钥泄漏风险,您可以根据业务需要,保存到配置文件里 AK=<ALIBABA_CLOUD_ACCESS_KEY_ID> SK=<ALIBABA_CLOUD_ACCESS_KEY_SECRET> DBS_API=dbs-api.<您的数据源所在地域ID,例如cn-hangzhou>.aliyuncs.com DATASOURCE_ID=<您的数据源ID>
执行xtrabackup备份命令,将备份数据保存到指定的目录,同时将错误日志输出到xtrabackup.log文件中。
## 获取脚本当前路径 BASE_PATH=$(cd `dirname $0`; pwd) TS=`date +%Y%m%d_%H%M%S` XTRA_DATA_DIR=~/tool/xtrabackup_data/$TS mkdir -p $XTRA_DATA_DIR ## 执行xtrabackup备份命令,将错误日志输出的到xtrabackup.log文件 ~/innobackupex --defaults-file=/etc/my.cnf --user='<您的数据库账号,例如root>' --password='<您的数据库密码,例如root>' --host='<您的数据库IP,例如localhost>' --port=<您的数据库端口号,例如3306> --socket='/var/lib/mysql/mysql.sock' --parallel=4 $XTRA_DATA_DIR/ 2>$XTRA_DATA_DIR/xtrabackup.log
后续将解析xtrabackup.log文件获得全量备份集的元数据信息:备份开始时间、备份结束时间、一致性时间点、对应Binlog名称。
限制说明:
当前执行xtrabackup备份命令,暂不支持压缩和加密参数(--compress --compress-threads和--encrypt --encrypt-key-file --encrypt-threads),使用xtrabackup备份命令时请先删除对应的参数。
将文件目录形式的全量备份数据进行gzip压缩和打包成tar.gz格式的文件。
## 获取当前xtrabackup备份的目录 backup_dir=`ls $XTRA_DATA_DIR | grep -v xtrabackup.log | head -n1` echo -e "\033[33mexecute innobackupex success, backup_dir: $backup_dir" && echo -n -e "\033[0m" && chmod 755 $XTRA_DATA_DIR/$backup_dir ## 打包成tar.gz文件 cd $XTRA_DATA_DIR/$backup_dir && tar -czvf ../$backup_dir.tar.gz . && file ../$backup_dir.tar.gz echo -e "\033[33mpackage to $backup_dir.tar.gz" && echo -n -e "\033[0m" && sleep 2
限制说明:当前仅支持文件格式的备份数据上传,支持如下格式:
tar:目录文件进行tar打包。
tar.gz:目录文件进行tar打包,然后进行gzip压缩。
注意事项:
使用tar命令打包前,需要chmod 755命令修改文件目录权限。
需进入文件夹根目录,进行tar命令的打包和压缩。
调用Python脚本upload_and_register_backup_set.py进行备份数据的上传,同时注册备份集元数据。
## 调用Python脚本进行上传备份数据,并注册备份集元数据 python3 $BASE_PATH/upload_and_register_backup_set.py --access_key_id $AK --access_key_secret $SK --endpoint $DBS_API --datasource_id $DATASOURCE_ID --region_code=cn-hangzhou --data_type=FullBackup --file_path=$XTRA_DATA_DIR/$backup_dir.tar.gz --xtrabackup_log_path=$XTRA_DATA_DIR/xtrabackup.log
参数
说明
--access_key_id
阿里云AccessKeyId。
--access_key_secret
阿里云AccessKeySecret。
--endpoint
DBS OpenAPI对应的Endpoint。请参见服务接入点。
--datasource_id
DBS对应的数据源ID。
--region_code
对应地域信息。
--data_type
备份数据类型,全量备份集:FullBackup,日志备份:LogBackup。
--file_path
全量备份数据路径。
--xtrabackup_log_path
全量备份xtrabackup命令产生的xtrabackup.log文件路径。
Python脚本处理流程
main函数主入口:
根据data_type传参为FullBackug或者LogBackup,分别构造元数据注册依赖的extra_meta信息:
说明BINLOG_FILE:对应Binlog名称。
dataBegin:备份开始时间,毫秒级别时间戳。
dataEnd:备份结束时间,毫秒级别时间戳。
consistentTime:一致性时间点,秒级时间戳。
全量备份extra_meta格式:
{ 'BINLOG_FILE':'mysql-bin.001', 'version':'5.5', 'dataBegin':17274********, 'dataEnd':17274********, 'consistentTime':17274******** }
日志备份extra_meta格式:
{ 'dataBegin':17274********, 'dataEnd':17274******** }
调用OssUploader.upload_and_register_backup_set方法进行备份数据上传和元数据注册。
if __name__ == '__main__': args = init_command_args() uploader = OssUploader(args.access_key_id, args.access_key_secret, args.endpoint, args.region_code, args.datasource_id) # 全量和日志备份分别通过不同方式构造extraMeta extra_meta = '{}' if args.data_type == 'FullBackup': obj = {} if args.xtrabackup_log_path is not None: obj = xtrabackup_log_parser.analyze_slave_status(logpath=args.xtrabackup_log_path) elif args.xtrabackup_info_path is not None: parser = xtrabackup_info_parser.ExtraMetaParser(file_path=args.xtrabackup_info_path) obj = parser.get_extra_meta() extra_meta = {'BINLOG_FILE': obj.get('BINLOG_FILE'), 'version': obj.get("SERVER_VERSION"), 'dataBegin': date_to_unix_timestamp(obj.get("START_TIME")), 'dataEnd': date_to_unix_timestamp(obj.get("END_TIME")), 'consistentTime': int(date_to_unix_timestamp(obj.get("END_TIME")) / 1000)} extra_meta = json.dumps(extra_meta) elif args.data_type == 'LogBackup': obj = {'dataBegin': date_to_unix_timestamp(args.begin_time), 'dataEnd': date_to_unix_timestamp(args.end_time)} extra_meta = json.dumps(obj) print(f"get extra meta json string: {extra_meta}") # 上传数据,并注册备份集元信息 uploader.upload_and_register_backup_set(file_path=args.file_path, data_type=args.data_type, extra_meta=extra_meta)
OssUploader.upload_and_register_backup_set方法备份数据上传流程。
class OssUploader: def __init__(self, access_key_id, access_key_secret, endpoint, region_code, datasource_id): self.access_key_id = access_key_id self.access_key_secret = access_key_secret self.endpoint = endpoint self.region_code = region_code self.datasource_id = datasource_id config = open_api_models.Config(access_key_id, access_key_secret) # Endpoint 请参考 https://api.aliyun.com/product/Rds config.endpoint = endpoint self.client = OpenApiClient(config) """ 注册备份集元数据 """ def configure_backup_set_info(self, req_param): params = open_api_models.Params( # 接口名称, action='ConfigureBackupSetInfo', # 接口版本, version='2021-01-01', # 接口协议, protocol='HTTPS', # 接口 HTTP 方法, method='POST', auth_type='AK', style='RPC', # 接口 PATH, pathname='/', # 接口请求体内容格式, req_body_type='json', # 接口响应体内容格式, body_type='json' ) # runtime options runtime = util_models.RuntimeOptions() request = open_api_models.OpenApiRequest( query=OpenApiUtilClient.query(req_param) ) # 返回值为 Map 类型,可从 Map 中获得三类数据:响应体 body、响应头 headers、HTTP 返回的状态码 statusCode。 print(f"ConfigureBackupSetInfo request: {req_param}") data = self.client.call_api(params, request, runtime) print(f"ConfigureBackupSetInfo response: {data}") return data['body']['Data'] """ 获取oss上传信息 """ def describe_bak_datasource_storage_access_info(self, req_param): params = open_api_models.Params( # 接口名称, action='DescribeBakDataSourceStorageAccessInfo', # 接口版本, version='2021-01-01', # 接口协议, protocol='HTTPS', # 接口 HTTP 方法, method='POST', auth_type='AK', style='RPC', # 接口 PATH, pathname='/', # 接口请求体内容格式, req_body_type='json', # 接口响应体内容格式, body_type='json' ) # runtime options runtime = util_models.RuntimeOptions() request = open_api_models.OpenApiRequest( query=OpenApiUtilClient.query(req_param) ) # 返回值为 Map 类型,可从 Map 中获得三类数据:响应体 body、响应头 headers、HTTP 返回的状态码 statusCode。 print(f"DescribeBakDataSourceStorageAccessInfo request: {req_param}") data = self.client.call_api(params, request, runtime) print(f"DescribeBakDataSourceStorageAccessInfo response: {data}") return data['body']['Data'] def _fetch_oss_access_info(self, params): info = self.describe_bak_datasource_storage_access_info({ 'RegionId': params['RegionId'], 'DataSourceId': params['DataSourceId'], 'RegionCode': params['RegionCode'], 'BackupType': params['BackupType'], 'BackupSetId': params['BackupSetId'] }) return info['OssAccessInfo'] def upload_and_register_backup_set(self, file_path, data_type, extra_meta): filename = os.path.basename(file_path) params = {'BackupMode': 'Automated', 'BackupMethod': 'Physical', 'RegionId': self.region_code, 'RegionCode': self.region_code, 'DataSourceId': self.datasource_id, 'BackupSetName': filename, 'ExtraMeta': extra_meta, 'BackupType': data_type, 'UploadStatus': 'WaitingUpload'} # 首次注册备份集,返回备份集ID data = self.configure_backup_set_info(params) params['BackupSetId'] = data['BackupSetId'] print(f"------ configure_backup_set_info success: {file_path}, {data_type}, {params['BackupSetId']}, WaitingUpload\n") # 上传数据到oss oss_info = self._fetch_oss_access_info(params) oss_client = create_oss_client(oss_info) upload_oss_file(oss_client, file_path, oss_info['ObjectKey']) print(f"------ upload_oss_file success: {file_path}, {data_type}, {params['BackupSetId']}\n") # 标记备份集上传完成 params['UploadStatus'] = 'UploadSuccess' self.configure_backup_set_info(params) print(f"------ configure_backup_set_info success: {file_path}, {data_type}, {params['BackupSetId']}, UploadSuccess\n")
完整上传脚本
备份数据上传脚本分为两部分: