業務リクエストがときどきタイムアウトし、インターフェースの受信ドロップカウンターも増えているからといって、NICの故障とは限りません。物理サーバーの受信経路には、NICのキュー、ドライバー、ソフトウェア割り込み(softirq)、プロトコルスタックが含まれ、同じ症状が異なる層で発生することがあります。調査では、業務エラーと同じ時間帯のカウンター増分を照合する必要があります。droppedが見えたというだけで、すべてのバッファーを拡大してはいけません。
以下ではDebian 12を例に説明します。管理者権限と、iproute2、ethtool、sysstat、python3の各ツールが必要です。AmdMetalの物理サーバーでは、支払い後にコンソールで接続情報を確認でき、SSHには最初のIPv4アドレスを使用します。この記事では、まず読み取り専用の採取を行い、アドレスやルーティングは変更しません。
1. 受信インターフェースと障害の発生時間帯を特定する
まずip -br addressで業務用アドレスが設定されているインターフェースを確認し、VLAN、ブリッジ、ボンディングデバイスをたどって、実際にトラフィックを処理している物理インターフェースを特定します。名前順で先頭にあるNICをそのまま選んではいけません。次のコマンドでは対話入力でインターフェースを指定し、採取用ディレクトリを自動作成します。
read -r -p "Physical interface: " IFACE
ip link show dev "$IFACE" || exit 1
D=$(mktemp -d /var/tmp/rx-audit.XXXXXX)
printf '%s\n' "$IFACE" > "$D/interface"
uname -r > "$D/kernel"
ethtool -i "$IFACE" > "$D/driver"
ip -d link show dev "$IFACE" > "$D/link"
printf '%s\n' "$D"
業務エラーの発生時刻、リクエスト数、パケットサイズ、一括インポートの有無を記録します。インターフェースの累積カウンターには長期間の稼働分が含まれている可能性があるため、直近で発生した1回のタイムアウトと直接結び付けて因果関係を判断することはできません。ドライバーの再読み込み、再起動、インターフェースの再作成によって、カウンターがリセットされることもあります。
NIC統計、インターフェース統計、プロトコルスタック統計は、そのまま足し合わせられる独立した集計ではありません。同じ事象を表すフィールドもあるため、まずドライバーでの定義を確認してから増分を解釈する必要があります。
アプリケーションがネットワーク名前空間内で動作している場合、物理インターフェースで確認できるのはホスト側の受信経路です。プロトコルスタック統計は、アプリケーションが属する名前空間でも採取する必要があります。ホストでエラーが出ていないからといって、コンテナ内部も正常とは限りません。
2. インターフェース統計とドライバー統計を併せて保存する
同じシェルで続けて実行します。この例の観測期間は30秒ですが、これは採取パラメーターであり、サービス上の約束ではありません。実際に問題が発生する業務の時間帯を選び、正常な時間帯でも同じ長さの比較用データを1組採取します。
snapshot() {
label=$1
date -Is > "$D/$label.time"
ip -s -s link show dev "$IFACE" > "$D/$label.link"
ethtool -S "$IFACE" > "$D/$label.nic" 2>&1
cat /proc/net/softnet_stat > "$D/$label.softnet"
nstat -az > "$D/$label.protocol"
}
snapshot before
mpstat -P ALL 1 30 > "$D/cpu"
snapshot after
diff -u "$D/before.nic" "$D/after.nic"
これらの読み取りは順番に実行されるため、アトミックなスナップショットではありません。短いバーストが発生する状況では、タイムスタンプと併せて解釈する必要があり、異なるファイル間でパケット単位の一致を求めることはできません。ethtool -Sが非対応を返した場合も、その結果を保存します。「統計が取得できない」を「パケット損失がない」と記録してはいけません。
まずカウンターの意味を確認する
名前にCRCやframeを含むエラーカウンターが増えている場合は、リンク層の証拠を確認します。missed、no_buffer、discardを含むフィールドについては、現在のドライバーでの定義を調べる必要があります。受信ディスクリプター、デバイスのバッファー、フィルタリング動作に関係している可能性があり、英語の名前だけで原因を判断することはできません。
ethtool -g "$IFACE"とethtool -l "$IFACE"の結果も保存し、それぞれリングキューとチャネルの情報を確認します。これらの照会に対応していないこと自体は、障害を意味しません。最大値はデバイスの対応範囲の上限であり、本番環境での推奨値ではありません。
3. CPU別にsoftnetの増分を計算する
/proc/net/softnet_statは16進数表記で、先頭の3列は順にprocessed、dropped、time_squeezeです。それ以降の列はカーネルによって変わる可能性があるため、今回は解析しません。次のコードは行ごとに比較し、採取データの行番号を出力します。CPUのホットプラグが発生した場合は再採取し、行の対応付けを機械的に続けてはいけません。
python3 - "$D/before.softnet" "$D/after.softnet" <<'PY'
import sys
from pathlib import Path
def load(path):
return [
[int(v, 16) for v in line.split()[:3]]
for line in Path(path).read_text().splitlines()
]
before, after = map(load, sys.argv[1:])
if len(before) != len(after):
raise SystemExit("CPU layout changed; sample again")
print("row processed_delta dropped_delta time_squeeze_delta")
for row, (old, new) in enumerate(zip(before, after)):
delta = [b - a for a, b in zip(old, new)]
if any(v < 0 for v in delta):
raise SystemExit("Counter reset or wrap; sample again")
print(row, *delta)
PY
ここでのdroppedの増加は、ソフトウェア受信バックログキューでドロップが発生したことを示します。time_squeezeの増加は、処理サイクルが予算の上限に達したことを意味し、すでにパケット損失が発生したという意味ではありません。softnet統計はCPU単位の集計であり、特定のNIC専用の統計ではないため、同じ時間帯の他のインターフェースのトラフィックによる影響を除外する必要があります。
増分をmpstatの%softと照合します。サーバー全体のCPUに余裕があっても、特定のコアに受信処理の負荷が集中することがあるため、平均使用率だけでは判断できません。必要に応じて/proc/interruptsを保存し、NICのキュー割り込みが特定のCPUに大きく偏っていないかを確認します。割り込みの分布はあくまで手掛かりであり、必ず均等でなければならないという合否基準ではありません。
4. 証拠に基づいて調整する層を選ぶ
NICのmissed系カウンターが増えている一方でsoftnetのdroppedが変わらない場合は、受信リングとドライバーのキューを優先して確認します。逆に、softnetのdroppedが増え、特定のコアに負荷が集中している場合は、ソフトウェアバックログとトラフィックの分散を確認します。両方が安定している場合は、nstatのプロトコルエラーの増分とアプリケーションログを照合し、根拠のないNIC調整を続けないようにします。
調整前に現在の設定を保存します。
ethtool -g "$IFACE" > "$D/rings" 2>&1
ethtool -l "$IFACE" > "$D/channels" 2>&1
sysctl net.core.netdev_max_backlog \
net.core.netdev_budget \
net.core.netdev_budget_usecs > "$D/budgets"
リング容量の変更は、ドライバーが対応しており、かつ変更を裏付ける証拠がある場合にのみ検討します。「最大値に設定する」を万能な対策にしてはいけません。バックログキューの拡大は、ドロップを減らす代わりにキュー待ちの遅延を増やす可能性があります。処理予算を増やすと、アプリケーションの実行時間を圧迫することもあります。マルチキューの分散調整では、IRQ、RSS、業務トラフィックのフロー数も考慮する必要があります。調整したからといって、単一のフローが自然にすべてのコアへ分散されるわけではありません。
リモート環境でチャネルの再構成、ドライバーの再読み込み、リンクのリセットをいきなり試してはいけません。これらの操作はSSH接続に影響する可能性があるため、事前に管理された作業計画、元の設定値の記録、復旧手段を用意する必要があります。1回の変更では1項目だけを変更し、異常があればまず元の値に戻します。
5. 業務負荷で再テストして効果を検証する
再テストでは、リクエストの種類、継続時間、同時実行の方法を比較可能な条件にそろえ、実際のトラフィックも記録します。2つの観測期間でドロップの絶対数だけを比べると、負荷の低下を最適化の成功と誤認するおそれがあります。スループットが同じでも、小さいパケットが増えれば受信処理の負荷は変わる可能性があります。
検証には、少なくとも次の3つの結果を含めます。
- 受信側の証拠:対象カウンターの増分が減り、新たなリンクエラーが発生していないこと。累積値が変わらないこと自体は、失敗の根拠にはなりません。
- 処理コスト:コア別のソフトウェア割り込み負荷とアプリケーションのCPU利用の間に、新たな顕著な圧迫が生じておらず、キュー待ちの遅延も悪化していないこと。
- 業務への効果:下位層のカウンターだけでなく、タイムアウト、失敗リクエスト、テールレイテンシーも併せて改善していること。
下位層のカウンターが安定しているにもかかわらず業務エラーが続く場合、結論は「今回の観測期間では、対応する受信ドロップの証拠は見つからなかった」にとどめます。プロトコルスタックとアプリケーション処理の調査を続け、ネットワークが完全に正常だとは断定しません。インターフェース、ドライバー、カーネルの情報、採取ファイル、変更前の設定値を保存しておくことで、次に同じ症状が発生したときに因果関係を再検証できます。
よくある質問
ip -s linkのdropped増加はNIC故障を示しますか?
断定できません。インターフェース統計は手掛かりです。同じ測定区間のドライバー統計、リンクエラー、業務上の症状を照合し、dropを含む項目を無条件に合算しないことが重要です。
softnetのtime_squeeze増加はパケット損失ですか?
それだけでは損失を意味しません。受信処理が予算の境界に達したことを示すため、droppedの差分、CPU別softirq負荷、業務エラーと合わせて判断します。
AMD EPYC 7543P 専用物理サーバー
月額$458.7〜