Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >SCF VS Code 实践:备份MySQL数据库至腾讯云COS

SCF VS Code 实践:备份MySQL数据库至腾讯云COS

原创
作者头像
孤鸿寄语
修改于 2019-10-08 03:23:39
修改于 2019-10-08 03:23:39
1.6K00
代码可运行
举报
文章被收录于专栏:孤鸿寄语孤鸿寄语
运行总次数:0
代码可运行

说明

云函数只有在需要的时候才进行调用和收费,这非常适合定期备份操作。

实现功能

  1. 定期利用mysqldump备份数据库数据
  2. 将备份的数据文件上传至腾讯云COS

实现步骤

利用vscode的插件创建函数

插件安装教程链接如下:

https://cloud.tencent.com/document/product/583/38090

利用HelloWorld模板创建函数

增加必需的文件和第三方库

由于云函数提供的环境中暂时无法预装一些二进制文件或者第三方库,因此需要手动拷贝对应文件到用户目录。本实践中需要mysqldump去在命令行执行数据库备份,需要python的第三方库toml和cos-python-sdk-v5去实现操作的配置化和操作腾讯云COS。

  1. 从任一安装有mysqldump的Linux系统中拷贝mysqldump文件至项目根目录下
  2. 在项目目录下新建文件夹site_packages,利用pip安装第三方包
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pip install --target=./site_packages toml cos-python-sdk-v5

由于mysqldump文件上传后不一定会拥有执行权限,所以最好在初始化时为mysqldump增加执行权限。另外为了使得代码能够找到自己打包的公共库,要在python的库查找路径中配置site_packages。具体代码如下:

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
import os
import sys

os.system('chmod a+x ./mysqldump')  # 为mysqldump添加执行权限
site_packages_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'site_packages')
sys.path.insert(0, site_packages_dir)

# 在以下代码中即可直接导入toml
import toml

自此,需要准备的东西已经完成,接下来可以编程去实现整个备份和上传的流程了。

编写配置文件

可以使用toml去编写配置文件,本实践中配置文件内容如下

代码语言:text
AI代码解释
复制
# db的公共配置,下边的配置中可以覆盖这里的配置
[ifish.backup.db.common]
host = "1.2.3.4"
port = 3306
user = "root"
password = "123456"

# 要备份的db信息
# 这里的配置会覆盖common中
[[ifish.backup.db.dbs]]
user = "test"
password = "123456"  
db = "test"   # 要备份的db的名称


# 腾讯云COS配置
[ifish.backup.db.cos]
SecretId = "123456"
SecretKey = "123456"
Region = "ap-beijing"
Scheme = "https"
BackupBuckets = [ "backup",]
BackupKeyPrefix = "db"  # 存储的文件夹名称
MaxBackupTimes = 5  # 最多要备份的数量,5表示桶中最多会保留最近5次备份的结果,之前的会被删除

编写业务代码

整体项目目录结构如图:

项目目录结构
项目目录结构

其中test.toml和tmp文件夹为本地测试使用,可以使用云函数的template.yaml去配置环境变量来使得程序去识别当前是生产环境还是开发环境。具体的代码如下:

config.py

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
# -*- coding: utf-8 -*-
import os
import sys
if os.getenv('DEPLOY', 'dev') != 'prod':
    sys.path.append('.')

site_packages_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'site_packages')
sys.path.insert(0, site_packages_dir)


import toml
import logging

if os.getenv('DEPLOY', 'dev') == 'prod':
    _CONFIG_FILE = './prod.toml'
    WORK_DIR = '/tmp'
    MYSQL_DUMP_CMD = './mysqldump -h%s -p%d -u%s -p%s %s > %s'
    _LOG_LEVEL = logging.INFO
else:
    _CONFIG_FILE = './test.toml'
    WORK_DIR = './tmp'
    MYSQL_DUMP_CMD = 'mysqldump -h%s -p%d -u%s -p%s %s > %s'
    _LOG_LEVEL = logging.DEBUG

