2026年6月9日

2026年6月9日

Knot DNS のパフォーマンスチューニング|計測から workers・TCP・RRL・XDP の調整まで

Knot DNS は既定値のままでも多くの権威 DNS で十分な性能が出るため、チューニングは「計測して足りない箇所を特定し、そこだけ変える」順で進めるのが近道です。この記事では、負荷の測り方、ワーカー数と TCP 関連の設定、応答サイズ、RRL(応答レート制限)、ゾーン更新が多い環境のジャーナル設定、最後の手段としての XDP モードまでを、変更の理由と確認方法とともに説明します。

設定項目名は Knot DNS 3.x 系を前提にしています。公式マニュアルの最新は 3.6 系です(2026年10月現在)。既定値や項目はバージョンで変わることがあるため、knotd --version で手元の版を確かめ、同じ版のリファレンスと照らし合わせてください。

先に知っておくこと:既定値はかなり賢い

Knot DNS の処理スレッド数は、既定で CPU 数に合わせて自動で決まります。UDP の処理スレッド(udp-workers)はオンラインの CPU 数、TCP の処理スレッド(tcp-workers)は CPU 数で最低 10、ゾーンの読み込みや転送などの裏方を担うスレッド(background-workers)は CPU 数で最大 10 です。ゾーンはメモリ上に展開されて応答されるため、ディスクの速さが応答速度に効くことはほとんどありません。

そのため、「とりあえずスレッドを増やす」ような変更は効かないか、かえって遅くなることがあります。遅いと感じたら、まず次のどれが原因かを切り分けます。

  • CPU が上限に張り付いている(スレッドや NIC の割り込みの偏りを含む)
  • パケットが OS の受信バッファであふれて捨てられている
  • TCP 接続が増えすぎて上限やタイムアウトに当たっている
  • 大きな応答が切り詰められ、TCP での再問い合わせが増えている
  • ゾーン更新や DNSSEC 署名が重く、裏方の処理が詰まっている

手順1:現状を計測する

最初に、本番に近い条件で「1秒あたりの応答数」と「応答時間」を測ります。測定は、対象サーバーとは別のマシンから行います。同じマシンで負荷をかけると、負荷ツール自身が CPU を使って結果がゆがむためです。DNS-OARC の dnsperf がよく使われます。

# queries.txt は1行に「名前 種類」。実際のログから作ると現実に近くなる
cat > queries.txt <<'EOF'
www.example.com A
example.com MX
example.com AAAA
nonexistent.example.com A
EOF

# 60秒間、20クライアントで、毎秒最大 20000 クエリを送る
dnsperf -s 192.0.2.53 -d queries.txt -l 60 -c 20 -Q 20000

結果の「Queries per second」「Average Latency」「Queries lost」を控え、-Q の値を段階的に上げて、取りこぼし(lost)が出始める地点を探します。存在しない名前(NXDOMAIN になる問い合わせ)も混ぜておくと、実際の負荷に近づきます。

測定中は、サーバー側で次の3点を見ます。

# スレッドごとの CPU 使用率(特定のスレッドだけ高くないか)
top -H -p "$(pgrep -x knotd)"

# UDP の受信バッファあふれ(数値が増え続けるなら取りこぼしている)
nstat -az | grep -i RcvbufErrors

# TCP の接続数の概況
ss -s

Knot 側の統計は、mod-stats モジュールを有効にすると knotc stats で読めます。

template:
  - id: default
    global-module: mod-stats
knotc stats mod-stats

プロトコル別(udp4・tcp4 など)の問い合わせ数や応答コード別の件数が出るので、「TCP の割合が急に増えた」「REFUSED が多い」といった偏りを確かめられます。数値は手順を変えるたびに取り直し、変更前後を比べます。

手順2:ワーカー数とソケットの設定

CPU に余力があるのに取りこぼしが出る場合や、特定のスレッドだけが忙しい場合は、ワーカー数とソケットの割り当てを見直します。

