【実務・中級編】 ルーターのCPU負荷とメモリ消費のボトルネック – 家庭用ネットワーク・IoT・モバイル通信実践ガイド

はじめに:なぜ、私たちの家庭用ルーターは「突然の沈黙」を選ぶのか

「夜になると、なぜかAPIのレスポンスタイムが跳ね上がる」
「自宅サーバーでのビルド中に、スマートホームのデバイスが一斉にオフラインになる」

Webエンジニアやインフラエンジニアであるあなたなら、こうした不可解なネットワークの挙動に直面したとき、真っ先にISPの回線速度や、クラウド側のオートスケーリング設定を疑うはずです。しかし、packet capture(パケットキャプチャ)を仕掛け、tracerouteを叩いてみて、最終的にたどり着く犯人は、リビングの片隅で静かに青いランプを点滅させている「家庭用無線LANルーター」のハードウェアリソース枯渇であることが少なくありません。

近年の家庭環境は、もはや小規模オフィスのインフラと同等か、それ以上の負荷をルーターに強います。数十台に及ぶIoTデバイスの常時接続、スマートスピーカーからの絶え間ないmDNSマルチキャスト、バックグラウンドでの重厚な暗号化通信(VPN)、そしてギガビット級のWAN/LAN間ルーティングにおけるパケットフィルタリング。

「IEEE 802.11ax(Wi-Fi 6)」や「BE(Wi-Fi 7)」という華やかな無線規格の裏側で、ルーターのCPUコアは悲鳴を上げ、限られたRAMはスワップ(あるいはOOM Killerによるプロセス強制終了)の瀬戸際に立されています。

今回は、シニアネットワークエンジニアの視点から、家庭用ルーターの心臓部である「CPU負荷」と「メモリ消費」のボトルネックを深掘りし、実務的なインフラ選定・デバッグ手法をコードや通信フローと共に紐解いていきましょう。

—

1. ルーターのハードウェアリソースを圧迫する3大要因

スペック表の「最大通信速度◯Gbps」という謳い文句に惑わされてはいけません。ルーターの本質は、専用のASICやネットワークプロセッサ(NPU)、あるいは汎用CPU上で動作するLinuxカーネルによる「パケット転送と制御装置」です。

[クライアント] ---> (無線/有線) ---> [ルーター (Linux Kernel / netfilter)] ---> [WAN (ISP)]
                                       ├── CPU: NAT/SPI, 暗号化(VPN), パケットフィルタ
                                       └── RAM: コネクションテーブル (conntrack), パケットバッファ

特に以下の3つの処理は、CPUとメモリに対して強烈な負荷をかけます。

① 膨大な「コネクション数」と conntrack のメモリ枯渇

家庭内であっても、PC、スマートフォン、テレビ、スマート家電、そして開発用のDockerコンテナ群が動いていれば、アクティブなTCP/UDPセッションは数千件に達します。
Linuxベースのルーター(OpenWrtや各社独自ファームウェア)では、Netfilterの nf_conntrack モジュールがすべての通信状態をメモリ上に保持します。1つのコネクションエントリが消費するメモリはわずか数十〜数百バイトですが、数千〜数万件を超えると、数MBから数十MBのRAMが固定消費され、ルーター全体のメモリを圧迫します。

② ステートフル・パケット・インスペクション(SPI)とCPU負荷

パケットが通過するたびに、ルーターはL3/L4ヘッダーを検査し、セッション状態を更新します。さらに、セキュリティ機能としてIDS/IPSやWebフィルタリングを有効にしている場合、CPUは各パケットのペイロードまで深層パケットインスペクション(DPI)を行うため、CPU使用率が跳ね上がります。

③ 常時接続VPN(WireGuard / OpenVPN)の暗号化処理

自宅のインフラや開発環境へリモートアクセスするために、ルーター側でVPNサーバー(あるいはクライアント)を稼働させているエンジニアも多いでしょう。
OpenVPNはユーザースペースでの処理やコンテキストスイッチが多く、CPUのシングルコア性能を激しく消耗します。現代の主流であるWireGuardはカーネルスペースで動作するため非常に軽量ですが、それでも暗号化・復号化の処理はCPUのバウンドワークであり、特に安価なARM Cortex-A7コアなどを搭載したルーターでは、スループットのボトルネックになります。

