如何使用 Nodejs 备份 MongoDB 数据
# 核心原理
配置备份工具的基本配置,数据库配置,目录配置,命名规范 mongodump 备份数据库 文件模块按时间规范压缩 数据库文件 定时清理过期资源
# 代码示例
var path = require('path'),
fs = require('fs-extra'),
exec = require('child_process').exec,
_ = require('lodash'),
async = require('async'),
moment = require('moment'),
config = {
dateFormate: 'YYYY.MM.DD',
dbBackupPath: '/tmp/backup',
prefix: '',
days: 3,
tarExt: '.tar.gz',
tar: true
},
Backup = {};
/**
* [init 数据库备份服务]
* @param {[type]} options [description]
* @return {[type]} [description]
*/
Backup.init = function (options) {
var dbBackupPath = options.path || config.dbBackupPath, //数据库备份父级目录
dbHost = options.host, //数据连接
dbName = options.name, //数据库名称
prefix = options.prefix || config.prefix, //存储目录前缀
dateFormate = options.dateFormate || config.dateFormate, //今日备份目录名的时间标示
todayBackUpName = getDatePath(new Date(), prefix, dateFormate), //今日备份目录名
todayBackUpPath = path.join(dbBackupPath, todayBackUpName),
tar = config.tar,
tarName,
tarPath; //今日备份目录路径
if (!dbHost) {
console.log('[参数缺失] dbHost');
return;
}
if (!dbName) {
console.log('[参数缺失] dbName');
return;
}
if (!fs.existsSync(dbBackupPath)) {
//创建数据库备份父级目录
fs.mkdirsSync(dbBackupPath);
}
// if (fs.existsSync(todayBackUpPath)) {
// console.log('[已经创建] %s', todayBackUpPath);
// return;
// }
async.waterfall([
//dump
function (cb) {
console.log('[开始备份] %s %s ', dbHost, dbName);
var cmdStr = 'mongodump -h ' + dbHost + ' -d ' + dbName + ' -o ' + todayBackUpPath;
exec(cmdStr, function (err) {
if (!err) {
console.log('[成功创建] %s', todayBackUpPath);
cb(null);
} else {
console.log(err);
console.log('[指令执行失败] %s', cmdStr);
cb(err);
}
});
},
//tar
function (cb) {
if (tar) {
tarName = todayBackUpName + config.tarExt;
tarPath = path.join(dbBackupPath, tarName);
console.log('[开始压缩] %s', todayBackUpPath);
exec('tar -cPzf ' + tarName + ' ' + todayBackUpName, {
cwd: dbBackupPath
}, function (err) {
if (!err) {
console.log('[成功创建] %s', tarPath);
cb(null, tarPath);
} else {
console.log(err);
cb(err);
}
});
} else {
cb(null);
}
}
], function (err, result) {
if (!err) {
if (tar) {
exec('rm -rf ' + todayBackUpPath, function (err) {
if (!err) {
console.log('[清理文件] %s', todayBackUpPath);
console.log('------------------------------------------------------------------------------------------------------------------');
console.log('[下载指令] %s', 'scp <sshName>:' + tarPath + ' ' + tarName);
console.log('------------------------------------------------------------------------------------------------------------------');
} else {
console.log(err);
}
});
//清理历史数据
var currentPaths = fs.readdirSync(dbBackupPath),
effectPaths = getDaysInnerPath(prefix, dateFormate, options.days || config.days);
console.log('[保留数据] %s', effectPaths[1] + '~' + effectPaths[effectPaths.length - 1]);
for (var i = 0, len = currentPaths.length; i < len; i++) {
if (_.indexOf(effectPaths, currentPaths[i]) < 0) {
var rmFile = path.join(dbBackupPath, currentPaths[i]);
exec('rm -rf ' + rmFile, function (err) {
if (!err) {
console.log('[清理过期文件] %s', rmFile);
} else {
console.log(err);
}
});
}
}
}
} else {
console.log(err);
console.log('[备份失败] %s %s', dbHost, dbName);
}
});
};
function getDatePath(date, prefix, dateFormate) {
var dir = moment(date)
.format(dateFormate);
return prefix + dir;
}
//获取几天内的目录
function getDaysInnerPath(prefix, dateFormate, days) {
days = days || 1;
var now = new Date(),
pathArray = [];
for (var i = days - 1; i >= 0; i--) {
var pathName = getDatePath(new Date(now.getTime() - i * 24 * 60 * 60 * 1000), prefix, dateFormate);
pathArray.push(pathName);
pathArray.push(pathName + config.tarExt);
}
return pathArray;
}
module.exports = Backup;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
上次更新: 2024/01/30, 00:35:17
- 02
- Node与GLIBC_2.27不兼容解决方案08-19
- 03
- Git清空本地文件跟踪缓存08-13