Fundebug的MongoDB复制集由1个Primary节点和2个Secondary节点构成,为保证我们服务可用性发挥了非常关键的作用!我之后所介绍的备份方案都是冗余措施,我们从来没有真正使用过那些备份数据,而复制集"拯救"了我们不少次,强烈建议大家都配置一下。
关于MongoDB复制集的更多技术细节,以后我再单独详述,欢迎关注Fundebug微信公众号。
阿里云磁盘快照快照能够保留某一时间点的磁盘数据状态,因此可以作为一种数据备份方式。很简单,配置一下自动快照策略就好了:
我备份了系统盘,万一数据丢失比如被删库,至少还能回滚磁盘。每周快照1次,保存7天。因为服务全部运行在Docker里面,服务器本身基本上没有什么配置,备份的需求不大,实际上我们也从来没有回滚过磁盘。
另外,我没有对MongoDB数据盘直接进行快照,因为发现快照后的数据无法恢复(这一点有待进一步确认)。
我只是将mongodump导出的核心数据所在磁盘进行了快照。每天快照1次,保存两天。这样做可以确保核心数据的安全性。
mongodump导出核心数据使用mongodump命令,可以全量导出MongoDB数据。对应的,之后可以使用命令将备份数据导入MongoDB。
导出数据的脚本dump-data.sh如下:
#!/bin/sh # 删除前一天导出的数据 rm -rf /data/mongodb_backup DIR=`date +%Y%m%d%H%M` OUT=http://www.likecs.com/data/mongodb_backup/$DIR mkdir -p $DEST # 全量导出MongoDB数据(排除部分集合) mongodump --host "rs0/192.168.59.11:27017,192.168.59.12:27017,192.168.59.13:27017" \ --db fundebug-production \ --excludeCollection events \ --out $OUT使用--excludeCollection选项,可以排除部分不需要备份的集合。例如,Fundebug累计处理了6亿+的错误事件,存在event集合中,因为我们已经聚合过了,所以没有必要备份,而且数据量太大,备份也不现实。
使用crontab脚本定期执行dump-data.sh脚本:
# 每天凌晨4点导出数据 0 4 * * * /root/fundebug-mongodb-backup/dump-data.sh 阿里云对象存储使用mongodump导出的数据保存在测试服务器的数据磁盘上,从地域层面上来说都在同一个地方,即阿里云深圳数据中心。如果要做到异地备份,可以借助阿里云的对象存储服务的跨区域复制功能,将备份数据自动同步到阿里云杭州数据中心。
在上传备份数据之前,使用gpg命令进行非对称加密,可以保证数据安全性。加密导出数据的脚本encrypt-data.sh脚本如下:
#!/bin/bash DIR=`find /data/mongodb_backup/ -maxdepth 1 -type d ! -path /data/mongodb_backup/` source=$DIR/fundebug-production cd $source # 将导出数据加密 for file in * ; do gpg --batch --yes -v -e -r fundebug --output $source/$file.gpg --always-trust $file done ;除了加密,gpg还有一定的压缩效果,这样可以减少备份数据量,一举两得。关于gpg命令的细节,可以查看参考博客。
使用阿里云提供的Node.js客户端ali-oss,可以将加密之后的.gpg文件上传到阿里云的对象存储服务中。使用方法即可,upload.js部分代码如下:
// 上传单个文件 async function uploadFile(fileName, filePath) { try { const result = await store.multipartUpload(fileName, filePath, { parallel: 4, partSize: 1024 * 1024, progress: function(p) { logger.info("Progress: " + p); } }); if (result.res.statusCode === 200) { logger.info(`upload file success! ${fileName}`); } else { const message = `upload file fail! ${fileName}`; logger.error(message); logger.error(result); fundebug.notifyError(new Error(message), { metaData: { message: message, result: result } }); } } catch (error) { const message = `upload file fail! ${fileName}`; logger.error(message); logger.error(error); fundebug.notifyError(error, { metaData: { message: message, error: error } }); } }代码运行在Docker容器中,使用curl命令访问HTTP接口/upload即可触发执行上传操作,使用crontab定期执行:
# 每天凌晨4点备份数据 0 4 * * * /root/mongodb-backup/dump-data.sh && /root/mongodb-backup/encrypt-data.sh && docker restart mongodb-backup && sleep 1m && curl :9160/upload备份数据通过数据卷(volume)映射到容器中,每天需要重启容器,才能访问每天导出的新数据。
在阿里云上为备份数据的存储空间配置跨区域复制,即可实现自动异地备份,非常方便。其他对象存储云服务应该也支持这种功能吧。
本地磁盘备份前文提到的备份方式,其实都是在阿里云内部COPY数据。那么问题来了,阿里云挂了怎么办?这种事情当然基本上不可能发生,毕竟我们有多处备份,甚至实现了异地备份。