DNS サーバ用のストレスツールである dnsperf を試してみました。
※ dnsperf で DDNS(Dynamic DNS)を試してみました。手順については「dnsperf で DDNS を実施してみた」をご参照ください。
※ここでは実際に設定、動作したものを掲載していますが、内容について保証するものではありません。流用される場合は各自の責任でお願いします。
対象 OS は以下のとおりです。
# cat /etc/redhat-release
Rocky Linux release 8.10 (Green Obsidian)
参考:dnsperf のインストール
# dnf install dnsperf -y
…
Installed:
dnsperf-2.12.0-1.el8.x86_64
Complete!
参考:dnsperf のヘルプ
# dnsperf -h
DNS Performance Testing Tool
Version 2.12.0
Usage: dnsperf [-f family] [-m mode] [-s server_addr] [-p port]
[-a local_addr] [-x local_port] [-d datafile] [-c clients]
[-T threads] [-n maxruns] [-l timelimit] [-b buffer_size]
[-t timeout] [-e] [-E code:value] [-D]
[-y [alg:]name:secret] [-q num_queries] [-Q max_qps]
[-S stats_interval] [-u] [-B] [-v] [-W] [-h] [-H] [-O]
-f address family of DNS transport, inet or inet6 (default: any)
-m set transport mode: udp, tcp, dot or doh (default: udp)
-s the server to query (default: 127.0.0.1)
-p the port on which to query the server (default: udp/tcp 53, DoT 853 or DoH 443)
-a the local address from which to send queries
-x the local port from which to send queries (default: 0)
-d the input data file (default: stdin)
-c the number of clients to act as
-T the number of threads to run
-n run through input at most N times
-l run for at most this many seconds
-b socket send/receive buffer size in kilobytes
-t the timeout for query completion in seconds (default: 5)
-e enable EDNS 0
-E send EDNS option
-D set the DNSSEC OK bit (implies EDNS)
-y the TSIG algorithm, name and secret (base64)
-q the maximum number of queries outstanding (default: 100)
-Q limit the number of queries per second
-S print qps statistics every N seconds
-u send dynamic updates instead of queries
-B read input file as TCP-stream binary format
-v verbose: report each query and additional information to stdout
-W log warnings and errors to stdout instead of stderr
-h print this help
-H print long options help
-O set long options: <name>=<value>
(個人メモ)
-a : クエリ送信元を指定(アドレスもしくはホスト名)※ここで指定するアドレスはインターフェイスに設定されている必要がある。
-s : クエリ送信先を指定(アドレスもしくはホスト名)
-d : クエリ情報(ドメイン名とタイプのリスト)が登録されているファイルを指定。この内容に従いクエリを発行する
-S : 情報(time stamp と qps)を表示する間隔を指定(秒)
-c : クライアント同時接続数を指定。ここで指定した数だけ異なる送信元ポートを使用する。デフォルトは1。1クライアント当たり送・受で2スレッド使用。
-q : プールのクエリ数を指定。ここで指定した数だけクエリ処理待ちとなるようにクエリ要求をプールする。※qpsではない
-Q : 1秒あたりのクエリ発行数を指定
-m : プロトコルを指定(tcp, udp(default))
-n : -d で指定したファイルを読み込む回数
-b : UDPバッファ(デフォルトは32Kbyte)。実行中の画面に"Timeout"が出力される場合は、この値を大きくすると改善されるかも。
-l : 何秒間送信し続けるかを指定。指定時間前に、-d 指定のRRが尽きた場合、再度リストの先頭から送信を継続する。
簡単な負荷試験を行ってみました。
dnsperf に読み込ませる クエリのリストを用意します。
# head -n 5 10000.foo.com.lst
always1.foo.com A << 値は”クエリ名 クエリタイプ”です
always2.foo.com A
always3.foo.com A
always4.foo.com A
always5.foo.com A
以下の条件で負荷試験を実施します。
(-s) 試験対象の DNS サーバに cachedns(/etc/hosts 登録済み)を指定
(-d) クエリのリストファイルに 10000.foo.com.lst を指定
(-Q) 負荷は 10000 qps
(-l) 試験期間は 10 秒間
(-S) time stamp と qps を 1 秒間隔で表示
(-b) バッファサイズに 64000 byte を指定 (*1)
*1 試験開始当初、Timeout(Queries lost)が出力されたのでバッファを拡大しました。Timeout(Queries lost)の原因が dnsperf 側にある場合、バッファの拡大で問題が解消される場合があります。
# dnsperf -s cachedns -d 10000.foo.com.lst -l 10 -Q 10000 -S 1 -b 64000
DNS Performance Testing Tool
Version 2.12.0
[Status] Command line: dnsperf -s cachedns -d 10000.foo.com.lst -l 10 -Q 10000 -S 1 -b 64000
[Status] Sending queries (to 172.18.1.54:53)
[Status] Started at: Tue Jan 21 10:49:04 2025
[Status] Stopping after 10.000000 seconds
1737424145.789470: 1177.704525 << unixtime と qps を 1 秒間隔で表示
1737424146.790464: 1293.714048
1737424147.791477: 1295.687469
1737424148.792477: 1278.721279
1737424149.793763: 1169.496028
1737424150.794464: 1258.118059
1737424151.795459: 1308.697846
1737424152.796533: 4062.636728
1737424153.797548: 6121.786387
[Status] Testing complete (time limit)
Statistics:
Queries sent: 24234 << クエリ送信件数
Queries completed: 24234 (100.00%)
Queries lost: 0 (0.00%) << Timeout が発生するとここがカウントアップされる
Response codes: NOERROR 24234 (100.00%)
Average packet size: request 37, response 53
Run time (s): 10.101726 << 試験期間(10 秒)
Queries per second: 2398.995974 << qps
Average Latency (s): 0.040860 (min 0.000074, max 0.149330)
Latency StdDev (s): 0.038348
以下は dnsperf 実行中のパケットキャプチャです。(172.18.1.20 : dnsperf を実行しているホストのアドレス、172.18.1.54 : DNS サーバのアドレス)
# tshark -i 1 -f "port 53" -w /tmp/test.pcap
Running as user "root" and group "root". This could be dangerous.
Capturing on 'eth0'
48468 ^C
# tshark -t a -r /tmp/test.pcap | head
Running as user "root" and group "root". This could be dangerous.
1 10:49:04.788519512 172.18.1.20 → 172.18.1.54 DNS 75 Standard query 0x0000 A always1.foo.com
2 10:49:04.789737739 172.18.1.20 → 172.18.1.54 DNS 75 Standard query 0x0001 A always2.foo.com
3 10:49:04.789804994 172.18.1.20 → 172.18.1.54 DNS 75 Standard query 0x0002 A always3.foo.com
4 10:49:04.790909860 172.18.1.20 → 172.18.1.54 DNS 75 Standard query 0x0003 A always4.foo.com
5 10:49:04.790940332 172.18.1.20 → 172.18.1.54 DNS 75 Standard query 0x0004 A always5.foo.com
6 10:49:04.791010206 172.18.1.54 → 172.18.1.20 DNS 91 Standard query response 0x0000 A always1.foo.com A 2.3.4.5
7 10:49:04.792043804 172.18.1.20 → 172.18.1.54 DNS 75 Standard query 0x0005 A always6.foo.com
8 10:49:04.792077880 172.18.1.20 → 172.18.1.54 DNS 75 Standard query 0x0006 A always7.foo.com
9 10:49:04.792083453 172.18.1.54 → 172.18.1.20 DNS 91 Standard query response 0x0001 A always2.foo.com A 2.3.4.5
10 10:49:04.792178275 172.18.1.20 → 172.18.1.54 DNS 75 Standard query 0x0007 A always8.foo.com
tshark: An error occurred while printing packets: Broken pipe.
下記では上記パケットキャプチャ #1 のDNS クエリ(dnsperf → DNS サーバ)の Flags を表示しています。表示では RD(Recursion desired)が 1 ですが、これはクエリが再帰問い合わせ(通常はキャッシュ DNS 宛)であることを示します。RD が 0 の場合は非再帰問い合わせ(反復問い合わせ。権威サーバ宛)ですが、dnsperf のオンラインヘルプ(-h オプション)を見る限り、RD を 0 にするオプションは見当たりませんでした。ただし、RD=1 に対しても応答する権威サーバであれば、dnsperf で権威サーバに対する負荷試験も行えそうです。
# tshark -nn -r /tmp/test.pcap -Y '(frame.number==1)' -V | grep ^Domain -A10|cat -n
Running as user "root" and group "root". This could be dangerous.
1 Domain Name System (query)
2 Transaction ID: 0x0000
3 Flags: 0x0100 Standard query
4 0... .... .... .... = Response: Message is a query
5 .000 0... .... .... = Opcode: Standard query (0)
6 .... ..0. .... .... = Truncated: Message is not truncated
7 .... ...1 .... .... = Recursion desired: Do query recursively
8 .... .... .0.. .... = Z: reserved (0)
9 .... .... ...0 .... = Non-authenticated data: Unacceptable
10 Questions: 1
11 Answer RRs: 0
(補足1)
DNS レスポンス(DNS サーバからの応答)で Flags の Truncated が 1 の場合、データサイズが大きいため切り捨てが発生したことを意味しています。dig のデフォルトでは切り捨て(Truncated = 1)が発生すると、TCP で接続しなおしてクエリを再送信します(TCP フォールバック)。今回は試していませんが、dnsperf では切り捨て(Truncated = 1)が発生しても TCP フォールバックは行われません。
(補足2)
dnsperf の開発元は 2019年に Nominum 社から OARC, Inc. に移行されました。