LinuxでvnStatを使った長期ネットワーク帯域幅モニタリング:使用量の追跡・分析・レポートエクスポート

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

背景とvnStatが必要な理由

ほとんどのネットワーク監視ツールは、パケットレート、アクティブな接続数、現在のスループットなど、今この瞬間の状況を表示します。それはスパイクの診断には役立ちますが、過去3ヶ月間の帯域幅消費量については何も教えてくれません。クラウドプロバイダーから予想外の超過請求書が届いたり、ISPが予告なくスロットリングをかけてきたりしたとき、必要なのはリアルタイムのグラフではなく、履歴データです。

そのギャップを埋めるのがvnStatです。軽量なデーモンとして動作し、カーネル自身のカウンターからインターフェース統計を読み取って、ローカルデータベースに蓄積します。時間、日、月、年単位で使用量をクエリできます。パケットキャプチャは不要で、レポートを取得するためだけにroot権限も必要ありません。

VPSインスタンスとベアメタルサーバーの両方で本番環境にvnStatを導入してきましたが、その信頼性の高さから、もはや意識することがなくなりました。1日あたり約5万リクエストを処理する稼働中のWebサーバーで1年間運用した後、月ごとのクリーンなトラフィックデータが蓄積され、CDNの請求書と照合して請求の不整合を発見することができました。リソースフットプリントは非常に小さく、RAMは約1〜2MB、定期的なディスク書き込みのみです。

iftopやnethogsといった代替ツールとvnStatを分けるポイントの一つは、再起動後も継続して動作することです。ネットワークをスニッフィングするのではなくカーネルカウンターを読み取るため、カウンターがロールオーバーした時点でデーモンが動作していた限り、インターフェース再起動後も正しく合計値を再構築します。

インストール

vnStatのパッケージは、主要なディストリビューションのデフォルトリポジトリに含まれています。PPAやサードパーティのソースは不要です。

Debian / Ubuntu

sudo apt update
sudo apt install vnstat -y

RHEL / CentOS / Rocky Linux / AlmaLinux

# EPELが未インストールの場合は先に有効化する
sudo dnf install epel-release -y
sudo dnf install vnstat -y

Arch Linux

sudo pacman -S vnstat

先に進む前に、バージョンを確認しておきましょう。vnStat 2.x(2019年リリース)ではデータベース形式が刷新され、JSONエクスポートが追加されています。このガイドはこの2点に依存しています:

vnstat --version

期待される出力は以下のようになります:

vnStat 2.12 by Teemu Toivola <tst at iki dot fi>

設定

デーモンの起動

データ収集はすべてデーモン(vnstatd)が担います。systemdで有効化して起動します:

sudo systemctl enable vnstat
sudo systemctl start vnstat
sudo systemctl status vnstat

デフォルトでは、設定された各インターフェースを5分ごとにポーリングします。データは/var/lib/vnstat/に保存され、インターフェースごとに1つのデータベースファイルが作成されます。

監視インターフェースの追加

デーモンは起動時にインターフェースを自動検出します。VPNトンネルや追加NICなど、後からインターフェースを追加した場合は、手動で登録できます:

# 利用可能なインターフェースを一覧表示する
ip link show

# インターフェースを手動で追加する
sudo vnstat --add -i eth0

# クラウドインスタンスでインターフェース名が異なる場合
sudo vnstat --add -i ens3

追加後は、デーモンがデータ収集を開始するまで数分待ちましょう。最初のクエリは空や不完全な結果になることがありますが、これは正常です。意味のある時間別データが得られるまで15〜30分ほどかかります。

設定ファイルの編集

メインの設定ファイルは/etc/vnstat.confにあります。調整する価値のある設定をいくつか紹介します:

sudo nano /etc/vnstat.conf

確認すべき主なオプション:

# デフォルトで監視するインターフェース(1つしかない場合に便利)
Interface "eth0"

# デーモンのポーリング間隔(秒単位、デフォルト300)
UpdateInterval 300

# データベースに保持する日数/月数/年数
SaveInterval 5
OfflineSaveInterval 30

# 日次統計の最大保存日数(0 = 無制限)
DailyDays 365

# 最大保存月数
MonthlyMonths 25

1年以上運用する予定のサーバーでは、DailyDays730MonthlyMonths36に設定しています。3年分の日次レコードがあってもデータベースは500KB以下とコンパクトに保たれます。履歴を捨てる理由はありません。

編集後はデーモンを再起動します:

sudo systemctl restart vnstat

確認とモニタリング

基本的な使用量クエリ

デーモンがしばらく動作したら、クエリを実行してみましょう。引数なしでvnstatを実行すると、監視対象の全インターフェースのサマリーが表示されます:

vnstat

出力例:

                      rx      /      tx      /     total    /   estimated
 eth0:
       2024-05     45.23 GiB  /   12.67 GiB  /   57.90 GiB  /   61.20 GiB
       2024-06      3.10 GiB  /    0.87 GiB  /    3.97 GiB  /   63.52 GiB
     estimated     63.52 GiB  /   17.83 GiB  /   81.35 GiB

