負荷テスト

ネットワーク経由とループバックという 2 つの環境でブローカーに負荷をかけ、ブローカー自身のふるまいと環境の影響を切り分けました。以下に手法、完全な表、短い考察を示します。

報告書をダウンロード(PDF)

試験環境

実施日:2026 年 7 月 24 日 · プロトコル:MQTT 3.1.1 · 道具:自作の負荷クライアント cmd/loadtest。本プロジェクトのコーデックを使い、サードパーティ製 MQTT ライブラリは用いていません。

ブローカー自身のふるまいと環境の影響を切り分けるため、2 つの環境で試験しました。ネットワーク経由とループバック、控えめな機材と強力な機材です。

環境 A — ネットワーク経由環境 B — ループバック
ブローカーの CPU12 コア2× Xeon E5-2690 v4 @ 2.6 GHz(28 コア / 56 スレッド)
ブローカーのメモリー16 GB128 GB
アドレス192.168.1.84:1883(LAN)127.0.0.1:1883(ループバック)
負荷生成側LAN 上の別のマシンブローカーと同じマシン
クライアントの一時ポート16,384(既定)55,000(拡張)
比較の読み方。2 つの環境は同等ではなく、答える問いが違います。環境 A は専用の生成機を使ったネットワーク越しの動作を示します。環境 B はネットワークを取り除き(遅延はほぼ 0)、ブローカーに強力な機材を与えますが、生成機とブローカーが同じコアを分け合います。したがって遅延とファンアウトは正面から比べられますが、受信量は比べられません。環境 B では、クライアントがブローカーからコアを奪っているからです。

結果の要約

  • 遅延。通常の負荷における「発行者 → ブローカー → 購読者」の端から端までの遅延は、ネットワーク経由でおよそ 1 ms、ループバックでは 73 µs(ネットワークを除いた分、約 16 分の 1)。
  • 接続数。ネットワーク経由では 10,000 セッションを失敗なく維持しました(それ以上はクライアント側のポート上限に当たりました)。強力な機材でのループバックでは 30,000 を失敗なく、50,000 を狙った試行では 約 41,000(ブローカーではなく 1 台のマシンの限界)。
  • 受信量。ネットワーク経由の最大は 毎秒約 277,000 メッセージ。ループバックではこれが下がります(毎秒約 185,000)。生成機がブローカーとコアを取り合うためです。
  • ファンアウト(配送)。強力な機材では、購読者へ 毎秒約 1,350,000 メッセージ(ファンアウト ×100)を配りました。ネットワーク経由の毎秒約 22,000 と比べての値です。
  • 安定性。どちらの環境でもブローカーは落ちも固まりもしませんでした。過負荷時には、遅れている購読者向けの QoS 0 のメッセージが行儀よく捨てられます。全試行を通じて、ブローカーのログにエラーは 1 件もありません。

同時接続の収容力

各接続は認証を伴う CONNECT → CONNACK の完全な流れで、その後セッションを開いたまま保ちます(PINGREQ で確認)。

環境 A — ネットワーク経由

目標確立失敗確立 p50p99
10100146 ms162 ms
1001000702 ms1.12 s
1,0001,00004.21 s9.78 s
5,0005,00004.64 s8.59 s
10,00010,00004.92 s10.52 s
15,00014,8791217.43 s14.09 s

環境 B — ループバック(段階的に増やす)

目標確立失敗確立 p50p99
1,0001,0000886 ms1.06 s
10,00010,0000903 ms1.55 s
30,00030,0000923 ms1.90 s
50,00041,2190984 ms1.90 s

