最適化の方法

Unbound: 最適化の方法

By W.C.A. Wijngaards, NLnet Labs, October 2008, updated July 2010.

これはunboundを最適化するためのガイドです。ほとんどのユーザはこれを行う必要はありません。しかし、大規模なリゾルバでは役に立つでしょう。下記の文書はunboundユーザからのフィードバックの結果です。異なる経験や推奨があれば、私に知らせてください。

設定

num-threadsをシステムのCPUのコア数に等しくなるように設定します。例えば、2コアのCPUが4個あれば、8を使います。

*-slabsをnum-threadsの値に近くなる2の累乗に設定します。msg-cache-slabsrrset-cache-slabsinfra-cache-slabskey-cache-slabsに対してこれを行います。これはロックの競合を減らします。

キャッシュのメモリサイズを増やします。msgキャッシュメモリの約2倍のrrsetキャッシュメモリを使ってください。例えば、rrset-cache-size: 100mmsg-cache-size: 50mです。mallocのオーバーヘッドにより、総メモリ使用量は設定ファイルに記入した総キャッシュメモリの2倍(あるいは2.5倍)まで増える可能性があります。

outgoing-rangeを可能な限り値を大きくするように設定します。全体で1024の制限を乗り越える方法については後述するセクションを見てください。これにより一度に多くのクライアントにサービスを提供します。1コアでは、950。2コアでは、450。4コアでは、200。num-queries-per-threadoutgoing-rangeの半分の数に設定するのが最もよいです。しかし、クエリーの数が突出したときにそれを吸収できるだけたくさん欲しいでしょう。outgoing-rangeの制限のためにnum-queries-per-threadも制限されます。outgoing-rangeの1024の制限をなくせるように、(下記のセクションに示す)libeventを使うようにコンパイルするのがよいでしょう。

負荷の高いサーバではso-rcvbufをより大きな値(4mか8m)に設定します。これは負荷が突出したときにメッセージが失われないようにカーネルバッファを大きく設定します。応答信頼性(reply-reliability)のパーセンテージにさらに9sを加えます。OSは最大値で上限をかけます。Linux上ではunboundはその制限を回避するためにroot権限を必要とします。あるいは管理者はsysctl net.core.rmem_maxを使うことができます。BSDでは、/etc/sysct.confkern.ipc.maxsockbufを変えます。OpenBSDではヘッダを変え、カーネルを再コンパイルします。Solarisではndd -set /dev/udp udp_max_buf 8388608を行います。

最適化した設定の短い概要をここに示します。

# some optimisation options.
server:
        # use all CPUs
        num-threads: <number of cores>  
	
        # power of 2 close to num-threads  
        msg-cache-slabs: <same>
        rrset-cache-slabs: <same>
        infra-cache-slabs: <same>
        key-cache-slabs: <same>

        # more cache memory, rrset=msg*2
        rrset-cache-size: 100m
        msg-cache-size: 50m

        # more outgoing connections
        # depends on number of cores: 1024/cores - 50 
        outgoing-range: 950

        # Larger socket buffer.  OS may need config.
        so-rcvbuf: 4m

デフォルトの設定はうまく働きます。しかし、多くのユーザにサービスを提供する必要があるときにはシステムの制限に達してしまいます。大部分はファイル記述子の数です。デフォルトで1024の制限があります。1024個より多くのファイル記述子を使うためには、libeventかフォーク運用を使います。これらについては下のセクションで記述します。

Libeventの使い方

libeventはプラットホーム特有のイベント通知システムコールのBSDライセンスのクロスプラットフォーム ラッパーです。
Unboundは1024個より多くのファイル記述子を効率よく使うためにlibeventを使うことができます。お好みのパッケージ マネージャでlibeventを(もしあればlibevent-develも)インストールします。unboundをコンパイルする前に、./configure --with-libeventを実行します。

そうすれば、outgoing-rangeにお好みのどんな数でも設定することができます。同様にnum-queries-per-threadの値も増やせます。

        # with libevent
        outgoing-range: 8192
        num-queries-per-thread: 4096 

libevent-1.4.8-stableでうまく動いているとのユーザからの報告があります。LinuxとFreeBSDで4096や8192を値として設定してうまく動いていることをユーザが確認しています。num-queries-per-threadを2倍にしてoutgoing-rangeとして使います。

安定版の(古い)ディストリビューションではlibevent-1.1のような古いバージョンのパッケージが含まれています。このようなパッケージではクラッシュの報告があります。そのため、libeventをアップグレードする必要があります。unbound 1.2.0では、libeventコールの競合条件が修正されました。

unboundはlibeventやlibevのビルド ディレクトリを指定してコンパイルできます; configure --with-libevent=/home/user/libevent-1.4.8-stableconfigure --with-libevent=/home/user/libev-3.52のように指定します。

備考 いずれせよクラッシュを経験したら、以下のことを試すことができます。libeventを更新します。問題が存続するのであれば、libeventは環境変数をセットすることにより異なるシステムコール バックエンドを使うことができあます。unboundはverbosityをレベル4にするときに使用中のバックエンドを報告します。unboundを開始する前に、EVENT_NOKQUEUEEVENT_NODEVPOLLEVENT_NOPOLLEVENT_NOSELECTEVENT_NOEPOLLEVENT_NOEVPORTをシェルでyesに設定することで、それらのバックエンドが除外できます。poll(2)バックエンドは信頼できますが、遅いです。

フォーク動作

unboundはスレッディングなしに動作する独特なモードを持っています。これは、libeventがプラットフォームで失敗するとき、更なる性能のため、毒が他に入らないようにコア間で壁を作るときなどに役に立ちます。

フォーク動作を使うようにコンパイルするためには、コンパイル前にスレッドを無効にして、フォーク動作を有効にするために./configure --without-pthreads --without-solaris-threadsを実行します。ロッキングが行われないため、そのコードは10%から20%くらい速度が向上します。

設定ファイルには、(スレッドではなくプロセスを使うとしても)num-threadsに使いたいコア数を指定します。そして、outgoing-rangeとキャッシュメモリの値はすべてスレッド毎にあります。これはコア毎にコア自身のキャッシュを使うため、もっと多くのメモリが使われることを意味します。コア毎に自身のキャッシュを持つため、キャッシュに毒入れされたときでも他のコアには影響はありません。

# with forked operation
server:
        # use all CPUs
        num-threads: <number of cores>  
	
        msg-cache-slabs: 1
        rrset-cache-slabs: 1
        infra-cache-slabs: 1
        key-cache-slabs: 1

        # more cache memory, rrset=msg*2  
        # total usage is 150m*cores 
        rrset-cache-size: 100m
        msg-cache-size: 50m

        # does not depend on number of cores 
        outgoing-range: 950
        num-queries-per-thread: 512 

        # Larger socket buffer.  OS may need config.
        so-rcvbuf: 4m

プロセス毎に多くても1024個のファイル記述子を使っているため、有効な最大値はコア数×1024です。上述した設定ではプロセス毎に950個を使います。4つのプロセッサでは3800個のソケットを与えます。クエリー毎にソケットを取得することを保証し、いくつかのソケットをqueries-for-nameserversに割かせるために、スレッド毎のクエリー数はソケットの数の半分です。

libeventといっしょにフォーク動作を使うことも可能です。スレッドの代わりに異なるプロセスにファイル記述子をOSに提供させるのに役に立ちます。基底にあるネットワーク スタックがプロセス毎の(遅い)検索構造を使っていれば、これは(急進的な)異なる性能を持つでしょう。

この文章はUnbound: Howto Optimise (www.unbound.net)の翻訳です。[翻訳: 滝澤 隆史]