logging.basicConfig(level=_LOG_LEVEL, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger()

if os.getenv('DEPLOY', 'dev') == 'prod':
    logger.info('PROD'.center(50, '-'))
else:
    logger.info('DEV'.center(50, '-'))

# 加载配置文件
config = toml.load(_CONFIG_FILE)
cos_config = config['ifish']['backup']['db']['cos']
config = config['ifish']['backup']['db']


# common和每个单独的配置合并后必须拥有的项
_CONFIG_COMMON_ITMES = ['host', 'port', 'user', 'password']
# 每个单独的配置必须拥有的项
_CONFIG_SPECIFIC_ITEMS = ['db']

for conf in config['dbs']:
    for k in _CONFIG_COMMON_ITMES:
        if not conf.get(k):
            conf[k] = config['common'][k]
    for k in _CONFIG_SPECIFIC_ITEMS:
        if not conf.get(k):
            raise ValueError('Specific config must have item: %s' % k)


# 给mysqldump添加执行权限
os.system('chmod a+x ./mysqldump')

if __name__ == "__main__":
    import json

    print(json.dumps(config, indent=2, ensure_ascii=False))
    print(json.dumps(cos_config, indent=2, ensure_ascii=False))

cos.py

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
# -*- coding=utf-8

from config import cos_config, logger
import os
import datetime
import time
from qcloud_cos import CosConfig
from qcloud_cos import CosS3Client
import json

config_detail = {
    'SecretId': cos_config['SecretId'],
    'SecretKey': cos_config['SecretKey'],
    'Region': cos_config['Region'],
    'Token': cos_config.get('Token', None),
    'Scheme': cos_config.get('Scheme', 'https'),
}

config = CosConfig(**config_detail)
client = CosS3Client(config)


def upload_to_backup_buckets(local_file):
    logger.info('Start to Upload File: ' + local_file)
    file_name = os.path.basename(local_file)
    key = os.path.join(cos_config['BackupKeyPrefix'],
                       time.strftime('%Y_%m_%d_%H_%M_%S') + '_' + file_name)
    result = {}
    for bucket in cos_config['BackupBuckets']:
        res = client.upload_file(
            Bucket=bucket,
            LocalFilePath=local_file,
            Key=key,
            PartSize=1,
            MAXThread=10,
            EnableMD5=False
        )
        result['bucket'] = res['ETag']
    logger.info('Start to Upload File: ' + local_file)
    return result


def delete_expired_items():
    logger.info('Start Delete Expired Items')
    for bucket in cos_config['BackupBuckets']:
        logger.info('Process Bucket: ' + bucket)
        # 目前备份数量远小于1000,所以这里不做迭代
        response = client.list_objects(
            Bucket=bucket,
            Prefix=cos_config['BackupKeyPrefix']
        )
        if response['IsTruncated'] != 'false':
            raise ValueError('Too Many Objects')
        contents = []
        logger.info('Found Contents:\n %s' % json.dumps(response, indent=2, ensure_ascii=False))
        for s in response['Contents']:
            if s['Key'].strip('/') == cos_config['BackupKeyPrefix']:
                continue
            content = {
                'key': s['Key'],
                'last_modified_date': datetime.datetime.strptime(s['LastModified'], '%Y-%m-%dT%H:%M:%S.%fZ')
            }
            contents.append(content)
        sorted(contents, reverse=True, key=lambda k: k['last_modified_date'].timestamp())
        logger.debug(len(contents))
        if len(contents) > cos_config['MaxBackupTimes']:
            delete_contents = contents[cos_config['MaxBackupTimes']:]
            logger.info('Delete Items: %s' % delete_contents)
            delete_param = {
                'Object': [{'Key': c['key']} for c in delete_contents],
                'Quiet': 'false'
            }
            response = client.delete_objects(Bucket=bucket, Delete=delete_param)
            logger.info('Delete Result:\n %s' % json.dumps(response, indent=2, ensure_ascii=False))


if __name__ == "__main__":
    upload_to_backup_buckets('./prod.toml')

util.py

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
# -*- coding: utf-8 -*-
import zipfile
import os
from config import MYSQL_DUMP_CMD, WORK_DIR, logger
import subprocess


def compress_dir(zip_dir, zip_filename, filename_filter=lambda filename: True):
    """
    压缩文件夹
    :param zip_dir:
    :param zip_filename:
    :param filename_filter:
    :return:
    """
    with zipfile.ZipFile(zip_filename, 'w', zipfile.ZIP_DEFLATED) as zip_file:
        for dirpath, dirnames, filenames in os.walk(zip_dir):
            for filename in filenames:
                if filename_filter(filename):
                    fpath = os.path.join(dirpath, filename)
                    arc_path = os.path.relpath(fpath, zip_dir)
                    zip_file.write(fpath, arc_path)


def backup_one_db(host, port, user, password, db):
    logger.info(f'Start to backup DB: user={user}, db={db}')
    backup_file_name = f'{user}__{db}.sql'
    backup_file_path = os.path.join(WORK_DIR, backup_file_name)
    cmd = MYSQL_DUMP_CMD % (host, port, user, password, db, backup_file_path)
    if not password:
        cmd = cmd.replace('-p', '')
    logger.debug(cmd)
    cmds = cmd.split()
    p = subprocess.run(cmds, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding='utf8', timeout=30)
    if p.returncode == 0:
        logger.info(f'Backup DB successfully: user={user}, db={db}')
        return True
    else:
        logger.info(f'Backup DB failed: user={user}, db={db}')
        return False


if __name__ == "__main__":
    zip_filename = '/Users/happylv/projects/tmp/test.zip'
    zip_dir = '/Users/happylv/projects/tmp'
    compress_dir(zip_dir, zip_filename)

index.py

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
# -*- coding: utf-8 -*-

import os

from config import logger, config, WORK_DIR
from cos import upload_to_backup_buckets, delete_expired_items
from util import backup_one_db, compress_dir


def main_handler(event, context):
    logger.info('Start Main Handler')
    for i, conf in enumerate(config['dbs']):
        backup_one_db(**conf)
    zip_filepath = os.path.join(WORK_DIR, 'db.zip')
    compress_dir(WORK_DIR, zip_filepath, lambda filename: filename.endswith('.sql'))
    upload_to_backup_buckets(zip_filepath)
    delete_expired_items()
    logger.info('End Main Handler')
    return {'code': 0, 'msg': 'success', 'data': {}}


if __name__ == '__main__':
    main_handler(None, None)

template.yaml

代码语言:yaml
AI代码解释
复制
Resources:
  ifish:
    Type: TencentCloud::Serverless::Namespace
    db_backup:
      Properties:
        CodeUri: .
        Description: DB backup function
        Environment:
          Variables:
            DEPLOY: prod  # 使用该环境变量控制是生产环境还是测试环境
        Events:
          # 配置定时出发,每天0点触发
          backup_mysql_daily:
            Properties:
              CronExpression: 0 0 0 */1 * * *
              Enable: true
            Type: Timer
        Handler: index.main_handler
        MemorySize: 128
        Runtime: Python3.6
        Timeout: 300
        # 配置vpc使得云函数可以访问db
        VpcConfig:
          SubnetId: subnet-123456
          VpcId: vpc-123456
      Type: TencentCloud::Serverless::Function

常见问题

  1. 使用pip安装至特定目录时报错:must supply either home or prefix/exec-prefix -- not both

根据stackoverflow上的回答,这是MacOS下的一个bug,解决方式见链接:

https://stackoverflow.com/questions/24257803/distutilsoptionerror-must-supply-either-home-or-prefix-exec-prefix-not-both

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
使用 SCF 无服务器云函数定时备份数据库
最近有客户询问到使用云函数进行数据库导出备份时的一些问题,在此也进行一下总结,描述如何使用云函数来进行数据库备份。
腾讯云serverless团队
2018/07/10
10.2K0
python备份mysql数据库
原本可以用shell完成的功能,现在学习python,就照抄照改。完成数据库备份。
py3study
2020/01/15
9.1K0
利用腾讯云 COS 云对象存储定时远程备份网站
一、优点分析 内网传输:和阿里云 OSS 一样,腾讯云 COS 同样支持内网和外网文件传输,对于腾讯云服务器,使用内网传输绝对是最快、最稳定的备份方案! 免费方案:看了下腾讯云 COS 的定价说明,发现对于备份网站来说简直是绝佳搭档,甚至可以说是钻了个空子(希望腾讯云的同事看到别打我。。。)!为啥这么说? 看下定价方案: 1、入流量免费 相当于我们上传文件的流量都是免费的,不区分内外网哦!内网就不说了,都懂。 [1487125898988_6230_1487125898942.jpg] 2、各种免费额度
张戈
2018/01/15
16.6K1
利用腾讯云 COS 云对象存储定时远程备份网站
Docker 安装 mysql 并映射数据库存放路径及配置文件/Docker备份mysql
show variables like '%datadir%';会输出数据文件的存放路径 /var/lib/mysql/
鳄鱼儿
2024/05/21
1.5K0
Docker 安装 mysql 并映射数据库存放路径及配置文件/Docker备份mysql
COS结合SCF的数据复制实践
1.上传的数据目录不合适,但是现有代码调整需要发布,临时处理方法可以将A目录的数据复制一份到B目录。
wainsun
2020/12/19
1.1K0
COS结合SCF的数据复制实践
mySql每天自动备份数据库
工具类 package cn.stylefeng.guns.modular.task; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.io.*; import java.nio.charset.StandardCharsets; /** * @author shiye * @create 2022-06-22 16:27 */ public cla
用户5927264
2022/06/26
2.6K0
在Ubuntu 16.04如何使用Percona将MySQL类别的数据库备份到指定的对象存储上呢?
数据库通常会在您的基础架构中存储一些最有价值的信息。因此,在发生事故或硬件故障时,必须具有可靠的备份以防止数据丢失。
木纸鸢
2018/08/10
13.5K0
用python备份mysql数据库的脚本
一、脚本 环境:Centos 6.3 Python  2.6.6      脚本如下: #!/usr/bin/env python # author: kuangl # -*- coding: utf-8 -*- # filename: mysql_back_zhubao.py import os import time import string ''' defined variable ''' databases=['kaixin'] sql_user='root' sql_pwd=['kwqsk12
py3study
2020/01/06
2.8K0
线上MySQL备份实例
是否为MySQL线上库的备份而烦恼过,这里提供一个完整的备份从属数据库的备份方案,亲测可用。
星哥玩云
2022/08/17
7900
MySQL数据库备份脚本
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/130902.html原文链接:https://javaforall.cn
全栈程序员站长
2022/07/01
7.9K0
云函数 SCF 与对象存储实现 WordCount 算法
本文将尝试通过 MapReduce 模型实现一个简单的 WordCount 算法,区别于传统使用 Hadoop 等大数据框架,本文使用云函数 SCF 与对象存储 COS 来实现。 MapReduce 在维基百科中的解释如下: MapReduce 是 Google 提出的一个软件架构,用于大规模数据集(大于 1TB)的并行运算。概念「Map(映射)」和「Reduce(归纳)」,及他们的主要思想,都是从函数式编程语言借来的,还有从矢量编程语言借来的特性。 通过这段描述,我们知道,MapReduce 是面向大数
腾讯云serverless团队
2020/05/28
9280
跨库数据备份还原、迁移工具
数据开发过程中,为了确保生产数据库安全,一般将实时数据同步、备份到本地测试数据库完成开发工作,最后部署应用。
用户8949263
2022/04/08
1K0
跨库数据备份还原、迁移工具
(7) MySQL数据库备份详解
比如我们由于误操作,在主数据库上删除了一些数据,由于主从复制的时间很短,在发现时,从数据库上的数据可能也已经被删除了, 我们不能使用从数据库上的数据来恢复主数据库上的数据,只能通过备份进行误删除数据的恢复
用户1214487
2019/05/25
1K0
利用腾讯云COS云对象存储定时远程备份网站
内网传输:和阿里云OSS一样,腾讯云COS同样支持内网和外网文件传输,对于腾讯云服务器,使用内网传输绝对是最快、最稳定的备份方案!
用户8851537
2021/07/21
6.1K0
SpringBoot实现MySQL数据库自动备份管理系统
最近写了一个 MySQL 数据库自动、手动备份管理系统开源项目,想跟大家分享一下,项目地址:
Java秦师兄
2022/08/16
3.5K0
SpringBoot实现MySQL数据库自动备份管理系统
记一次生产环境MySQL数据库的备份与还原
版权声明:本文为耕耘实录原创文章,各大自媒体平台同步更新。欢迎转载,转载请注明出处,谢谢
耕耘实录
2018/12/20
1.1K0
腾讯云Serverless架构安装Python依赖的小工具(包括对外的API,基于SCF)
很久很久之前,做了一个在线下载依赖包的工具,但是由于是放在了CVM上,收费比较高昂,而自己比较清贫,所以没能坚持多久,那个工具就被我下掉了,后来有小伙伴就给我留言问我为啥工具不能用了?对啊,有Serverless架构,为什么要用CVM这种鬼东西呢?那么今天我就弄一个Python安装依赖的小工具。
None-xiaomi
2019/12/31
2.2K1
代码分享:用java备份MySQL数据库
t-io官网的数据库都会定时备份,并且可以通过http直接下载到本地(这个当然需要特权,不是人人有这个操作权限),为了操作的灵活性,采用java来实现MySql的备份
talent-tan
2019/08/03
2.6K0
Python实现腾讯云CDB备份文件自动上传到COS
一、背景 需求:目前遇到的客户需求为将腾讯云CDB备份文件自动上传到腾讯云COS内,再次抛砖引玉,还有很多类似的需求均可以采用此类方法解决,线下IDC数据文件备份至云端COS内,或根据文件下载地址url将文件上传至COS内。 思路:首先获取到CDB的备份下载url,通过COS的API上传文件,大佬如有更好的方法欢迎一块讨论。 二、技术细节 COS:COS有API同时有SDK,这就很方便我们来通过Python对COS进行各类操作,COS SDK for Python CDB:CDB有API但是CDB的查询备份
KaliArch
2018/07/16
2.5K0
Python实现腾讯云CDB备份文件自动上传到COS
shell脚本备份mysql数据库
第一种方法: #!/bin/sh # 备份数据库 # Mysql 用户名密码 MYSQL_USER=root MYSQL_PASS=root BACKUP_DIR=/data/backup/mysql DATA_DIR=/data/backup/dbdata # 查询mysql中所有数据库名字 SQL_STRING="SELECT SCHEMA_NAME AS db FROM information_schema.SCHEMATA WHERE SCHEMA_NAME NOT IN ('mysql
老七Linux
2018/05/09
3.5K0
相关推荐
使用 SCF 无服务器云函数定时备份数据库
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验