estimatedの行は当月の使用量を外挿したものです。請求サイクルがリセットされる前に月間上限を超えるかどうかを把握するのに役立ちます。

期間別詳細レポート

# 日次内訳(直近30日)
vnstat -d

# 時間別内訳(直近24時間)
vnstat -h

# 月次サマリー
vnstat -m

# 年次合計
vnstat -y

# 5分間隔(最も詳細、直近数時間)
vnstat -5

# インターフェースを明示的に指定
vnstat -i eth0 -m

リアルタイムトラフィックレート

現在のスループットをすばやく確認したいですか?iftopは不要です。vnStatの組み込みライブモードで十分なサニティチェックができます:

# ライブビュー — 毎秒更新
vnstat -l -i eth0

iftopより軽量で、「トラフィックは流れているか?」という感覚的な確認には申し分ありません。

JSONへのデータエクスポート

何度も重宝しているのがJSONエクスポートです。出力をそのままスクリプトやダッシュボードにパイプできます。正規表現も、壊れやすいテキスト解析も不要です。

# インターフェースの完全なJSONダンプ
vnstat -i eth0 --json

# 月次データのみをJSONで取得
vnstat -i eth0 --json m

# 日次データをJSONで取得
vnstat -i eth0 --json d

月次合計を解析して表示するシンプルなPythonスクリプト:

import subprocess
import json

result = subprocess.run(
    ["vnstat", "-i", "eth0", "--json", "m"],
    capture_output=True, text=True
)
data = json.loads(result.stdout)

for entry in data["interfaces"][0]["traffic"]["month"]:
    year = entry["date"]["year"]
    month = entry["date"]["month"]
    rx_gb = entry["rx"] / 1024**3
    tx_gb = entry["tx"] / 1024**3
    print(f"{year}-{month:02d}  RX: {rx_gb:.2f} GB  TX: {tx_gb:.2f} GB")

シンプルな帯域幅アラートの設定

月間上限のある従量課金VPSを使っていますか?上限に達する前にこのcronスクリプトを仕掛けておきましょう。月間RXが80GBを超えるとメールで通知します:

#!/bin/bash
# /usr/local/bin/check_bandwidth.sh

LIMIT_GB=80
RX_BYTES=$(vnstat -i eth0 --json m | python3 -c "
import sys, json
d = json.load(sys.stdin)
entries = d['interfaces'][0]['traffic']['month']
if entries: print(entries[-1]['rx'])
else: print(0)
")

RX_GB=$(echo "scale=2; $RX_BYTES / 1073741824" | bc)

if (( $(echo "$RX_GB > $LIMIT_GB" | bc -l) )); then
    echo "警告: 月間RXは${RX_GB} GBです(上限: ${LIMIT_GB} GB)" \
    | mail -s "帯域幅アラート: eth0" [email protected]
fi

毎日実行するようにcronに追加します:

crontab -e
# 以下を追加:
0 9 * * * /usr/local/bin/check_bandwidth.sh

データベース移行後の履歴データの確認

サーバーを移行したり、クリーンインストールをしたりする場合は、デーモンを起動する前に/var/lib/vnstat/を新しいマシンにコピーすれば、全履歴を引き継げます。同じvnStatバージョン間であれば、データ形式の互換性があります。

1.xから2.xへのアップグレードは話が別で、エクスポートと再インポートが必要です。vnStat 2.xのパッケージには、通常そのための移行ツールが同梱されています。

実際の運用から得たTips

  • インターフェース名を固定する。クラウドプロバイダーが再起動時にインターフェース名を変更する場合(例:ens3ens4になるなど)、vnStatは新しい名前に対して新しいデータベースを作成し、履歴が2つに分かれてしまいます。udevルールで名前を固定するか、プロバイダーのドキュメントを確認してください。
  • 複数のインターフェースを個別に監視する。パブリックとプライベート両方のNICを持つサーバーでは、それぞれ独立してトラッキングしましょう。プライベートVLAN上のDockerコンテナ間など、内部トラフィックは間違ったインターフェースを監視していると合計値を不正確に膨らませることがあります。
  • ssまたはnethogsをプロセス別の特定に組み合わせる。vnStatはインターフェースごとの合計を提供しますが、プロセスごとの情報はありません。数値が急増した場合は、ss -tulnpまたはnethogsで原因プロセスを特定し、vnStatの時間別データと照合していつ始まったかを確認しましょう。
  • データベースディレクトリを定期的に確認する。デフォルト設定では、/var/lib/vnstat/は数年分のデータがあっても10MB以下に収まります。予期しない増加は通常、Interfaceエントリの設定ミスにより、カウンターが膨張したループバックや仮想インターフェースを追跡していることを示しています。
Share: