UniFi - 如何删除或修剪旧数据并调整 Mongo 数据库大小


概述


对于管理多个站点或记录较多客户端的控制器,随着时间流逝,其占用空间会越来越大。因此本文介绍了如何通过 prune 脚本删除早于 X 天前的统计信息,包括警报,事件,来宾条目,检测到的恶意 AP,已知客户端和流量统计信息。修剪脚本不会删除控制器中配置信息,例如已被阻止的用户。

注意事项和要求: 
在执行脚本之前,UniFi 控制器需要保持运行。如果未运行,请在先启动启动控制器。切记在执行任何修改操作之前为控制器 创建备份

目录


  1. 介绍
  2. 如何修剪 Windows 上的控制器
  3. 如何修剪 macOS 上的控制器
  4. 如何修剪 Linux (Ubuntu, Debian, and Cloud Key) 上的控制器
  5. 修剪脚本
  6. 相关文章

介绍


回到顶部

UniFi 使用 MongoDB 来存储有关已连接设备,控制器配置,客户端和统计信息的相关信息。UniFi 控制器提供了从 Controller 自身内部压缩数据库的选项。如果您可以登录 UniFi 控制器,请依次点击  Settings > Maintenance 中  Services 下的压缩数据库选项,而不要使用本文中的手动修剪方式。

压缩数据库并不会从数据库中删除数据,只会缩小 dataSize 到数据库中当前的大小。压缩数据库只涉及碎片整理,并不涉及对错误数据的筛选。如果您的数据库中有无效或损坏的信息,请按照以下说明进行操作。


如何修剪 Windows 上的控制器


回到顶部

1. 下载 mongo。Windows 系统中 UniFi 安装程序不包含 mongo 二进制文件。请访问 MongoDB 官方下载网站,并下载与您的操作系统相对应的 MongoDB.zip 版本,该版本与您的 UniFi 控制器正在使用的版本相匹配,您可以参考 MongoDB 日志或在控制器发行说明中确认所需版本。 

2. 解压 mongo。将t \bin\mongo.exe 解压缩,本文将解压缩文件放置在了 C:\prune\ 中. 您可以忽略压缩包中的其他文件。

3. 下载脚本。 单击此处下载脚本。

4. 打开命令提示符。通过按 WINDOWS + R 打开命令提示符。在弹出窗口中,输入 cmd,然后按 Enter。

5. 进入设备存放目录。在命令提示符界面,输入以下命令并按 Enter 键,切换到指定目录:

cd C:\prune\

6. 测试运行。默认情况下,该脚本处于“dry run”模式,您可以输入以下命令来模拟执行。此步骤是为了确保脚本可运行。

mongo.exe --port 27117 < mongo_prune_js.js

输出类似如下内容:

7.禁用 dry run。修改脚本来关闭 dry run 模式并配置要保留的数据天数。默认情况下,该脚本将保留 7 天内的数据。使用  Notepad++  或类似的纯文本编辑器来修改脚本并保存。切记不要使用富文本编辑器,如写字板或 Word 。

修改 var days = 7;此行内容,更改要保留多少天的数据,并将 var  dryrun = true 更改为 var dryrun=false 来允许脚本实际修剪数据库。

8. 修剪数据库。修改并保存后,运行修改后的脚本,开始修剪数据库:

mongo.exe --port 27117 < mongo_prune_js.js
注意: 由于正在修改数据库,因此与测试(dry run)相比,此步骤可能花费更长的时间。在收到提示 bye 的消息之前,请勿中断该过程 。

9. 修剪完成。 修剪成功完成,如果未报告任何错误。输出应类似于以下内容:

10. 可根据需要清理文件。如果您不再使用,您可以删除创建的目录和其中的文件.


如何修剪 macOS 上的控制器


回到顶部

1. 创建一个目录。在计算机上创建一个目录。本文将创建一个名为 /prune 的目录。

2. 下载 mongo。  macOS 系统中 UniFi 安装程序不包含 mongo 二进制文件。请访问 MongoDB 官方下载网站,并下载与您的 CPU 相对应的 .tgz 版本,该版本与您的 UniFi 控制器正在使用的版本相匹配。您也可以直接在此处下载 2.4.14:2.4.14.tgz

3.解压 mongo。 将下载的软件包移到 /prune 目录,然后将其解压缩。

4.将 mongo 移动到。 将 bin / mongo 二进制文件复制到 /prune 目录中。此时,由于我们只需要 mongo 二进制文件,因此可以删除下载的 .tgz 软件包以及压缩包中的其他文件。

5. 进入 /prune 目录。 打开 Terminal 窗口,使用以下命令来进入 /prune 目录:

cd /prune

6. 下载脚本。 通过以下命令下载脚本:

curl "https://help.ubnt.com/hc/article_attachments/115024095828/mongo_prune_js.js" -o "mongo_prune_js.js"

7. 测试运行。 默认情况下,该脚本处于“dry run”模式,您可以输入以下命令来模拟执行。此步骤是为了确保脚本可运行。

./mongo --port 27117 < mongo_prune_js.js

输出类似如下内容:

8. 禁用“dry run” 模式。请编辑脚本以禁用 dry run 并配置要保留的数据天数。默认情况下,该脚本将保留7 天的数据。您可以使用 nano 或类似的常用编辑器来修改脚本,如下所示:

nano mongo_prune_js.js

通过编辑 var days = 7; 来更改要保留多少天的数据,并将 var dryrun = true 更改为 var dryrun = FALSE 来允许脚本实际修剪数据库,而不仅仅是进行测试运行。准备就绪后,按 CTRL + O 保存文件(按 Enter 确认),然后按 CTRL + X 退出。

9. 修剪数据库。运行修改后的脚本来修剪数据库。

./mongo --port 27117 < mongo_prune_js.js
注意: 由于正在修剪数据库,因此与测试(dryrun 模式)相比,此步骤可能花费更长的时间。在收到提示 bye 的消息之前,请勿中断该过程 。

10. 修剪完成。修剪成功完成,如果未报告任何错误。输出应类似于以下内容:

11. 关闭窗口。通过输入以下命令并按 Enter 键来关闭终端窗口。

exit

12.  清理如果您不再使用,您可以删除创建的目录。


如何修剪 Linux (Ubuntu, Debian, and Cloud Key) 上的控制器


回到顶部

在执行脚本之前,确保控制器正在运行。如果未运行,请在执行以下步骤之前启动 Controller,然后在步 骤 2:进入目录后输入以下命令。

sudo service unifi start

1. 建立连接。 通过 SSH 连接到服务器并进行身份验证。这里我们使用 Windows 上的 PuTTY 做演示。如果使用 Linux 或 Mac 客户端,则可以使用内置的终端应用程序连接到服务器。

2.进入目录。转到您的主目录,或创建您选择的目录。这里我们将使用主目录。.

cd ~

3.下载脚本。使用以下命令下载脚本:

wget https://help.ubnt.com/hc/article_attachments/115024095828/mongo_prune_js.js

4. 测试运行。 默认情况下,该脚本处于“dry run”模式,您可以输入以下命令来模拟执行。此步骤是为了确保脚本可运行。

mongo --port 27117 < mongo_prune_js.js

输出类似如下内容:

5. 禁用“dry run” 模式。请编辑脚本以禁用 dry run 并配置要保留的数据天数。默认情况下,该脚本将保留7 天的数据。您可以使用 nano 或类似的常用编辑器来修改脚本,如下所示:

nano mongo_prune_js.js

通过编辑 var days = 7; 来更改要保留多少天的数据,并将 var dryrun = true 更改为 var dryrun = FALSE 来允许脚本实际修剪数据库,而不仅仅是进行测试运行。准备就绪后,按 CTRL + O 保存文件(按 Enter 确认),然后按 CTRL + X 退出。

注意: 如果收到指示未安装 nano 的错误,则可以使用以下命令先进行安装,然后再运行上一个命令编辑脚本sudo apt-get update && sudo apt-get -y install nano

6. 修剪数据库。 运行修改后的脚本来修剪数据库。

mongo --port 27117 < mongo_prune_js.js
注意: 由于正在修剪数据库,因此与测试(dryrun 模式)相比,此步骤可能花费更长的时间。在收到提示 bye 的消息之前,请勿中断该过程

7. 修剪完成。 修剪成功完成,如果未报告任何错误。输出应类似于以下内容:

8. 可根据需要清理文件。如果您不再使用,您可以通过以下命令删除:

rm mongo_prune_js.js

9. 关闭窗口。结束终端会话:

exit

修剪脚本


回到顶部

这是修剪脚本,仅供参考,也可以从本文底部的附件中下载它:

var days=7;
// 保留数据的天数

var dryrun=true;
// 更改为 false,以使脚本从数据库中排除旧记录。如果为 true,则对 DB 不做任何更改

var now = new Date().getTime(),
time_criteria = now - days * 86400 * 1000,
time_criteria_in_seconds = time_criteria / 1000;

print((dryrun ? "[dryrun] " : "") + "pruning data older than " + days + " days (" + time_criteria + ")... ");

use ace;
var collectionNames = db.getCollectionNames();
for (i=0; i<collectionNames.length; i++) {
var name = collectionNames[i];
var query = null;

if (name === 'event' || name === 'alarm') {
query = {time: {$lt:time_criteria}};
}

// rogue ap
if (name === 'rogue') {
query = {last_seen: {$lt:time_criteria_in_seconds}};
}



if (name === 'voucher') {
query = {end_time: {$lt:time_criteria_in_seconds}};
}
// 删除超过过期时间超过 $ 天的设备

// guest authorization
if (name === 'guest') {
query = {end: {$lt:time_criteria_in_seconds}};
}

// if a user was only seen ONCE, $last_seen will not be defined
// so, if $last_seen not defined, lets use $first_seen instead
// also check if $blocked or $use_fixedip is set. If true, do NOT purge the
// entry no matter how old it is. We want blocked/fixed_ip users to continue
// blocked/fixed_ip. Also noted users should not be deleted.
if (name === 'user') {
query = { blocked: { $ne: true}, use_fixedip: { $ne: true}, noted: { $ne: true}, $or: [
{last_seen: {$lt:time_criteria_in_seconds} },
{last_seen: {$exists: false}, first_seen: {$lt:time_criteria_in_seconds} }
]
};
}

if (query) {
count1 = db.getCollection(name).count();
count2 = db.getCollection(name).find(query).count();
print((dryrun ? "[dryrun] " : "") + "pruning " + count2 + " entries (total " + count1 + ") from " + name + "... ");
if (!dryrun) {
db.getCollection(name).remove(query);
db.runCommand({ compact: name });
}
}
}

if (!dryrun) db.repairDatabase();

use ace_stat;
var collectionNames = db.getCollectionNames();
for (i=0; i<collectionNames.length; i++) {
var name = collectionNames[i];
var query = null;

// historical stats (stat.*)
if (name.indexOf('stat')==0) {
query = {time: {$lt:time_criteria}};
}

if (query) {
count1 = db.getCollection(name).count();
count2 = db.getCollection(name).find(query).count();
print((dryrun ? "[dryrun] " : "") + "pruning " + count2 + " entries (total " + count1 + ") from " + name + "... ");
if (!dryrun) {
db.getCollection(name).remove(query);
db.runCommand({ compact: name });
}
}
}

if (!dryrun) db.repairDatabase(); 

相关文章


回到顶部

网络入门 - 如何使用 SSH 建立连接

UniFi - 如何导出和删除设备数据