—

2. 通信フローとプロトコルの裏側:パケットがCPUを直撃する瞬間

ここで、ローカルネットワーク内のクライアントが外部のWeb API(例: api.example.com)へHTTPSリクエストを送信し、ルーターを経由してレスポンスを受け取るまでのシーケンスを追ってみましょう。

Client                Router (Netfilter / conntrack)        WAN / Server
  |                                 |                             |
  |--- 1. SYN (TCP Handshake) ----->|                             |
  |                                 |-- 2. Allocate conntrack entry
  |                                 |-- 3. NAT (SNAT/DNAT) lookup-|
  |                                 |--- 4. SYN ----------------->|
  |                                 |<-- 5. SYN-ACK --------------|
  |<-- 6. SYN-ACK ------------------|                             |
  |--- 7. ACK --------------------->|                             |
  |                                 |--- 8. ACK ----------------->|
  |                                 |                             |
  |--- 9. TLS Client Hello -------->|                             |
  |    (暗号化パケットの爆撃)       |-- 10. CPU context switch /  |
  |                                 |       Packet Processing     |
  |                                 |--- 11. TLS Client Hello --->|

このフローの中で、特にルーターのCPUとメモリを最も激しく消費するのは、ステップ9以降の「大量のパケット処理とNAT変換、そして必要に応じたパケットキューイング」です。
もし、クライアント側から大量の非同期リクエスト(例えば、Webフロントエンドからの並行Fetch APIコールや、負荷テストツールによるリクエスト)が飛ぶと、ルーターのRAM上にある nf_conntrack_max の上限に達し、新しいコネクションが張れなくなる(Connection refused やタイムアウトが頻発する)現象が発生します。

—

3. 実践:ルーターの負荷状態を監視・診断するスクリプト

「ルーターが重い」と感じたとき、感覚で判断するのではなく、エンジニアらしくメトリクスを収集しましょう。SSHアクセスが可能なルーター(OpenWrtや一部のカスタムファームウェア)や、ネットワーク上のLinuxゲートウェイに対して実行できる、Pythonを用いた簡易ヘルスチェック・負荷監視スクリプトの例を紹介します。

このスクリプトは、SSH経由でルーターにログインし、CPU使用率、メモリ空き容量、および現在のネットワークコネクション数(conntrack の利用状況)を定期的に取得してログ出力します。

import time
import paramiko

# ルーターへの接続設定(OpenWrt等のSSHアクセスを想定)
ROUTER_IP = "192.168.1.1"
ROUTER_PORT = 22
USERNAME = "root"
PASSWORD = "your_secure_password"  # 実際の運用ではSSH鍵認証を推奨

def check_router_health():
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    
    try:
        ssh.connect(ROUTER_IP, port=ROUTER_PORT, username=USERNAME, password=PASSWORD, timeout=5)
        
        # 1. CPU使用率の取得 (topコマンドの出力を1回分パース)
        stdin, stdout, stderr = ssh.exec_command("top -n 1 | grep 'CPU:'")
        cpu_info = stdout.read().decode('utf-8').strip()
        
        # 2. メモリ空き容量の取得 (freeコマンド)
        stdin, stdout, stderr = ssh.exec_command("free | grep 'Mem:'")
        mem_info = stdout.read().decode('utf-8').strip()
        
        # 3. 現在のコネクション数(conntrack)の取得
        stdin, stdout, stderr = ssh.exec_command("cat /proc/sys/net/netfilter/nf_conntrack_count")
        conntrack_count = stdout.read().decode('utf-8').strip()
        
        stdin, stdout, stderr = ssh.exec_command("cat /proc/sys/net/netfilter/nf_conntrack_max")
        conntrack_max = stdout.read().decode('utf-8').strip()
        
        print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] --- Router Health Status ---")
        print(f"  CPU Status: {cpu_info}")
        print(f"  Memory Status: {mem_info}")
        print(f"  Conntrack Usage: {conntrack_count} / {conntrack_max} ({(int(conntrack_count)/int(conntrack_max))*100:.2f}%)")
        print("-" * 50)
        
    except Exception as e:
        print(f"[Error] Failed to connect or fetch metrics from router: {e}")
    finally:
        ssh.close()

