Skip to content
Published on

ネットワークパフォーマンス分析完全ガイド:測定、診断、モニタリング

Authors
  • Name
    Twitter

概要

ネットワークパフォーマンスの問題は、アプリケーションの応答速度低下、ファイル転送の失敗、ストリーミング品質の劣化など、さまざまな形で現れます。問題を効果的に解決するには、コアとなるパフォーマンス指標を理解し、適切なツールを用いて体系的に診断することが不可欠です。

本記事では、ネットワークパフォーマンスの測定と分析に必要なすべての内容を取り上げます。基本指標の理解から、実務で頻繁に発生する問題シナリオの解決まで、幅広く解説します。

1. コアネットワークパフォーマンス指標

1.1 レイテンシ(遅延時間)

レイテンシは、パケットが送信元から宛先に到達するまでにかかる時間です。通常はRTT(Round Trip Time)として測定されます。

# 基本的なpingテスト
ping -c 20 target-server.example.com

# タイムスタンプ付きping
ping -c 100 -D target-server.example.com

# 出力例
# PING target-server.example.com (10.0.1.50): 56 data bytes
# 64 bytes from 10.0.1.50: icmp_seq=0 ttl=64 time=0.523 ms
# 64 bytes from 10.0.1.50: icmp_seq=1 ttl=64 time=0.481 ms
# ...
# round-trip min/avg/max/stddev = 0.481/0.512/0.623/0.042 ms

レイテンシは以下の要素で構成されています。

  • 伝搬遅延(Propagation Delay):物理的距離に比例する光速の制限
  • 伝送遅延(Transmission Delay):データをリンクに載せる時間(パケットサイズ / 帯域幅)
  • 処理遅延(Processing Delay):ルータでパケットヘッダを処理する時間
  • キューイング遅延(Queuing Delay):ルータバッファで待機する時間
# レイテンシ分布の詳細分析スクリプト
#!/bin/bash
TARGET="target-server.example.com"
COUNT=1000

echo "=== Latency Distribution Analysis ==="
ping -c $COUNT $TARGET | tail -1

# hping3を使用したTCPベースのレイテンシ測定(ICMPがブロックされている場合に有効)
sudo hping3 -S -p 443 -c 20 $TARGET

1.2 スループット

スループットは、単位時間あたりに実際に転送されるデータ量です。帯域幅(bandwidth)と混同されがちですが、帯域幅は理論上の最大容量であり、スループットは実際に達成可能な転送レートです。

# iperf3でTCPスループットを測定
# サーバ側
iperf3 -s -p 5201

# クライアント側 - 基本テスト
iperf3 -c server-ip -p 5201 -t 30

# 双方向同時テスト
iperf3 -c server-ip -p 5201 -t 30 --bidir

# 出力例
# [ ID] Interval           Transfer     Bitrate         Retr
# [  5]   0.00-30.00  sec  3.28 GBytes   939 Mbits/sec   12  sender
# [  5]   0.00-30.00  sec  3.27 GBytes   937 Mbits/sec       receiver

1.3 パケットロス

パケットロスは、送信されたパケットのうち宛先に到達しなかった割合です。1%以上のロスは、目に見えるパフォーマンス低下を引き起こします。

# パケットロスの測定
ping -c 1000 -i 0.01 target-server.example.com

# mtrでホップごとのパケットロスを確認
mtr -r -c 100 target-server.example.com

# 出力例
# HOST: myhost                     Loss%   Snt   Last   Avg  Best  Wrst StDev
#  1.|-- gateway                    0.0%   100    0.5   0.6   0.3   1.2   0.2
#  2.|-- isp-router                 0.0%   100    3.2   3.5   2.8   5.1   0.5
#  3.|-- core-router                2.0%   100    8.1  12.3   7.5  45.2   8.1
#  4.|-- target-server              2.0%   100   10.2  14.1   9.8  48.3   9.2

1.4 ジッタ

ジッタは、パケット到着時間の変動幅です。VoIPやビデオ通話などのリアルタイム通信では特に重要です。

# iperf3 UDPモードでジッタを測定
# サーバ
iperf3 -s

