备份大量异构Web项目

看来这个话题很老套-关于备份的讨论和讨论很多,所以没有什么可以重新发明轮子的了,只管自己去做就可以了。 但是,每当一个Web项目的系统管理员面对设置备份的任务时,对于许多备份来说,它就悬而未决。 如何正确收集数据备份? 哪里存储备份? 如何提供必要级别的追溯存储副本? 如何统一各种软件整个动物园的备份过程?



对于我们自己,我们在2011年首先解决了这个问题。然后我们坐下来编写了备份脚本。 多年来,我们仅使用它们,并且它们成功地提供了可靠的过程来收集和同步客户Web项目的备份。 备份存储在我们的或其他外部存储中,可以针对特定项目进行调整。


我必须说,这些脚本发挥了最大作用。 但是,随着我们的发展,出现了我们的脚本不支持的,具有不同软件和外部存储库的多样化项目。 例如,我们不支持Redis以及稍后出现的MySQL和PostgreSQL热备份。 备份过程没有受到监视,只有电子邮件警报。


另一个问题是支持过程。 多年以来,我们曾经紧凑的脚本已经成长为巨大的笨拙怪物。 当我们在一起发布新版本时,值得单独努力为使用旧版本进行某种定制的那部分客户推出更新。


结果,在今年年初,我们做出了一个坚定的决定:用更现代的东西替换旧的备份脚本。 因此,起初我们坐下来并写下了所有的愿望清单,以寻求新的解决方案。 结果大致如下:


  • 备份最常用软件的数据:
    • 文件(离散和增量复制)
    • MySQL(冷/热备份)
    • PostgreSQL(冷/热备份)
    • Mongodb
    • 雷迪斯
  • 将备份存储在常用存储库中:
    • 本地的
    • 的FTP
    • SSH
    • 中小企业
    • 消防队
    • Webdav
    • S3
  • 在备份过程中出现任何问题时接收警报
  • 有一个配置文件,可让您集中管理备份
  • 通过连接外部模块来增加对新软件的支持
  • 指定用于收集转储的其他选项
  • 能够通过常规方式还原备份
  • 简单的初始配置

我们分析可用的解决方案


我们研究了已经存在的开源解决方案:


  • Bacula及其叉子,例如Bareos
  • 阿曼达
  • 博格
  • 重复的
  • 双重性
  • 快照
  • Rdiff备份

但是它们每个都有其缺点。 例如,Bacula充斥着我们不需要的功能,由于大量的手动工作(例如,用于编写/搜索数据库备份脚本),因此初始配置是一项相当费力的任务,并且为了恢复副本,必须使用特殊的实用程序等。


最后,我们得出两个重要结论:


  1. 现有的解决方案都不完全适合我们;
  2. 看来我们自己有足够的经验和理智可以开始编写我们的决定。

我们做到了。


nxs备份的诞生


选择Python作为实现语言-它易于编写和维护,灵活方便。 决定以yaml格式描述配置文件。


为了方便支持和添加新软件的备份,选择了模块化体系结构,其中在单独的模块中描述了收集每个特定软件(例如MySQL)的备份的过程。


支持文件,数据库和远程存储


当前,支持以下类型的文件,数据库和远程存储库备份:


DB:


  • MySQL(热/冷备份)
  • PostgreSQL(热/冷备份)
  • 雷迪斯
  • Mongodb

档案:


  • 离散复制
  • 增量复印

远程存储库:


  • 本地的
  • S3
  • 中小企业
  • 消防队
  • 的FTP
  • SSH
  • Webdav

离散备份


对于不同的任务,离散备份或增量备份都适用,因此,它们实现了这两种类型。 您可以在单个文件和目录级别指定要使用的方法。


对于离散副本(文件和数据库),可以以天/周/月的格式设置回顾。


增量备份


文件的增量副本如下所示:


在今年年初,将进行完整备份。 接下来,在每个月初-相对于年度副本的每月增量副本。 月经内-相对于每月增加的十年数。 在相对于十天期间的每十天增量时间内。


应该注意的是,当使用包含大量子目录(数万个)的目录时会出现一些问题。 在这种情况下,副本的收集速度会大大降低,并且可能需要一天以上的时间。 我们正在积极解决这一缺陷。


我们从增量备份中恢复


从离散备份恢复没有问题-只需在所需日期复制一份,然后使用常规控制台tar进行部署即可。 增量副本要复杂一些。 要恢复,例如,在2018年7月24日,您需要执行以下操作:


  1. 即使我们的情况是从2018年1月1日开始,也要扩展一年的备份(实际上,这可以是任何日期,具体取决于决定何时实施增量备份的日期)
  2. 为他提供7月的每月备份
  3. 汇总7月21日的十年备份
  4. 汇总7月24日的每日备份