if __name__ == "__main__":
    # 30秒ごとにルーターのハードウェアリソースをポーリング
    while True:
        check_router_health()
        time.sleep(30)

パラメーターチューニングの実務的アプローチ

もし上記スクリプトの監視で conntrack の使用率が常に80%を超えている場合、以下のカーネルパラメータ(Linuxベースルーターの場合、/etc/sysctl.conf やルーターのカスタム設定画面)をチューニングする必要があります。

# コネクション追跡テーブルの最大数を引き上げる(メモリに余裕がある場合)
net.netfilter.nf_conntrack_max = 131072

# TCPタイムアウト時間を短縮し、ゾンビ状態のコネクションを早期解放する
net.netfilter.nf_conntrack_tcp_timeout_established = 43200
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30

*※注意:メモリ容量が少ない低スペック機で nf_conntrack_max をやみくもに増やすと、OOM Killerが働きルーターのプロセスがクラッシュするため、ハードウェアスペックとのトレードオフを必ず考慮してください。*

—

4. エンジニアが選ぶべき「ボトルネック知らず」なルーターの選定基準

では、こうしたハードウェア負荷のボトルネックを回避し、安定した開発・生活インフラを構築するためには、どのようなスペックのルーターを選定すべきでしょうか。マーケティング上の「最大通信速度」という数字を忘れ、以下の3つのハードウェア要件に注目してください。

① マルチコアCPU(最低でもクアッドコア以上、できれば1.5GHz以上)

単一の高速なコアよりも、複数のコアを搭載したSoC(Qualcomm製IPQシリーズやMediaTek製Filogicシリーズなど)を搭載したモデルを選びましょう。パケット処理、無線制御、VPN、そしてルーター上で動作する追加サービス(DockerやAdGuard Homeなど)のプロセスを綺麗にコア分散できます。

② 潤沢なRAM(最低 512MB以上、できれば 1GB)

「たかが家庭用」と侮ってはいけません。128MBや256MBのRAMを搭載したルーターは、前述の conntrack やIPv6ルーティング、各種デーモンの稼働ですぐにスワップやメモリ不足に陥ります。RAM 1GB以上を搭載したモデルであれば、高負荷時でもLinuxカーネルのバッファキャッシュが十分に機能し、安定したスループットを維持できます。

③ ハードウェアアクセラレーション(NAT/Routing Offload)のサポート

CPUにすべてのパケット処理をさせず、専用のハードウェア(NPUやスイッチングASIC)にパケットフォワーディングをオフロードする機能(例: QualcommのPPE: Packet Processor Engine)が有効に機能するファームウェア・ハードウェアを選定します。これにより、ルーティング処理におけるCPU使用率を劇的に下げることができます。

—

おわりに:安定したネットワークは、堅牢なハードウェア設計から

今回は、家庭用ルーターのCPU負荷とメモリ消費という、一見すると地味ながらインフラエンジニアにとっては致命傷になり得るボトルネックについて解説しました。

私たちが日々の開発で美しいコードを書き、高速なAPI設計を行っても、そのパケットを中継するゲートウェイのCPUが100%に張り付き、RAMが枯渇していては、真のパフォーマンスを発揮することはできません。

もし自宅のネットワーク環境に不可解な遅延や切断を感じたら、回線業者やWi-Fiの電波強度だけでなく、ぜひルーターのハードウェアリソース(CPU・メモリ・コネクション数)に目を向けてみてください。適切なハードウェア選定とパラメーターチューニングこそが、ストレスフリーな開発ライフラインを支える最大の武器となります。

コメント

タイトルとURLをコピーしました