# クライアント - UDPモード、100Mbpsターゲット
iperf3 -c server-ip -u -b 100M -t 30

# 出力例
# [ ID] Interval           Transfer     Bitrate         Jitter    Lost/Total
# [  5]   0.00-30.00  sec   358 MBytes   100 Mbits/sec  0.042 ms  12/45892 (0.026%)

2. ネットワーク診断ツール

2.1 iperf3 - 帯域幅テスト

iperf3は、ネットワーク帯域幅の測定に最も広く使用されているツールです。

# マルチストリームテスト(並列接続でフル帯域幅を活用)
iperf3 -c server-ip -P 4 -t 30

# 帯域幅制限付きテスト
iperf3 -c server-ip -b 500M -t 30

# TCPウィンドウサイズ指定
iperf3 -c server-ip -w 256K -t 30

# JSON形式の出力(自動化に便利)
iperf3 -c server-ip -t 30 -J > iperf3_result.json

# 逆方向テスト(サーバからクライアント方向)
iperf3 -c server-ip -R -t 30

# MSS設定
iperf3 -c server-ip -M 1400 -t 30

# レポート間隔の設定
iperf3 -c server-ip -t 60 -i 5

2.2 mtr - 経路分析

mtrはtracerouteとpingを組み合わせたツールで、ネットワーク経路の各ホップでのパフォーマンスを継続的にモニタリングします。

# 基本レポートモード
mtr -r -c 200 target-server.example.com

# TCPモード(ICMPブロック環境)
mtr -r -c 100 -T -P 443 target-server.example.com

# UDPモード
mtr -r -c 100 -u target-server.example.com

# 詳細レポート(AS番号含む)
mtr -r -c 200 -w -z target-server.example.com

# CSV出力
mtr -r -c 100 --csv target-server.example.com > mtr_report.csv

mtrの結果を解釈する際の注意点は以下の通りです。

  • 中間ホップでのみロスが見られ、最終宛先でロスがない場合、ICMPレートリミティングの可能性が高い
  • 特定のホップからレイテンシが急増する場合、その区間がボトルネック
  • 最後の数ホップでロスが増加する場合、実際の問題がある可能性が高い

2.3 traceroute

# ICMP traceroute
traceroute target-server.example.com

# TCP traceroute(ファイアウォール回避に有効)
sudo traceroute -T -p 443 target-server.example.com

# UDP traceroute(特定ポート)
traceroute -U -p 33434 target-server.example.com

# 最大ホップ数指定
traceroute -m 30 target-server.example.com

# Paris-traceroute(ロードバランサ環境での正確な経路追跡)
paris-traceroute target-server.example.com

2.4 netperf - 高度なパフォーマンステスト

# netperfサーバの起動
netserver -p 12865

# TCPストリームテスト
netperf -H server-ip -p 12865 -t TCP_STREAM -l 30

# TCP RR(Request/Response)テスト - トランザクション性能測定
netperf -H server-ip -p 12865 -t TCP_RR -l 30

# TCP CRR(Connect/Request/Response)- コネクション確立含む
netperf -H server-ip -p 12865 -t TCP_CRR -l 30

# メッセージサイズ指定
netperf -H server-ip -t TCP_STREAM -l 30 -- -m 65536

# UDPストリームテスト
netperf -H server-ip -t UDP_STREAM -l 30

3. 帯域幅テストとボトルネックの特定

3.1 体系的な帯域幅テスト

#!/bin/bash
# bandwidth_test.sh - 体系的な帯域幅テストスイート

SERVER="10.0.1.50"
PORT=5201
DURATION=30
LOGDIR="/var/log/bandwidth_tests"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)

mkdir -p $LOGDIR

echo "=== Bandwidth Test Suite - $TIMESTAMP ==="

# 1. シングルストリームTCP
echo "[1/5] Single Stream TCP Test"
iperf3 -c $SERVER -p $PORT -t $DURATION -J > "$LOGDIR/tcp_single_${TIMESTAMP}.json"

# 2. マルチストリームTCP
echo "[2/5] Multi Stream TCP Test (4 streams)"
iperf3 -c $SERVER -p $PORT -t $DURATION -P 4 -J > "$LOGDIR/tcp_multi_${TIMESTAMP}.json"