同时,要完成2-4点,请将-G开关添加到tar命令,从而表明这是增量备份。 当然,这不是最快的过程,但是考虑到从备份中恢复的频率不是很高,而且成本效益很重要,因此这种方案非常有效。


例外情况


通常,您需要从备份中排除单个文件或目录,例如,具有缓存的目录。 这可以通过指定适当的异常规则来完成:


配置文件示例
- target: - /var/www/*/data/ excludes: - exclude1/exclude_file - exclude2 - /var/www/exclude_3 

备用轮换


在我们的旧脚本中,实现了轮换,以便仅在成功组装新副本之后才删除旧副本。 这导致了项目上的问题,这些项目原则上仅为一个副本分配了备份空间-由于空间不足,无法在此处收集新副本。


在新的实现中,我们决定更改此方法:首先删除旧的方法,然后再收集新的副本。 并且应该监视收集备份的过程以发现任何问题。


对于离散备份,存档被认为是旧副本,其格式超出了天/周/月格式的指定存储方案。 对于增量备份,默认情况下将备份存储一年,并且在每个月初删除旧副本,而将去年同一月的存档视为旧备份。 例如,在2018年8月1日收集每月备份之前,系统将检查是否有2017年8月的备份,如果有,则将其删除。 这样可以最佳利用磁盘空间。


记录中


在任何过程中,特别是在备份中,保持同步并找出是否出了问题是很重要的。 系统保留其工作日志并捕获每个步骤的结果:资金的开始/停止,特定任务的开始/结束,在临时目录中收集副本的结果,将副本从临时目录复制/移动到永久位置的结果,备份轮换的结果等。 ..


事件分为2个级别:


  • 信息 :信息级别-飞行正常,下一阶段成功完成,在日志中进行了相应的信息输入
  • 错误 :错误级别-出了点问题,下一阶段失败,在日志中记录了相应的错误记录

电邮通知


在备份收集结束时,系统可以发送电子邮件通知。


支持2个收件人列表:


  • 管理员是为服务器提供服务的人员。 他们只收到错误通知;他们对成功操作的通知不感兴趣
  • 业务用户 -在我们的例子中,这些客户有时是想要接收通知以确保备份一切正常的客户。 或者相反,不是真的。 他们可以选择接收完整日志还是仅接收包含错误的日志。

配置文件结构


配置文件的结构如下:


结构实例
 /etc/nxs-backup ├── conf.d │ ├── desc_files_local.conf │ ├── external_clickhouse_local.conf │ ├── inc_files_smb.conf │ ├── mongodb_nfs.conf │ ├── mysql_s3.conf │ ├── mysql_xtradb_scp.conf │ ├── postgresql_ftp.conf │ ├── postgresql_hot_webdav.conf │ └── redis_local_ftp.conf └── nxs-backup.conf 

/etc/nxs-backup/nxs-backup.conf是主要配置文件,其中指示了全局设置:


配置文件
 main: server_name: SERVER_NAME admin_mail: project-tech@nixys.ru client_mail: - '' mail_from: backup@domain.ru level_message: error block_io_read: '' block_io_write: '' blkio_weight: '' general_path_to_all_tmp_dir: /var/nxs-backup cpu_shares: '' log_file_name: /var/log/nxs-backup/nxs-backup.log jobs: !include [conf.d/*.conf] 

任务(作业)数组包含任务(作业)列表,这些列表描述了要确切备份的内容,存储的位置和数量。 通常,它们被移动到单独的文件(每个作业一个文件),这些文件通过包含在主配置文件中进行连接。


他们还尽可能地优化了准备这些文件的过程,并编写了一个简单的生成器。 因此,管理员无需花费时间搜索某些服务(例如MySQL)的配置模板,只需运行以下命令:


 nxs-backup generate --storage local scp --type mysql --path /etc/nxs-backup/conf.d/mysql_local_scp.conf 

输出生成文件/etc/nxs-backup/conf.d/mysql_local_scp.conf


文件内容
  - job: PROJECT-mysql type: mysql tmp_dir: /var/nxs-backup/databases/mysql/dump_tmp sources: - connect: db_host: '' db_port: '' socket: '' db_user: '' db_password: '' auth_file: '' target: - all excludes: - information_schema - performance_schema - mysql - sys gzip: no is_slave: no extra_keys: '--opt --add-drop-database --routines --comments --create-options --quote-names --order-by-primary --hex-blob' storages: - storage: local enable: yes backup_dir: /var/nxs-backup/databases/mysql/dump store: days: '' weeks: '' month: '' - storage: scp enable: yes backup_dir: /var/nxs-backup/databases/mysql/dump user: '' host: '' port: '' password: '' path_to_key: '' store: days: '' weeks: '' month: '' 

在其中仅需替换一些必要的值。


让我们举个例子。 假设在我们的服务器上/ var / www目录中,有一个1C-Bitrix在线商店的站点(bitrix-1.ru,bitrix-2.ru),每个站点都在不同的MySQL实例中使用其自己的数据库(端口3306用于bitrix_1_db和bitrix_2_db的3307端口)。


典型的Bitrix项目的文件结构大致如下:


 ├── ... ├── bitrix │ ├── .. │ ├── admin │ ├── backup │ ├── cache │ ├── .. │ ├── managed_cache │ ├── .. │ ├── stack_cache │ └── .. ├── upload └── ... 

通常,上目录很重,并且只会随着时间的推移而增长,因此将对其进行增量备份。 除带有本机Bitrix工具收集的缓存和备份的目录外,所有其他目录都是离散的。 让这两个站点的备份存储方案应该相同,而文件副本应同时存储在本地和远程ftp存储中,而数据库应仅存储在远程smb存储中。


此类设置的结果配置文件如下所示:


bitrix-desc-files.conf(带有作业描述的配置文件,用于离散备份)
  - job: Bitrix-desc-files type: desc_files tmp_dir: /var/nxs-backup/files/desc/dump_tmp sources: - target: - /var/www/*/ excludes: - bitrix/backup - bitrix/cache - bitrix/managed_cache - bitrix/stack_cache - upload gzip: yes storages: - storage: local enable: yes backup_dir: /var/nxs-backup/files/desc/dump store: days: 6 weeks: 4 month: 6 - storage: ftp enable: yes backup_dir: /nxs-backup/databases/mysql/dump host: ftp_host user: ftp_usr password: ftp_usr_pass store: days: 6 weeks: 4 month: 6 

bitrix-inc-files.conf(带有作业描述的配置文件,用于增量备份)
  - job: Bitrix-inc-files type: inc_files sources: - target: - /var/www/*/upload/ gzip: yes storages: - storage: ftp enable: yes backup_dir: /nxs-backup/files/inc host: ftp_host user: ftp_usr password: ftp_usr_pass - storage: local enable: yes backup_dir: /var/nxs-backup/files/inc 

bitrix-mysql.conf(带有MySQL备份作业描述的配置文件)
  - job: Bitrix-mysql type: mysql tmp_dir: /var/nxs-backup/databases/mysql/dump_tmp sources: - connect: db_host: localhost db_port: 3306 db_user: bitrux_usr_1 db_password: password_1 target: - bitrix_1_db excludes: - information_schema - performance_schema - mysql - sys gzip: no is_slave: no extra_keys: '--opt --add-drop-database --routines --comments --create-options --quote-names --order-by-primary --hex-blob' - connect: db_host: localhost db_port: 3307 db_user: bitrix_usr_2 db_password: password_2 target: - bitrix_2_db excludes: - information_schema - performance_schema - mysql - sys gzip: yes is_slave: no extra_keys: '--opt --add-drop-database --routines --comments --create-options --quote-names --order-by-primary --hex-blob' storages: - storage: smb enable: yes backup_dir: /nxs-backup/databases/mysql/dump host: smb_host port: smb_port share: smb_share_name user: smb_usr password: smb_usr_pass store: days: 6 weeks: 4 month: 6 

开始收集备份的选项


在上一个示例中,我们准备了作业配置文件以一次收集所有元素的备份:文件(离散和增量),两个数据库并将它们存储在本地和外部(ftp,smb)存储中。


它仍然可以运行整个过程。 通过以下命令执行启动:


 nxs-backup start $JOB_NAME -c $PATH_TO_MAIN_CONFIG 

有几个保留的作业名称:


  • 文件 -任意执行desc_filesinc_files类型的所有作业 (实质上,仅备份文件)
  • 数据库 -随机执行类型为mysqlmysql_xtradbpostgresqlpostgresql_hotmongodbredis的所有作业(即仅备份数据库)
  • 外部 -随机执行所有具有外部类型的作业(仅运行其他自定义脚本,有关更多信息,请参见下文)
  • 模仿-通过作业文件数据库外部 (默认值)一一运行命令

由于我们需要在输出中同时(或差异最小)同时获取文件和数据库的数据备份,因此建议对job all运行nxs-backup,这将确保所描述的作业的一致性执行(Bitrix-desc-文件,Bitrix-inc_files,Bitrix-mysql)。


也就是说,重要的一点-备份将不会并行收集,而是以最小的时间差一个接一个地依次收集。 此外,在下次启动时,软件本身会检查系统中已经在运行的进程,如果检测到该进程,它将自动以日志中的相应标记结束其工作。 这种方法大大减少了系统的负载。 减号-单个元素的备份不是立即收集,而是有一些时间差。 但是,尽管我们的实践表明这并不重要。


外部模块


如上所述,由于采用了模块化架构,因此可以使用通过特殊界面与系统交互的其他用户模块来扩展系统的功能。 目标是将来能够添加对新软件备份的支持,而无需重写nxs-backup。


配置文件示例
  - job: TEST-external type: external dump_cmd: '' storages: …. 

应该特别注意dump_cmd键,其中的值是用于运行外部脚本的完整命令。 此外,完成此命令后,预计:


  • 将收集现成的软件数据档案
  • 数据将以json格式发送到stdout,格式为:
     { "full_path": "ABS_PATH_TO_ARCHIVE", "basename": "BASENAME_ARCHIVE", "extension": "EXTERNSION_OF_ARCHIVE", "gzip": true/false } 

    • 在这种情况下,密钥basenameextensiongzip仅对于形成最终备份名称必需的。
  • 如果脚本成功完成,则返回代码应为0,如果出现任何问题,则返回任何其他代码。

例如,假设我们有一个脚本来创建快照etcd /etc/nxs-backup-ext/etcd.py


脚本代码
 #! /usr/bin/env python3 # -*- coding: utf-8 -*- import json import os import subprocess import sys import tarfile def archive(snapshot_path): abs_tmp_path = '%s.tar' %(snapshot_path) with tarfile.open(abs_tmp_path, 'w:') as tar: tar.add(snapshot_path) os.unlink(snapshot_path) return abs_tmp_path def exec_cmd(cmdline): data_dict = {} current_process = subprocess.Popen([cmdline], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, executable='/bin/bash') data = current_process.communicate() data_dict['stdout'] = data[0][0:-1].decode('utf-8') data_dict['stderr'] = data[1][0:-1].decode('utf-8') data_dict['code'] = current_process.returncode return data_dict def main(): snapshot_path = "/var/backups/snapshot.db" dump_cmd = "ETCDCTL_API=3 etcdctl --cacert=/etc/ssl/etcd/ssl/ca.pem --cert=/etc/ssl/etcd/ssl/member-node1.pem"+\ " --key=/etc/ssl/etcd/ssl/member-node1-key.pem --endpoints 'https://127.0.0.1:2379' snapshot save %s" %snapshot_path command = exec_cmd(dump_cmd) result_code = command['code'] if result_code: sys.stderr.write(command['stderr']) else: try: new_path = archive(snapshot_path) except tarfile.TarError as e: sys.exit(1) else: result_dict = { "full_path": new_path, "basename": "etcd", "extension": "tar", "gzip": False } print(json.dumps(result_dict)) sys.exit(result_code) if __name__ == '__main__': main() 

运行此脚本的配置如下:


配置文件
  - job: etcd-external type: external dump_cmd: '/etc/nxs-backup-ext/etcd.py' storages: - storage: local enable: yes backup_dir: /var/nxs-backup/external/dump store: days: 6 weeks: 4 month: 6 

在这种情况下,运行job etcd-external时的程序:


  • 运行不带参数的脚本/etc/nxs-backup-ext/etcd.py
  • 脚本完成后,它将检查完成代码以及stdout中必要数据的可用性
  • 如果所有检查都成功,则使用与内置模块相同的机制,其中full_path键值用作tmp_path。 如果没有,它将在日志中用相应的标记完成此任务。

支持与更新


开发和支持新备份系统的过程已通过所有CI / CD规范实施。 战斗服务器上不再有更新和脚本编辑。 所有更改都将通过我们在Gitlab中的中央git存储库进行,在那里将新版本的deb / rpm软件包的程序集注册到管道中,然后将其上载到我们的deb / rpm存储库。 之后,通过包管理器将它们传递到最终客户端服务器。


如何下载nxs-backup?


我们制作了nxs-backup开源项目。 任何人都可以下载并使用它来组织项目中的备份过程,以及修改其需求,编写外部模块。


可以从Github存储库中的此链接下载nxs-backup的源代码。 还有安装和配置说明。


我们还准备了一个Docker映像并将其发布在DockerHub上


如果您在设置或使用过程中有任何疑问,请写信给我们。 我们将帮助您理解并最终确定说明。


结论


在不久的将来,我们将实现以下功能:


  • 监控整合
  • 备份加密
  • 基于Web的界面,用于管理备份设置
  • 使用nxs-backup部署备份
  • 还有更多

Source: https://habr.com/ru/post/zh-CN424717/


All Articles