server:
    listen: [ 0.0.0.0@53, ::@53 ]
    udp-workers: 8          # 既定は CPU 数。他の常駐プロセスに CPU を残したいときは減らす
    tcp-workers: 16         # TCP の比率が高い環境で増やす
    background-workers: 4   # ゾーン数が多い・更新が多いときに見直す
    tcp-reuseport: on       # TCP ワーカーごとに SO_REUSEPORT ソケットを持たせる
    socket-affinity: on     # Linux でソケットとワーカーを結びつける

udp-workers を CPU 数より大きくしても、たいていは速くなりません。むしろ同じサーバーで監視エージェントやログ転送が動いているなら、少し減らして CPU を空けたほうが応答時間が安定することがあります。tcp-reuseport と socket-affinity は、接続の振り分けを OS に任せて偏りを減らす設定ですが、環境によって効果が変わるため、手順1の計測で差を確かめてから残すかどうかを決めます。

ここに挙げた項目は、変更後に knotd の再起動が要ります。knotc reload だけでは反映されない点でつまずきやすいので注意してください。

手順3:TCP 接続の上限とタイムアウト

DNS over TCP は、大きな応答、ゾーン転送、TC ビット付き応答後の再問い合わせなどで使われます。TCP の同時接続数の上限(tcp-max-clients)は、既定でプロセスのファイル記述子上限の半分です。つまり、systemd の LimitNOFILE が小さいと、上限も小さくなります。

server:
    tcp-max-clients: 20000
    tcp-idle-timeout: 10     # 秒。要求のない接続を閉じるまでの時間
    tcp-io-timeout: 500      # ミリ秒。1メッセージの送受信にかけてよい時間
# systemctl edit knot で作るドロップイン
[Service]
LimitNOFILE=65536

tcp-idle-timeout を長くすると、遊んでいる接続がスロットを占有し続けます。攻撃や行儀の悪いクライアントがいる環境では、短めの既定値のままのほうが安全です。上限を上げたら、ss -s で接続数が想定どおりに推移しているかを確かめます。

手順4:応答サイズと EDNS

DNSSEC を使うゾーンでは応答が大きくなり、UDP で収まらない分は TC ビット付きで返され、クライアントが TCP で問い合わせ直します。udp-max-payload の既定値は 1232 バイトで、これは途中経路での IP フラグメントを避けるための値として広く使われているものです。性能のためにこの値を大きくすると、フラグメントの欠落による取りこぼしが増えることがあるため、通常は既定値のままにします。

TCP の比率が高い場合は、値を変えるより応答を小さくする方向で考えます。たとえば、DNSSEC の署名アルゴリズムを RSA から ECDSA(アルゴリズム 13)に変えると署名が短くなり、応答サイズが下がります。ただしアルゴリズムの切り替えは鍵のロールオーバーを伴う作業なので、計画を立てて別途行います。

手順5:RRL で反射攻撃への耐性を上げる

権威 DNS は、送信元を偽った問い合わせで第三者を攻撃する「反射攻撃」の踏み台にされることがあります。mod-rrl モジュールは、同じ送信元(またはネットワーク)への応答の頻度を制限し、こうした負荷を抑えます。正規の利用者への影響を抑えるため、最初は応答を変えずに数えるだけの dry-run で様子を見ます。

mod-rrl:
  - id: default
    rate-limit: 200      # 1つの送信元あたり毎秒の上限(既定は 50)
    slip: 2              # 制限対象の応答のうち、およそ半分を TC 付きで返す
    whitelist: [ 192.0.2.0/24 ]   # 自社の監視サーバーなど
    dry-run: on          # 応答は変えず、カウンターだけを更新する

template:
  - id: default
    global-module: [ mod-rrl/default, mod-stats ]

slip は、制限した応答を捨てるか、TC 付きの短い応答で返すかの割合です。TC 付きで返すと、正規のリゾルバーは TCP で問い合わせ直せるため、巻き込まれても名前解決が止まりにくくなります。dry-run の期間に knotc stats で制限に当たった件数を確かめ、正規の大口リゾルバーまで制限していないことを見てから dry-run を外します。mod-rrl はバージョンアップの過程でオプションが追加・変更されており、古い版には dry-run が無い場合もあります。以前の設定を流用するときは、手元の版のモジュール説明で項目名と既定値を確認してください。