# 3. リバースTCP
echo "[3/5] Reverse TCP Test"
iperf3 -c $SERVER -p $PORT -t $DURATION -R -J > "$LOGDIR/tcp_reverse_${TIMESTAMP}.json"

# 4. UDP帯域幅
echo "[4/5] UDP Bandwidth Test"
iperf3 -c $SERVER -p $PORT -t $DURATION -u -b 1G -J > "$LOGDIR/udp_${TIMESTAMP}.json"

# 5. 双方向同時
echo "[5/5] Bidirectional Test"
iperf3 -c $SERVER -p $PORT -t $DURATION --bidir -J > "$LOGDIR/bidir_${TIMESTAMP}.json"

echo "=== Tests Complete. Results in $LOGDIR ==="

3.2 ボトルネックの特定

# ステップ1: ローカルインターフェース速度の確認
ethtool eth0 | grep -i speed
# Speed: 10000Mb/s

# ステップ2: ループバック性能の確認(NIC/CPU限界の把握)
iperf3 -c 127.0.0.1 -t 10

# ステップ3: 同一スイッチ内のサーバ間テスト
iperf3 -c same-switch-server -t 30

# ステップ4: 異なるサブネットのサーバテスト(ルーティングの影響)
iperf3 -c different-subnet-server -t 30

# ステップ5: WAN区間テスト
iperf3 -c remote-server -t 30

# 各ステップでスループットが大幅に低下する区間がボトルネック

4. ネットワークインターフェース統計とエラーカウンタ

4.1 ethtool統計

# インターフェース基本情報
ethtool eth0

# 詳細統計
ethtool -S eth0

# 主要確認項目
ethtool -S eth0 | grep -E "(rx_errors|tx_errors|rx_dropped|tx_dropped|rx_crc|collisions)"

# ドライバ情報
ethtool -i eth0

# リングバッファサイズの確認
ethtool -g eth0

# リングバッファサイズの調整(ドロップ削減のため)
sudo ethtool -G eth0 rx 4096 tx 4096

# オフロード設定の確認
ethtool -k eth0

# TSO/GSO/GRO設定
sudo ethtool -K eth0 tso on gso on gro on

4.2 ipコマンドによるインターフェース統計

# インターフェース統計サマリ
ip -s link show eth0

# 出力例
# 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...
#     RX: bytes  packets  errors  dropped overrun mcast
#     948271623  1523847  0       0       0       12847
#     TX: bytes  packets  errors  dropped carrier collsns
#     523841267  892341   0       0       0       0

# 詳細統計
ip -s -s link show eth0

# 全インターフェース統計
ip -s link show

# 統計変化量の追跡スクリプト
#!/bin/bash
IFACE="eth0"
while true; do
    echo "=== $(date) ==="
    ip -s link show $IFACE | grep -A 2 "RX\|TX"
    sleep 5
done

4.3 エラーカウンタのモニタリング

# /proc/net/devからリアルタイム統計確認
cat /proc/net/dev

# netstat -iによるインターフェース統計
netstat -i

# エラーカウンタの継続モニタリングスクリプト
#!/bin/bash
IFACE="eth0"
INTERVAL=10

echo "Monitoring $IFACE errors every ${INTERVAL}s..."
echo "Time | RX_errors | TX_errors | RX_dropped | TX_dropped"

while true; do
    STATS=$(ip -s link show $IFACE)
    RX_ERR=$(echo "$STATS" | awk '/RX:/{getline; print $3}')
    TX_ERR=$(echo "$STATS" | awk '/TX:/{getline; print $3}')
    RX_DROP=$(echo "$STATS" | awk '/RX:/{getline; print $4}')
    TX_DROP=$(echo "$STATS" | awk '/TX:/{getline; print $4}')
    echo "$(date +%H:%M:%S) | $RX_ERR | $TX_ERR | $RX_DROP | $TX_DROP"
    sleep $INTERVAL
done

5. TCPウィンドウ分析と輻輳制御

5.1 TCPウィンドウサイズ分析

# 現在のTCP接続のウィンドウサイズを確認
ss -ti dst target-server.example.com

