読者です 読者をやめる 読者になる 読者になる

BLOG::はるかさん

はるかさん のブログです。近況情報や技術的な話題など。

nginxのtcp_nodelayディレクティブは設定しなくても良い

「nginx実践入門」お買い上げ頂きありがとうございます。レビュー等読ませて頂いていると、気になるところがあったので補足です。

nginx実践入門 (WEB+DB PRESS plus)

nginx実践入門 (WEB+DB PRESS plus)

tcp_nodelayは設定しなくても良い

tcp_nodelayディレクティブはTCP_NODELAYオプションを付与するための設定です。これはデフォルトで有効ですし、競合しそうなTCP_NOPUSHsendfileともうまいこと使えるように実装されています。そのため明示的にoffにすることは殆どないでしょう。このディレクティブがデフォルトで有効になったのはnginx 0.3.61の事なので、これより古いバージョンを使っている環境はあまり想像できません。

tcp_nodelayは何をするのか

さて本題はもう終わったのですが、tcp_nodelayディレクティブは何を設定するディレクティブなのか簡単に説明しておきます。tcp_nodelayディレクティブが有効であるとき、ソケットにTCP_NODELAYオプションが設定されます。TCP_NODELAYオプションはNagleアルゴリズムを無効にするためのオプションです。

NagleアルゴリズムはRFC896の著者であるJohn Nagle氏の名前から名付けられたアルゴリズムであり、このRFC中で説明されている"small-packet problem"を回避するためのアルゴリズムです。Nagleアルゴリズムでは、小さなパケットの送信を防ぐため、データを一旦バッファリングして大きなパケットにしてから送信しようとします。そのため、小さなパケットを送信しようとしたとき、バッファリングがタイムアウトするまで(調べてないけど200ms?)遅延が発生してしまうことになります。TCP_NODELAYを有効にすると、このバッファリングを無効にすることで、遅延を最小化することができます。

前述したように、nginxではキープアライブ接続の場合デフォルトでTCP_NODELAYを設定します。これにより、パケット到着までの遅延を短くすることを実現しています。特にTLSのハンドシェイクなどではかなり効いてくるはずです。

tcp_nopushディレクティブと組み合わせるとどうなるのか

さて、本書ではtcp_nopushディレクティブを有効にすることを推奨しています(詳しくは3.4節をごらん下さい)。このオプションはパケットをまとめることで送信するパケット数を最小化するためのオプションです。つまりTCP_NODELAYと逆の動きをするように見えます。ではtcp_nopushディレクティブとtcp_nodelayディレクティブの両方を有効にしても大丈夫なのでしょうか?

nginxではTCP_NOPUSHが有効になるのはsendfileを利用する場合のみです。ソースコードを見ると、LinuxではTCP_CORKを有効にするまえにTCP_NODELAYが有効であれば無効にするように動作します*1。そのため、両方のディレクティブが有効のままでも問題はありません。

設定しないといけないディレクティブは意外と少ない

nginxには数百ものディレクティブがあり、書籍中で取り上げたのはそのうちの一部です。静的ファイル配信に使うのであれば、設定する必要があるディレクティブはそれほど多くありません。自分の好みとしては設定する必要がないディレクティブは少ない方が嬉しいです。調べる必要もなくなるし、余計な手間を減らすことができます。ということで書籍中でもそのようなディレクティブは説明自体を省いています*2

設定しなければないディレクティブが少ないのはnginxの良いところの1つです。tcp_nodelayディレクティブはデフォルトで有効なので、明示的に記述する必要はないでしょう。sendfiletcp_nopushディレクティブは歴史的な事情と環境依存の問題によってデフォルトoffにされていることが推測できるのですが、通常の使用においては有効にして問題になることは少ないでしょう。ということで書籍で紹介しているようにsendfiletcp_nopushは明示的に有効にすることをおすすめします。

詳しくはnginx Tech Talksで

このあたりの話は2月の勉強会でやろうと思ってるので、是非参加いただければ幸いです。

eventdots.jp

*1:FreeBSDのためには別実装が存在しますが追いかけていません

*2:載せるべき、という意見はごもっともだと思いますし、tcp_nodelayディレクティブ以外に説明したほうが良かったな、と思っているディレクティブも多数あります。