手順6:ゾーン更新が多い環境

動的更新や頻繁なゾーン転送、DNSSEC の自動署名があるとき、裏方の処理が詰まって反映が遅れることがあります。見直す候補は次のとおりです。

database:
    journal-db-mode: robust        # 既定。asynchronous にすると速いが障害時の耐久性が下がる
    journal-db-max-size: 20G       # 既定。上限に達すると全ゾーンで変更が拒否される

template:
  - id: default
    zonefile-sync: 60              # 秒。変更をまとめてゾーンファイルへ書き出す

zonefile-sync の既定は 0 で、変更のたびにゾーンファイルを書き出します。更新が多い大きなゾーンでは、この書き出しが重くなるため、数十秒程度にまとめると負荷が下がります。その代わり、障害時に未書き出しの変更はジャーナルから復元することになるので、ジャーナルが置かれたディスクの空きと journal-db-max-size の監視を合わせて行います。journal-db-mode を asynchronous にする変更は、クラッシュ時に直前の変更を失う可能性と引き換えです。プライマリでは慎重に判断してください。

ゾーン数が数千を超えるような環境では、起動時や一斉更新時に background-workers が足りなくなることがあります。knotc zone-status で refresh や更新の予定がたまっていないかを確かめ、必要に応じて増やします。

手順7:それでも足りないときの XDP モード

Linux では、カーネルの通常のネットワーク処理を通さずに NIC から直接パケットを受け取る XDP モードを使えます。大規模な問い合わせを捌くための機能ですが、運用上の制約が大きいので、ここまでの手順で足りない場合の選択肢と考えてください。公式マニュアルに挙げられている主な注意点は次のとおりです。

  • XDP で処理される DNS の通信は、ファイアウォールや tcpdump などの一般的なツールから見えません。iptables や nftables で 53 番を絞っているつもりでも、その制限はかかりません
  • 要求と応答が同じ物理 NIC を通る必要があり、動的更新は XDP 経由では扱えません
  • 大きな MTU に制限があり、NIC やドライバーによってはゼロコピー動作が不安定なものがあります
  • 読み込んだ BPF フィルターは自動では外れないため、やめるときは ip link set dev <インターフェース名> xdp off を実行します
xdp:
    listen: eth0
    udp: on
    tcp: off

ファイアウォールが効かないことを前提に、アクセス制御は Knot の ACL や上流のネットワーク機器で行う設計に変える必要があります。導入前にステージング環境で、監視やログ収集が今までどおり動くかを確かめてください。

変更の進め方

  • 変更は1つずつ行い、そのたびに手順1と同じ条件で計測します。複数を同時に変えると、どれが効いたのか分からなくなります
  • 設定を書き換えたら knotc conf-check で文法を確かめてから反映します
  • server セクションの多くの項目は再起動で反映されます。セカンダリが複数ある構成なら、1台ずつ再起動すれば利用者への影響を抑えられます
  • 作業前に knot.conf とゾーンファイル、DNSSEC の鍵を含むデータディレクトリをバックアップしておきます
  • 問い合わせログを mod-dnstap などで取得していると、それ自体が負荷になります。計測中は有無を揃えて比べます

まとめ

  • Knot DNS の既定値は CPU 数に合わせて自動で決まるため、まず dnsperf と knotc stats で計測し、ボトルネックを特定します。
  • ワーカー数やソケットの設定は再起動で反映され、効果は環境で変わるので前後比較で判断します。
  • TCP の上限はファイル記述子の上限に連動します。udp-max-payload は既定値のままが無難です。
  • RRL は dry-run で影響を確かめてから有効にし、監視サーバーは除外リストに入れます。
  • 更新が多い環境は zonefile-sync とジャーナルの上限を見直し、XDP はファイアウォールが効かない前提で最後に検討します。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