# 出力例
# State  Recv-Q  Send-Q  Local Address:Port  Peer Address:Port
# ESTAB  0       0       10.0.1.10:42856     10.0.1.50:443
#   cubic wscale:7,7 rto:204 rtt:1.523/0.742 ato:40 mss:1448
#   pmtu:1500 rcvmss:1448 advmss:1448 cwnd:10 ssthresh:7
#   bytes_sent:15234 bytes_acked:15235 bytes_received:45678
#   send 76.1Mbps pacing_rate 152.1Mbps delivery_rate 45.2Mbps

# 主要フィールドの説明
# cwnd: 輻輳ウィンドウサイズ(セグメント数)
# ssthresh: スロースタート閾値
# rtt: ラウンドトリップ時間 / 標準偏差
# mss: 最大セグメントサイズ

5.2 TCP輻輳制御アルゴリズム

# 現在使用中の輻輳制御アルゴリズムを確認
sysctl net.ipv4.tcp_congestion_control
# net.ipv4.tcp_congestion_control = cubic

# 利用可能なアルゴリズム一覧
sysctl net.ipv4.tcp_available_congestion_control
# net.ipv4.tcp_available_congestion_control = reno cubic bbr

# BBRに変更
sudo sysctl -w net.ipv4.tcp_congestion_control=bbr

# BBR使用のためのfqスケジューラ設定
sudo tc qdisc replace dev eth0 root fq

# TCPバッファサイズチューニング
# 最小/デフォルト/最大(バイト)
sudo sysctl -w net.ipv4.tcp_rmem="4096 131072 16777216"
sudo sysctl -w net.ipv4.tcp_wmem="4096 65536 16777216"

# TCPウィンドウスケーリングの有効化
sudo sysctl -w net.ipv4.tcp_window_scaling=1

5.3 tcpdumpによるTCP分析

# TCPハンドシェイクのキャプチャ
sudo tcpdump -i eth0 -c 50 'tcp[tcpflags] & (tcp-syn|tcp-fin) != 0' -nn

# 特定ホストとのTCP通信をキャプチャ
sudo tcpdump -i eth0 host target-server.example.com -w capture.pcap

# 再送パケットの確認
sudo tcpdump -i eth0 'tcp[tcpflags] & tcp-syn != 0' -nn

# ゼロウィンドウパケットの検出
sudo tcpdump -i eth0 'tcp[14:2] = 0' -nn

# キャプチャファイルをtsharkで分析
tshark -r capture.pcap -q -z io,stat,1
tshark -r capture.pcap -q -z conv,tcp

6. MTUとフラグメンテーション問題

6.1 MTU確認とパスMTU探索

# インターフェースMTUの確認
ip link show eth0 | grep mtu

# パスMTU探索(Path MTU Discovery)
# DFビットを設定してフラグメンテーションなしで送信を試みる
ping -c 5 -M do -s 1472 target-server.example.com
# PING target-server.example.com: 1472 data bytes
# 1480 bytes from 10.0.1.50: icmp_seq=1 ttl=64 time=0.523 ms

# パケットサイズを減らしながら最大MTUを探索
ping -c 3 -M do -s 1473 target-server.example.com
# ping: local error: message too long, mtu=1500

# 自動MTU探索スクリプト
#!/bin/bash
TARGET=$1
SIZE=1500

while [ $SIZE -gt 0 ]; do
    ping -c 1 -M do -s $SIZE $TARGET > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        echo "Path MTU: $((SIZE + 28)) bytes (payload: $SIZE + 20 IP + 8 ICMP)"
        break
    fi
    SIZE=$((SIZE - 1))
done

6.2 フラグメンテーション問題の診断

# フラグメンテーション統計の確認
cat /proc/net/snmp | grep -i frag
# Ip: ... FragCreates FragOKs FragFails

# netstatでフラグメンテーションを確認
netstat -s | grep -i frag

# フラグメンテーション発生のリアルタイムモニタリング
watch -n 1 'cat /proc/net/snmp | grep Ip: | head -2'

# MTUの変更
sudo ip link set dev eth0 mtu 9000  # Jumbo Frame

# PMTUDステータスの確認
sysctl net.ipv4.ip_no_pmtu_disc
# 0 = PMTUD有効(推奨)

6.3 Jumbo Frameの設定と検証

# Jumbo Frameサポートの確認
ethtool -i eth0

# Jumbo Frameの有効化
sudo ip link set dev eth0 mtu 9000

# Jumbo Frame経路の検証
ping -c 5 -M do -s 8972 target-server.example.com

# Jumbo Frameのパフォーマンス比較
echo "=== MTU 1500 ==="
iperf3 -c server-ip -t 10 -M 1460
echo "=== MTU 9000 ==="
iperf3 -c server-ip -t 10 -M 8960

7. Prometheus/Grafanaによるネットワークモニタリング

7.1 node_exporterの設定

# /etc/prometheus/prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'node'
    static_configs:
      - targets:
          - 'server1:9100'
          - 'server2:9100'
          - 'server3:9100'
    scrape_interval: 5s

node_exporterが収集する主要なネットワークメトリクスは以下の通りです。

  • node_network_receive_bytes_total: 受信バイト総計
  • node_network_transmit_bytes_total: 送信バイト総計
  • node_network_receive_errs_total: 受信エラー総計
  • node_network_transmit_errs_total: 送信エラー総計
  • node_network_receive_drop_total: 受信ドロップ総計
  • node_network_transmit_drop_total: 送信ドロップ総計

7.2 PromQLクエリの例

# インターフェースごとの受信トラフィックレート(bps)
rate(node_network_receive_bytes_total{device!="lo"}[5m]) * 8

# インターフェースごとの送信トラフィックレート(bps)
rate(node_network_transmit_bytes_total{device!="lo"}[5m]) * 8

# パケットエラー率(%)
rate(node_network_receive_errs_total{device="eth0"}[5m])
  / rate(node_network_receive_packets_total{device="eth0"}[5m]) * 100

# パケットドロップ率
rate(node_network_receive_drop_total{device="eth0"}[5m])

# 帯域幅使用率(%)
rate(node_network_receive_bytes_total{device="eth0"}[5m]) * 8
  / node_network_speed_bytes{device="eth0"} / 8 * 100

# TCP再送率
rate(node_netstat_Tcp_RetransSegs[5m])
  / rate(node_netstat_Tcp_OutSegs[5m]) * 100

# 状態別TCP接続数
node_netstat_Tcp_CurrEstab

7.3 Grafanaアラートルール

# Grafana Alert Rules
groups:
  - name: network_alerts
    rules:
      - alert: HighPacketLoss
        expr: |
          rate(node_network_receive_errs_total{device="eth0"}[5m])
          / rate(node_network_receive_packets_total{device="eth0"}[5m]) > 0.01
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: 'High packet loss on {{ $labels.instance }}'
          description: 'Packet loss rate is {{ $value | humanize }}%'

      - alert: HighBandwidthUsage
        expr: |
          rate(node_network_receive_bytes_total{device="eth0"}[5m]) * 8
          / 10000000000 > 0.85
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: 'High bandwidth usage on {{ $labels.instance }}'

      - alert: NetworkInterfaceDown
        expr: node_network_up{device="eth0"} == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: 'Network interface down on {{ $labels.instance }}'

      - alert: HighTcpRetransmission
        expr: |
          rate(node_netstat_Tcp_RetransSegs[5m])
          / rate(node_netstat_Tcp_OutSegs[5m]) > 0.05
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: 'High TCP retransmission rate on {{ $labels.instance }}'

7.4 SNMP Exporterの活用

# SNMP exporter設定(ネットワーク機器のモニタリング)
# /etc/prometheus/snmp.yml(generatorで生成)

# prometheus.ymlにSNMPターゲットを追加
scrape_configs:
  - job_name: 'snmp'
    static_configs:
      - targets:
          - 'switch01.example.com'
          - 'router01.example.com'
    metrics_path: /snmp
    params:
      module: [if_mib]
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: snmp-exporter:9116

8. 実務パフォーマンス診断シナリオ

8.1 シナリオ:アプリケーション応答遅延

# ステップ1: DNS解決遅延のチェック
dig target-server.example.com | grep "Query time"
# Query time: 245 msec  <-- DNSが遅い

