1. 定位
vnstat 是一个面向 Linux / BSD 的轻量级网络流量统计工具。它的核心目标不是实时抓包,而是长期记录网卡维度的接收流量 rx、发送流量 tx 和总量 total,适合 VPS、家用服务器、NAS、路由器、跳板机、代理机等场景。
官方文档对它的定位很明确:vnstat 使用内核提供的网络接口统计信息作为数据来源,不 sniff traffic,因此 CPU 和内存开销非常低,流量越大也不会像抓包工具那样显著增加处理成本。
它和常见工具的区别:
| 工具 | 主要用途 | 是否长期记账 | 粒度 |
|---|---|---|---|
vnstat | 按网卡长期统计流量 | 是 | 5 分钟 / 小时 / 天 / 月 / 年 |
iftop | 实时连接流量 | 否 | 连接 / 主机 |
nethogs | 按进程看实时流量 | 否 | 进程 |
tcpdump | 抓包分析 | 否 | packet |
node_exporter | 主机指标采集 | 依赖 Prometheus | 多指标 |
如果问题是“这台机器本月用了多少流量”,优先用 vnstat。如果问题是“哪个进程正在跑流量”,用 nethogs。如果问题是“这个连接具体发了什么包”,用 tcpdump。
2. 本机环境实测
当前系统已经安装 vnstat:
vnstat --version
输出:
vnStat 2.13 by Teemu Toivola <tst at iki dot fi> (SQLite 3.51.2)
systemd 服务状态:
systemctl status vnstat --no-pager
关键输出:
● vnstat.service - vnStat network traffic monitor
Loaded: loaded (/usr/lib/systemd/system/vnstat.service; enabled; preset: disabled)
Active: active (running) since Thu 2026-05-28 08:56:56 CST
Main PID: 271177 (vnstatd)
Memory: 1.1M
CPU: 456ms
CGroup: /system.slice/vnstat.service
└─271177 /usr/sbin/vnstatd --nodaemon
服务日志显示,首次启动时自动发现了 5 个接口:
Interface "enp2s0" added with 1000 Mbit bandwidth limit.
Interface "enp3s0" added with 1000 Mbit bandwidth limit.
Interface "wg0" added with 1000 Mbit bandwidth limit.
Interface "tun-int" added with 10000 Mbit bandwidth limit.
Interface "tun-ext" added with 10000 Mbit bandwidth limit.
Info: Data retention: 48 5MinuteHours, 4 HourlyDays, 62 DailyDays, 25 MonthlyMonths, -1 YearlyYears, 20 TopDayEntries
Info: Monitoring (5): wg0 (1000 Mbit) tun-int (10000 Mbit) tun-ext (10000 Mbit) enp3s0 (1000 Mbit) enp2s0 (1000 Mbit)
当前可用接口:
vnstat --iflist
Available interfaces: enp2s0 (1000 Mbit) enp3s0 (1000 Mbit) wg0 tun-int (10000 Mbit) tun-ext (10000 Mbit)
数据库中的接口:
vnstat --dbiflist
Interfaces in database: enp2s0 enp3s0 tun-ext tun-int wg0
默认概览:
vnstat
rx / tx / total / estimated
enp2s0:
2026-05 7.15 MiB / 1.92 MiB / 9.07 MiB / 482.67 MiB
today 7.15 MiB / 1.92 MiB / 9.07 MiB / 20.56 MiB
enp3s0:
2026-05 218.99 MiB / 34.28 MiB / 253.27 MiB / 13.17 GiB
today 218.99 MiB / 34.28 MiB / 253.27 MiB / 574.34 MiB
tun-ext:
2026-05 150.61 KiB / 150.61 KiB / 301.21 KiB / 15.54 MiB
today 150.61 KiB / 150.61 KiB / 301.21 KiB / 681 KiB
tun-int:
2026-05 35.08 KiB / 35.08 KiB / 70.16 KiB / 3.59 MiB
today 35.08 KiB / 35.08 KiB / 70.16 KiB / 158 KiB
wg0:
2026-05 42.04 MiB / 6.04 MiB / 48.08 MiB / 2.50 GiB
today 42.04 MiB / 6.04 MiB / 48.08 MiB / 109.03 MiB
> 本机数据是 2026-05-28 当天刚开始采集的结果,因此历史记录较短。
vnstat的价值会随着 daemon 长期运行而体现出来。
3. 安装与启动
Fedora / RHEL 系
sudo dnf install vnstat
sudo systemctl enable --now vnstat
Debian / Ubuntu 系
sudo apt update
sudo apt install vnstat
sudo systemctl enable --now vnstat
Arch Linux
sudo pacman -S vnstat
sudo systemctl enable --now vnstat
源码安装
官方源码构建的最短路径:
./configure --prefix=/usr --sysconfdir=/etc
make
sudo make install
sudo systemctl enable --now vnstat
源码安装需要 C compiler、SQLite3 library/development files。vnstati 图片输出还需要 libgd。
4. 常用命令
4.1 查看概览
vnstat
不指定接口时,vnstat 会按配置和数据库自动选择默认接口;如果有多接口,会显示所有已监控接口的汇总。
4.2 指定接口
vnstat -i enp3s0
vnstat -i wg0
适合多网卡、WireGuard、TUN/TAP、Docker host 网络等场景。
4.3 5 分钟、小时、天、月、年
vnstat -5
vnstat -h
vnstat -d
vnstat -m
vnstat -y
示例:查看 enp3s0 最近 8 小时:
vnstat -i enp3s0 -h 8
本机输出:
enp3s0 / hourly
hour rx | tx | total | avg. rate
------------------------+-------------+-------------+---------------
2026-05-28
08:00 5.06 MiB | 935.88 KiB | 5.97 MiB | 13.91 kbit/s
09:00 85.59 MiB | 19.16 MiB | 104.75 MiB | 244.09 kbit/s
10:00 128.34 MiB | 14.20 MiB | 142.54 MiB | 569.40 kbit/s
4.4 实时速率
vnstat -l
vnstat -l -i enp3s0
-l 是 live mode,适合临时观察实时收发速率。它仍然不是抓包,只是更频繁地读取接口计数器。
4.5 短时间采样
vnstat -tr
vnstat -tr 10 -i enp3s0
-tr 会在指定秒数内采样并计算平均速率,默认采样时间由 Sampletime 控制,本机默认配置为 5 秒。
4.6 Top days
vnstat -t
vnstat -i enp3s0 -t 20
用于查历史峰值日期,比如定位某天异常下载、备份或同步流量。
4.7 JSON 输出
vnstat --json
vnstat --json s
vnstat -i enp3s0 --json d 30
--json s 会输出 summary,包含每个接口最近 2 条 5 分钟、小时、天、月、年数据。所有 traffic 数值默认以 bytes 表示,适合脚本、Telegraf、Prometheus exporter 或自写 API 读取。
4.8 XML / oneline 输出
vnstat --xml
vnstat --oneline
--oneline 适合非常简单的 shell 脚本;复杂集成建议使用 JSON。
4.9 95th percentile
vnstat --95th
95th percentile 常用于带宽计费场景。注意官方 man page 说明:如果要覆盖整个月,5MinuteHours 需要至少保存 744 小时的 5 分钟数据;默认 48 小时不够,只能算当前保留窗口内的数据。
5. 接口管理
5.1 添加接口
新版 vnstatd 在无数据库或配置允许时会自动添加可见接口。手动添加:
sudo vnstat --add -i eth0
sudo systemctl restart vnstat
如果 RescanDatabaseOnSave 开启,daemon 可在下次保存周期后自动发现数据库新增接口,不一定需要重启。
5.2 删除不需要监控的接口
sudo vnstat --remove -i tun-ext
删除前建议先确认:
vnstat --dbiflist
5.3 给接口设置别名
sudo vnstat -i enp3s0 --setalias lan
vnstat -i lan
别名适合接口名可能变化的场景,例如 USB 网卡、虚拟网卡或容器环境。配置项 InterfaceMatchMethod 控制接口名与别名的匹配方式。
5.4 合并接口查询
vnstat -i enp3s0+wg0
这只是在查询时合并展示,不会改变数据库原始记录。
6. 配置文件
主配置文件:
/etc/vnstat.conf
数据库目录:
/var/lib/vnstat/
本机实际文件:
ls -l /etc/vnstat.conf /var/lib/vnstat
-rw-r--r--. 1 root root 6552 Jan 17 08:00 /etc/vnstat.conf
/var/lib/vnstat:
total 68
-rw-r--r--. 1 vnstat vnstat 69632 May 28 10:35 vnstat.db
常用配置项:
| 配置项 | 默认值 | 作用 |
|---|---|---|
DatabaseDir | /var/lib/vnstat | SQLite 数据库目录 |
UpdateInterval | 20 或发行版默认 | daemon 多久读取一次接口计数器 |
PollInterval | 5 | 多久检查接口上下线 |
SaveInterval | 5 | 多久把缓存写入数据库 |
5MinuteHours | 48 | 5 分钟粒度保留多少小时 |
HourlyDays | 4 | 小时粒度保留多少天 |
DailyDays | 62 | 日粒度保留多少天 |
MonthlyMonths | 25 | 月粒度保留多少个月 |
YearlyYears | -1 | 年粒度保留多少年,-1 表示无限 |
MonthRotate | 1 | 每月从几号开始统计,适合账单周期 |
MaxBandwidth | 1000 | 异常流量过滤的带宽上限,单位 Mbit |
BandwidthDetection | 1 | 尝试自动检测接口带宽 |
UseUTC | 0 | 是否用 UTC 存储时间 |
DatabaseWriteAheadLogging | 0 | 是否启用 SQLite WAL |
> 如果运营商或 VPS 的流量账单不是自然月,例如每月 7 日重置,可以把
MonthRotate设置为7。这个设置只影响之后写入的数据,不会重算已有历史。
6.1 修改历史数据保留策略
vnstat 的历史数据保留时间由 /etc/vnstat.conf 中的 5MinuteHours、HourlyDays、DailyDays 等配置控制。默认策略比较保守,适合低占用长期运行;如果希望后续能查看更长时间的小时级或 5 分钟级趋势,可以显式调大。
本机调整目标:
5MinuteHours 2160
HourlyDays 365
DailyDays 365
其中 5MinuteHours 2160 等价于 24 * 90,表示保留 90 天的 5 分钟粒度数据。配置文件不支持写表达式,因此不能写成 24*90,必须写最终整数 2160。
实际执行命令:
sudo cp /etc/vnstat.conf /etc/vnstat.conf.bak.$(date +%F-%H%M%S)
sudo sed -i \
-e 's/^;*5MinuteHours.*/5MinuteHours 2160/' \
-e 's/^;*HourlyDays.*/HourlyDays 365/' \
-e 's/^;*DailyDays.*/DailyDays 365/' \
/etc/vnstat.conf
sudo systemctl restart vnstat
验证配置文件:
grep -nE '^(5MinuteHours|HourlyDays|DailyDays)' /etc/vnstat.conf
本机输出:
111:5MinuteHours 2160
112:HourlyDays 365
113:DailyDays 365
验证 daemon 已读取新策略:
journalctl -u vnstat -n 40 --no-pager
关键输出:
Info: Data retention: 2160 5MinuteHours, 365 HourlyDays, 365 DailyDays, 25 MonthlyMonths, -1 YearlyYears, 20 TopDayEntries
Info: Monitoring (5): wg0 (1000 Mbit) tun-int (10000 Mbit) tun-ext (10000 Mbit) enp3s0 (1000 Mbit) enp2s0 (1000 Mbit)
> 增大保留时间只影响之后的数据保留,已经被
vnstat清理掉的历史明细无法恢复。已有的日、月、年汇总仍按数据库中现存数据继续保留。
7. 告警用法
vnstat --alert 可以按小时、天、月、年或 95th percentile 做阈值判断,并用退出码配合 cron、systemd timer、脚本或监控系统。
示例:如果 enp3s0 今日 total 预计超过 10 GiB,则输出告警并返回非零状态:
vnstat -i enp3s0 --alert 2 2 d total_estimate 10 GiB
参数含义:
| 位置 | 示例值 | 含义 |
|---|---|---|
output | 2 | 只有超过 estimate limit 时输出 |
exit | 2 | 超过 estimate limit 时返回 1,否则返回 0 |
type | d | 按 day 比较 |
condition | total_estimate | 使用 total 的估算值 |
limit | 10 | 阈值数字 |
unit | GiB | 阈值单位 |
更适合脚本的写法:
if ! vnstat -i enp3s0 --alert 0 2 m total 1000 GiB; then
echo "monthly traffic exceeded"
fi
8. 底层技术细节
8.1 数据不是来自抓包
vnstat 的数据来自内核接口计数器。在 Linux 上,常见来源包括:
/proc/net/dev
/sys/class/net/<iface>/statistics/rx_bytes
/sys/class/net/<iface>/statistics/tx_bytes
这类计数器由内核网络栈或网卡驱动维护,记录接口自启动以来累计收发的字节数。vnstatd 周期性读取这些累计值,和上一次读取值做差,得到当前时间片内新增的 rx / tx。
用本机 enp3s0 举例:
ip -s link show enp3s0
输出中的 RX bytes / TX bytes 是内核计数器:
RX: bytes packets errors dropped missed mcast
35225303975 25292897 0 0 0 5008
TX: bytes packets errors dropped carrier collsns
3189468298 7368624 0 2983 0 0
vnstat 记录的是增量,不是直接保存这两个累计值作为最终结果。
8.2 daemon 与 CLI 分工
vnstat 实际上分为两个角色:
| 组件 | 作用 |
|---|---|
vnstatd | 后台 daemon,负责读取接口计数器、缓存、写 SQLite |
vnstat | 查询 CLI,负责从数据库读取并格式化输出 |
vnstati | 可选图片输出工具,生成 PNG 图 |
官方 man page 说明:vnstatd 大部分时间处于 sleep 状态,只在更新、轮询或保存周期醒来工作。因此它非常适合长期运行。
本机 systemd 启动的命令是:
/usr/sbin/vnstatd --nodaemon
在 systemd 服务里使用 --nodaemon 很常见,因为 systemd 自己负责进程管理,不需要 daemon 再 fork 到后台。
8.3 时间窗口与聚合
vnstatd 会把短周期采样聚合成多种分辨率:
5-minute -> hour -> day -> month -> year
默认保留策略来自配置:
5MinuteHours 48
HourlyDays 4
DailyDays 62
MonthlyMonths 25
YearlyYears -1
TopDayEntries 20
这意味着:
- 5 分钟明细只保留最近 48 小时
- 小时明细只保留最近 4 天
- 日统计保留 62 天
- 月统计保留 25 个月
- 年统计无限保留
如果你要做更细粒度的长期图表,需要调整保留策略。例如保留 90 天 5 分钟数据,同时把小时和日统计都扩展到 365 天:
5MinuteHours 2160
HourlyDays 365
DailyDays 365
但这样会增加 SQLite 数据库体积。vnstat 数据量仍然很小,只是没有必要无限保留高分辨率数据。调整后要重启 vnstat,并通过 journalctl -u vnstat 确认 daemon 日志里的 Data retention 已更新。
8.4 SQLite 数据库结构
本机 /var/lib/vnstat/vnstat.db 是 SQLite 数据库。当前系统没有安装 sqlite3 CLI,因此使用 Python 标准库只读查看 schema:
python3 - <<'PY'
import sqlite3
path = "/var/lib/vnstat/vnstat.db"
con = sqlite3.connect(f"file:{path}?mode=ro", uri=True)
cur = con.cursor()
print("tables:")
for (name,) in cur.execute("select name from sqlite_master where type='table' order by name"):
print("-", name)
print("\\ninterfaces:")
for row in cur.execute("select id,name,alias,active,created,updated from interface order by name"):
print(row)
con.close()
PY
输出:
tables:
- day
- fiveminute
- hour
- info
- interface
- month
- top
- year
interfaces:
(1, 'enp2s0', None, 1, '2026-05-28 08:56:57', '2026-05-28 10:35:00')
(2, 'enp3s0', None, 1, '2026-05-28 08:56:57', '2026-05-28 10:35:00')
(5, 'tun-ext', None, 1, '2026-05-28 08:56:57', '2026-05-28 10:35:00')
(4, 'tun-int', None, 1, '2026-05-28 08:56:57', '2026-05-28 10:35:00')
(3, 'wg0', None, 1, '2026-05-28 08:56:57', '2026-05-28 10:35:00')
核心表结构可以简化理解为:
interface:
id, name, alias, active, created, updated,
rxcounter, txcounter, rxtotal, txtotal
fiveminute / hour / day / month / year / top:
id, interface, date, rx, tx
其中 interface.rxcounter / txcounter 用于记录上次读取到的内核累计计数器,rxtotal / txtotal 是总累计值,各时间窗口表保存聚合后的 rx / tx。
8.5 计数器回绕、重启与异常过滤
网卡计数器可能遇到几个问题:
- 系统重启后计数器从 0 开始
- 32-bit 计数器在高流量下可能回绕
- 虚拟接口重建后计数器清零
- 驱动或系统异常导致计数器突变
vnstatd 会尝试根据启动时间、接口状态和计数器变化判断是否需要同步,而不是简单地把负数差值当作真实流量。配置项 64bitInterfaceCounters 默认自动检测;MaxBandwidth / MaxBW<iface> 用于过滤不合理的突增值。
这也是为什么在高速接口或虚拟接口较多的机器上,需要关注日志:
journalctl -u vnstat --since today --no-pager
如果日志频繁出现超出 bandwidth limit 或接口上下线,就要检查 MaxBandwidth、接口实际速率和虚拟接口生命周期。
8.6 时间与时区
默认 UseUTC 0 时,数据库使用本地时区写入。修改系统时区或系统时间不会重算旧数据。如果系统时间回拨到已经出现过的时间段,新的流量会累加到已有时间段。
建议:
- 普通本地服务器:保留
UseUTC 0 - 跨时区统一报表:考虑
UseUTC 1 - 没有 RTC 的嵌入式设备:保留或调大
TimeSyncWait
9. 可视化与集成
Vault 里已有一篇 vnstat 流量监控工具使用指南 + Grafana 可视化集成,重点讲了 Grafana 集成。这里补充几个集成路径:
9.1 vnstati 生成图片
如果安装了 vnstati 和 libgd:
vnstati -s -i enp3s0 -o summary.png
vnstati -d -i enp3s0 -o daily.png
vnstati -m -i enp3s0 -o monthly.png
适合静态 Web 页面、邮件日报或轻量 dashboard。
9.2 JSON + 脚本
vnstat -i enp3s0 --json s
脚本里可以读取 interfaces[].traffic.day[-1].rx / tx,转换成 MiB/GiB 后发通知。
9.3 Prometheus / Grafana
常见方案:
vnstat-exporter读取vnstat --json或数据库,暴露 Prometheus metrics- Prometheus 定期 scrape
- Grafana 展示日/月/接口维度流量
这种方式适合已经有 Prometheus 栈的环境。没有 Prometheus 时,直接用 JSON 输出 + cron 也足够。
9.4 Telegraf / InfluxDB
Telegraf 可以用 inputs.exec 定期执行:
[inputs.exec](/posts/inputs.exec/)
commands = ["/usr/bin/vnstat -i enp3s0 --json"]
timeout = "10s"
data_format = "json"
然后写入 InfluxDB,再由 Grafana 查询。
10. 典型使用场景
10.1 VPS 月流量防超
vnstat -m
vnstat --alert 2 2 m total_estimate 950 GiB
如果 VPS 套餐每月 1 TiB,可以在估算值接近 950 GiB 时告警。
10.2 WireGuard / 代理链路流量
vnstat -i wg0
vnstat -i tun-int
vnstat -i tun-ext
适合观察 VPN、TUN 代理或透明网关流量。注意虚拟接口流量可能和物理网卡流量重复计数,例如 wg0 上的加密隧道流量最终也会经过 enp3s0 出口。
10.3 多网卡主机
vnstat --iflist
vnstat --dbiflist
vnstat -i enp2s0
vnstat -i enp3s0
如果一个接口是 LAN,另一个是 WAN,建议设置 alias:
sudo vnstat -i enp2s0 --setalias lan
sudo vnstat -i enp3s0 --setalias wan
10.4 自然月之外的账单周期
例如账单每月 7 日重置:
MonthRotate 7
修改后重启:
sudo systemctl restart vnstat
11. 排障
11.1 没有数据
检查服务:
systemctl status vnstat --no-pager
journalctl -u vnstat --since today --no-pager
检查接口是否存在:
vnstat --iflist
ip link
检查数据库是否有接口:
vnstat --dbiflist
如果数据库没有接口:
sudo vnstat --add -i eth0
sudo systemctl restart vnstat
11.2 接口名变了
USB 网卡、虚拟网卡、容器网络重建后可能出现接口名变化。处理方式:
vnstat --iflist
vnstat --dbiflist
sudo vnstat --add -i newname
sudo vnstat --remove -i oldname
如果只是显示名不友好,优先用 alias,不要随意改系统网卡名。
11.3 统计值异常偏大
排查方向:
- 是否同时统计了物理接口和隧道接口,导致理解上重复
- 是否虚拟接口重建造成计数器重置
MaxBandwidth是否设置过低或过高- 系统时间是否跳变
- 是否存在 32-bit 计数器回绕问题
查看日志:
journalctl -u vnstat --since "2026-05-28" --no-pager
11.4 权限问题
vnstat 查询数据库通常不需要 root,但手动添加、删除接口可能需要 root。数据库默认归属:
/var/lib/vnstat/vnstat.db -> vnstat:vnstat
如果 exporter 或 Telegraf 读取失败,需要检查执行用户是否能调用 vnstat --json,不要直接给数据库乱改权限。
12. 实践建议
- 长期记账使用
vnstatd,不要用 cron 反复跑vnstat替代 daemon。 - 多接口环境先执行
vnstat --iflist和vnstat --dbiflist,确认“系统可见接口”和“数据库监控接口”是否一致。 - 虚拟接口、VPN、容器场景要注意重复统计:物理出口和隧道接口都可能记录同一业务流量的不同层面。
- 做月流量账单时关注
MonthRotate,不要默认所有账单都按自然月计算。 - 做 95th percentile 时调大
5MinuteHours,否则默认 48 小时无法覆盖整月。 - 自动化集成优先使用
--json,不要解析普通文本输出。 - 高速接口或异常值较多时检查
MaxBandwidth和日志。
13. 参考资料
- 官方主页:vnStat - a network traffic monitor for Linux and BSD
- 官方 GitHub:vergoh/vnstat
- man page:vnstat(1)
- man page:vnstatd(8)
- man page:vnstat.conf(5)
- Vault 既有笔记:vnstat 流量监控工具使用指南 + Grafana 可视化集成