考察

  • ネットワーク経由では 10,000 まで失敗ゼロ。15,000 での 121 件の失敗はクライアント側の一時ポート(16,384)の枯渇です。ブローカーではなく生成機の限界です。
  • ループバックでは、ポートの範囲を広げたあと 30,000 セッションを問題なく維持しました。50,000 では保持期間の終わりに約 41,000 が生きていました。両側が 1 台のマシンを分け合っているためです。ブローカーのログは終始きれいで、エラーはありません。
  • 副次的な発見。ループバックでは接続の立ち上がりが急すぎると(同時に 1,000 の dialconnection refused が起きます。受け入れ待ち行列があふれるためで、ネットワークの遅延がないと SYN が一斉に届くからです。段階的に増やせば(1 回に 200)この現象は完全に消えます。ネットワーク越しなら遅延が自然に山をならします。

受信スループット

発行者の集団ができるだけ速く発行し、ブローカーの受信速度を測ります。

QoS 0 · 64 バイトのペイロード

発行者環境 A(ネットワーク)環境 B(ループバック)
10271,006/s185,012/s
100236,422/s101,457/s
500103,546/s125,324/s

受信量はネットワーク経由のほうが多いのですが、環境 A のブローカーが速いからではなく、そこでは生成機が別のマシンで動いているからです。ループバックではクライアントとブローカーが同じコアを分け合うので、合計の速度に上限がかかります。

QoS 1(PUBACK による確認あり)· 64 B

発行者環境 A(ネットワーク)環境 B(ループバック)
1010,292/s63,606/s
10022,085/s48,983/s

QoS 1 の試験クライアントは同期式で(1 通ごとに PUBACK を待つ)、往復時間に縛られます。ループバックでは往復がほぼ 0 なので、約 6 倍になりました。QoS 1 の数値がブローカーではなくネットワークの遅延で決まることが、はっきり分かります。

メッセージ長を変えた試験 · QoS 0 · 発行者 50

長さ環境 A(ネットワーク)環境 B(ループバック)
64 B277,198/s · 17.7 MB/s101,961/s · 6.5 MB/s
256 B124,997/s · 32.0 MB/s102,029/s · 26.1 MB/s
1,024 B38,458/s · 39.4 MB/s102,151/s · 104.6 MB/s

2 つの異なる天井が見えます:

  • ネットワーク経由では毎秒約 40 MB で回線に当たります。メッセージが大きくなるほど毎秒の件数は落ち、MB/s は上限の近くに留まります。
  • ループバックでは回線が桁違いに太いので件数は保たれ(接続 50 で毎秒約 102,000)、量は毎秒 104.6 MB まで伸びます。ここでの制約はバイト数ではなく、1 通あたりの処理(CPU)です。

端から端までの配信

メッセージ本体に時刻を埋め込み、実際の配信量と端から端までの遅延を測ります。ファンアウトとは、フィルターが一致する購読者すべてへの配信のことです。

環境 A — ネットワーク経由

条件発行配信平均 / p50 / p99
購読 10 / 発行 10 / 毎秒 100 — 通常986/s9,863/s1.17 / 1.0 / 3.6 ms
購読 100 / 発行 10 / 制限なし261,551/s22,351/s780 / 453 / 678 ms
購読 100 / 発行 10 / 毎秒 5004,934/s12,150/s1.87 / 1.77 / 2.83 s
購読 1,000 / 発行 5 / 毎秒 100494/s178,961/s2.29 s / 480 / 952 ms

環境 B — ループバック

条件発行配信平均 / p50 / p99
購読 10 / 発行 10 / 毎秒 100 — 通常987/s9,867/s73 / ~0 / 555 µs
購読 100 / 発行 10 / 制限なし47,557/s1,353,431/s514 / 135 / 251 ms
購読 100 / 発行 10 / 毎秒 5003,608/s360,834/s17.1 / 10.5 / 71.6 ms
購読 1,000 / 発行 5 / 毎秒 100494/s183,746/s4.73 / 4.54 / 15.1 ms

考察

  • 通常の負荷での遅延は、ネットワーク経由で 1.17 ms、ループバックで 73 µs。差はネットワークの経路そのものです。
  • 負荷時の配送:強力なマシンは購読者へ毎秒約 135 万メッセージ(ファンアウト ×100)を届けました。ブローカーも回線も小さいネットワーク環境(毎秒 2.2 万)に比べ、2 桁上です。
  • ファンアウトが大きい条件では生成機も制約になります(すべての購読者が 1 台のマシンの 1 プロセスにいるため)。したがって配信量の最大値は、ブローカーの実力の下限とみるべきです。

両環境の比較

指標環境 A — ネットワーク(12 コア)環境 B — ループバック(28 コア)
失敗なしの接続数10,00030,000
接続数の最大14,879(クライアントの限界)約 41,000(1 台のマシンの限界)
受信 QoS 0(64 B)最大271,006/s185,012/s
受信 QoS 1(64 B)最大22,085/s63,606/s
量の上限毎秒約 40 MB(回線)毎秒約 105 MB(CPU)
遅延(通常)中央値1.0 msほぼ 0(平均 73 µs)
ファンアウト時の配信、最大22,351/s1,353,431/s
ブローカーのログのエラーなしなし

手法上の注意

  • 受信速度は 2 つの環境で直接は比べられません。環境 B では生成機とブローカーがコアを分け合い、環境 A では生成機が別のマシンです。
  • どちらの環境でも負荷は 1 台のクライアントマシンから与えています。条件によっては(大きなファンアウト、数万の接続)、制約になるのはブローカーではなくそのマシンです。
  • QoS 1 の試験クライアントは同期式のため、QoS 1 の数値はブローカーの実力を控えめに示しています。
  • 試験中のブローカー側のシステム指標(CPU・メモリー)は採取していません。サーバーの状態は、そのログ(エラーなし)とクライアント側のふるまいから推し量っています。

再現するには

どの試行も loadtest という 1 つのバイナリから起動します。以下は 3 つのモードのコマンドです。

go build -o loadtest ./cmd/loadtest

# 接続の収容力(段階的な立ち上げと受け入れ待ち行列)
./loadtest -addr HOST:1883 -user myelx -pass *** \
    -mode conn -levels 1000,10000,30000,50000 -hold 3s -dial-concurrency 200

# 受信スループット
./loadtest -addr HOST:1883 -user myelx -pass *** \
    -mode pub -pubs 10 -qos 0 -payload 64 -duration 10s

# 端から端までの配信と遅延
./loadtest -addr HOST:1883 -user myelx -pass *** \
    -mode pubsub -subs 10 -pubs 10 -qos 0 -rate 100 -payload 64 -duration 10s