# 解決策: ローカルDNSキャッシュまたはより高速なDNSサーバの使用
# /etc/resolv.confのnameserverを変更

# ステップ2: TCPコネクション確立時間の確認
curl -o /dev/null -s -w "\
  DNS: %{time_namelookup}s\n\
  Connect: %{time_connect}s\n\
  TLS: %{time_appconnect}s\n\
  TTFB: %{time_starttransfer}s\n\
  Total: %{time_total}s\n" \
  https://target-server.example.com

# ステップ3: 経路上の問題を確認
mtr -r -c 50 target-server.example.com

8.2 シナリオ:ファイル転送速度の低下

# ステップ1: ローカルインターフェースの状態確認
ethtool eth0 | grep -E "(Speed|Duplex|Link)"
# Speed: 1000Mb/s
# Duplex: Full
# Link detected: yes

# オートネゴシエーション失敗で100Mbpsに固定された場合
sudo ethtool -s eth0 speed 1000 duplex full autoneg on

# ステップ2: エラーカウンタの確認
ethtool -S eth0 | grep -E "(error|drop|crc|collision)"

# ステップ3: TCPチューニング状態の確認
sysctl net.ipv4.tcp_rmem
sysctl net.ipv4.tcp_wmem
sysctl net.core.rmem_max
sysctl net.core.wmem_max

# ステップ4: 帯域幅の測定
iperf3 -c remote-server -t 30 -P 4

8.3 シナリオ:間欠的な接続断

# ステップ1: 長時間pingでパターンを把握
ping -c 3600 -i 1 target-server.example.com | while read line; do
    echo "$(date '+%Y-%m-%d %H:%M:%S') $line"
done | tee ping_log.txt

# ステップ2: インターフェースフラッピングの確認
dmesg | grep -i "link\|eth0\|carrier"
journalctl -u NetworkManager --since "1 hour ago" | grep -i "disconnect\|connect"

# ステップ3: ARPテーブルの異常確認
ip neigh show | grep -i "FAILED\|STALE"

# ステップ4: スイッチポート統計の確認(SNMPまたは管理インターフェース)
snmpwalk -v2c -c public switch01 IF-MIB::ifOperStatus
snmpwalk -v2c -c public switch01 IF-MIB::ifInErrors

8.4 シナリオ:VoIP品質問題

# ステップ1: ジッタとパケットロスの測定
iperf3 -c voip-server -u -b 100K -t 60 -l 160
# VoIPは通常64-160バイトの小さなパケットを使用

# ステップ2: QoS設定の確認
tc qdisc show dev eth0
tc class show dev eth0
tc filter show dev eth0

# ステップ3: QoSポリシーの適用(VoIPトラフィックの優先)
sudo tc qdisc add dev eth0 root handle 1: htb default 30
sudo tc class add dev eth0 parent 1: classid 1:1 htb rate 1000mbit
sudo tc class add dev eth0 parent 1:1 classid 1:10 htb rate 100mbit ceil 200mbit prio 1
sudo tc class add dev eth0 parent 1:1 classid 1:30 htb rate 900mbit ceil 1000mbit prio 3

# VoIPトラフィックを高優先度クラスに分類
sudo tc filter add dev eth0 parent 1: protocol ip prio 1 \
    u32 match ip dport 5060 0xffff flowid 1:10

まとめ

ネットワークパフォーマンス分析は、以下の順序で体系的にアプローチすることが重要です。

  1. 指標の収集: レイテンシ、スループット、パケットロス、ジッタを測定する
  2. 区間分析: mtr、tracerouteで問題区間を特定する
  3. インターフェース検査: ethtool、ipコマンドで物理的な問題を確認する
  4. プロトコル分析: TCPウィンドウ、輻輳制御の状態を点検する
  5. MTU確認: パスMTUとフラグメンテーション問題を検証する
  6. 継続モニタリング: Prometheus/Grafanaでトレンドを観察する

各ステップで正しいツールを選択し、結果を正確に解釈する能力が重要です。単一のツールに依存せず、複数のツールの結果をクロスバリデーションして、問題の根本原因を正確に特定してください。