と一緒に nginx sendfile そして tcp_nopush 静的ファイルをファイルシステムからソケットへゼロコピーで配信することで、CPU負荷とパケット数を目に見えて低減します。適切に設定すれば、これら2つのディレクティブは転送効率を高め、オーバーヘッドを低減し、アセットやダウンロードにおけるnginxの最適化の基盤を築きます。.
中心点
- ゼロコピー sendfile による:コピー回数の削減、スループットの向上
- tcp_nopush パケットをバッファリング:より大きなフレーム、オーバーヘッドの低減
- コンビネーション カウント対象:sendfile + tcp_nopush + tcp_nodelay
- 使用例 優先順位をつける:静的アセット、大容量のダウンロード
- テスト NFS/SMBの場合:影響を測定し、必要に応じてsendfileを無効にする
なぜsendfileがNGINXのパフォーマンスをこれほど向上させるのか
起動させる sendfile, 。これは、カーネルがユーザースペースでの追加のコピー操作を経由することなく、ネットワークスタックを介してファイルを直接送信できるためです。このゼロコピパスにより、コンテキストスイッチが削減され、特に多数のクライアントが同時に静的コンテンツを取得する場合に、CPUサイクルを節約できます。 画像、CSS、JavaScript、アーカイブなどの大容量ファイルも、データ転送がよりスムーズに行われ、オーバーヘッドが減少するため、その恩恵を受けます。また、メモリ移動が少なくなり、カーネルがデータの経路を制御するため、システムキャッシュの効率も向上します。 ローカルファイルシステムではそのメリットが最も顕著に現れるため、私はまずそこで測定を行い、その後で特殊な環境へと適用しています。.
tcp_nopush が具体的に何を行うのか、そしてどのような場面で真価を発揮するのか
と一緒に tcp_nopush システムに対し、小さなセグメントを早々に送信するのではなく、TCPパケットが適切に埋め尽くされてから送信するよう指示します。LinuxではこれはTCP_CORKに、FreeBSDではTCP_NOPUSHに相当し、いずれの場合もパケット数が目に見えて減少します。 このディレクティブはレイテンシを最小限に抑えるものではなく、有効データとオーバーヘッドの比率を改善することを目的としています。 私は静的ファイルに対して意図的に tcp_nopush を使用しています。なぜなら、連続したデータストリームでは、この設定によって最大の効率向上が得られるからです。sendfile なしでは tcp_nopush は効果を発揮しないため、私は常に両方の設定を組み合わせて適用しています。.
sendfile と tcp_nopush の組み合わせ:これが私の基本設定です
の組み合わせである。 sendfile また、tcp_nopush はコピーを削減し、パケットを束ねるため、CPU コア 1 つあたりのサーバーが処理できる並列転送量を大幅に増やすことができます。私はこれら両方を http コンテキストレベルで設定し、フローの最後の残りを待機時間なしで送信できるように、しばしば tcp_nodelay を追加しています。 パケットサイズ、MTU、クライアントは様々であり、ワークロードによって最適なバランスがわずかに異なる可能性があるため、実際のトラフィックを用いたテストは依然として重要です。静的なディレクトリの場合は、通常、グローバルに有効化すれば十分ですが、動的なレスポンスルートについては、その影響に注意を払っています。 この組み合わせは、後で追加されるさらなるnginx最適化の手順に向けた堅固な基盤となります。.
| 指令 | 目的 | 代表的な効果 | 依存 |
|---|---|---|---|
| sendfile を有効にする | ファイルからソケットへのゼロコピー | CPUへの負荷軽減、スループットの向上 | ローカルファイルシステムが最適 |
| tcp_nopush on | パッケージを充填し、間接費を削減する | 1ファイルあたりのセグメント数を減らす | sendfile でのみ有効です |
| tcp_nodelay on | 待ち時間なしで最後のバイトを送信する | 譲渡手続きの迅速な完了 | tcp_nopush を追加しました |
tcp_nodelay と tcp_nopush の連携の仕組み
起動させる tcp_nopush, 、転送の冒頭部分を大きなパケットで送信するために使用し、同時にtcp_nodelayを有効にして、転送の完了が滞らないようにします。これらの設定はフローの異なる段階に作用するため、NGINXがsendfile経由でファイルを配信する際、互いに干渉することはありません。 特に小さなファイルが多数ある場合、tcp_nodelayを設定することで、わずかな残データのためにクライアントが不必要に待機することを防ぎます。 まずステージング環境でこの組み合わせをテストし、RTTやセグメントサイズを監視して、本番環境のメトリクスと照合します。これにより、転送の開始時の効率と終了時の速度を確保しています。.
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
}
代表的な活用シナリオ:ディレクティブの効果が顕著に現れる場面
大型の場合 ダウンロード 動画、アーカイブ、ISOイメージなどの場合、カーネルのゼロコピーパスにより、転送ごとのCPU時間が大幅に削減されます。CSS、JS、フォントファイルが多数存在するCDNのような構成では、tcp_nopushがセグメント数を削減し、ソケットあたりの利用可能帯域幅を向上させます。 キャッシュが適切に機能しているWordPressサイトでは、リクエストの大部分が静的アセットに向けられるため、その効果をすぐに実感できます。また、ビルドアーティファクト、コンテナイメージ、インストーラーについても、ローカルに存在し、不安定なネットワークファイルシステムを経由しない限り、同様の恩恵を受けられます。 トラフィックのピークが予想される場合、この2つの組み合わせにより、既存のハードウェアから高い安定性を引き出すことができます。.
実践例:キャッシュとアセットを備えたWordPress向けNGINX
WordPressの設定では、私は sendfile, tcp_nopush および tcp_nodelay をグローバルに設定し、静的リソースは直接配信し、動的パスについては PHP-FPM と明確に分離しています。 また、ブラウザによるラウンドトリップを減らすため、画像、CSS、JavaScript には適切なキャッシュヘッダーを追加します。ストリーミング形式のレスポンスを返す場合は、バッファリングとの相互作用に注意を払い、チャンクサイズがレイテンシやスループットに与える影響をテストします。これに関連して、以下の概要も参考にしてください。 チャンク単位のレスポンス・ストリーミング. テキストベースのコンテンツについては、バイナリファイルを不必要に圧縮することなく、圧縮処理を適用しています。これにより、リクエストの流れが安定し、CPUへの負荷が軽減され、Time-to-First-Byteも短くなります。.
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
gzip on;
gzip_types text/css application/javascript image/svg+xml;
server {
listen 80;
server_name blog.example.com;
root /var/www/blog;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~* \.(jpg|jpeg|png|gif|css|js|ico|svg|woff2?)$ {
expires 30d;
add_header Cache-Control "public, max-age=2592000";
}
}
}
sendfile を意図的に無効にする場合
Iスイッチ sendfile NFS、SMB、または分散ファイルシステムを介してファイルが存在する場合、私のテストではスループットが低下するため、この方法は除外します。 一部のドライバやストレージパスにおけるレイテンシによって、ゼロコピーの利点が相殺されてしまうこともあるため、測定結果が判断の基準となります。ネットワークに散発的な異常が見られる場合は、sendfile自体を疑う前に、まずtcp_nopushを無効にして影響の範囲を絞り込みます。 また、予期せぬカーネルのバグや古いスタックが原因で、一時的に従来の読み書きパスに切り替える必要がある場合もあります。重要なのは、変更を段階的に導入し、メトリクスでその効果を裏付けることです。.
私が常に注意を払っているエラーの原因
私はまず、次のことを確認する。 tcp_nopush sendfileが無効なまま、誤って有効になっていると、その設定は効果を発揮しません。動的パスについては、追加のバッファリングがレイテンシを増加させないかを確認し、その利点と応答時間を天秤にかけて検討しています。 高レイテンシのネットワークでは、パケットサイズを大きくすることが本当に有効か、それともセグメントサイズやキープアライブの設定を微調整すべきかを測定します。また、MTUの設定やネットワークカードのオフロード機能も、結果に目に見える影響を与える可能性があります。 整理されたログ、pcapサンプル、および相関付けられたシステムメトリクスにより、どこを微調整すべきかがすぐにわかります。.
NGINXのパフォーマンスを包括的に考える:その他の調整ポイント
そのほか sendfile worker_processes と worker_connections の値を適切に設定することで、ソケットを人為的に制限する必要がなくなります。Linux では epoll を使用し、負荷のピーク時にボトルネックが発生しないよう、十分なファイルディスクリプタを確保しています。 テキストコンテンツについては、gzip または Brotli を有効にし、圧縮レベルが CPU に適切な負荷をかけているかどうかをテストします。トランスポート層では、接続をより長くオープンに保ち、Keep-Alive を最適化します。その方法については、ガイド キープアライブチューニング 実用的な指針を提供します。TLS、セッションの再利用、そしてHTTP/2やHTTP/3がセットアップを完成させ、適度な遅延で高い並列処理を実現します。.
制限と特例:TLS、HTTP/2/3、およびプロキシ処理
私は次のことを考慮に入れている。 sendfile 技術的には、暗号化されていないファイルパスや特定のカーネル関数にのみ適用されます。 従来のTLSでは、NGINXはユーザー空間でバイトを暗号化するため、ゼロコピーの利点は失われます。最新のカーネルでは、暗号化処理の一部をカーネル内に移行できるため、その利点が復活しますが、すべての設定で利用できるわけではありません。 HTTP/2 データがフレームに格納され、複数の応答が1つのTCP接続を共有し、NGINXがバイト単位で能動的に再パッケージ化を行う場合、sendfileはあまり重要ではありません。. HTTP/3 UDP/QUICを基盤としており、また別のルールに従っているため、効率の向上はむしろバッファ、輻輳制御、そして適切に選択されたチャンクサイズによって実現しています。例えば、 リバースプロキシ sendfile が機能するのは、実際にローカルファイルシステムからファイルを提供している場合のみです。回答は proxy_pass 或いは fastcgi_pass いずれにせよユーザースペースを経由することになります。そのため、ゼロコピー方式を最大限に活用できるよう、アセットを動的パスから厳格に分離しています。.
圧縮の適切な位置づけ:gzip/Brotli 対 gzip_static
NGINXがコンテンツをオンザフライで圧縮する際、ファイルを読み込み、処理し、その結果を書き込む必要がありますが、その過程で sendfile その利点。そのため、静的アセットについては、可能な限り、, あらかじめ圧縮された ファイル(例:.gz や .br)を直接配信します。これにより、NGINX が他のアセットと同様に事前圧縮されたファイルを転送できるため、ゼロコピーパスが維持されます。 テキスト中心で変更頻度の低いコンテンツの場合、この方法により、転送時間を犠牲にすることなく、CPU負荷の軽減と安定したスループットを実現できます。 バイナリファイルやすでに圧縮済みの形式の場合、実行時の圧縮処理を省略できます。ここでは純粋なI/Oスループットが重要であり、sendfileとtcp_nopushがその真価を発揮します。.
AIO、directio、およびページキャッシュ:小規模ファイルと大規模ファイルのパターン
コンバイン sendfile 非同期I/Oとディスクへの直接アクセスを併用し、ファイルサイズに応じて最適な処理を実現します。小~中規模のファイルはカーネルのページキャッシュの恩恵を受け、sendfileパス上に留まります。一方、非常に大きなファイルはキャッシュを追い出す可能性があるため、その場合は意図的に 直通 キャッシュの外で処理を行い、AIOスレッドを使用しています。これにより、メモリの負荷を軽減し、他のリクエストに対するレイテンシを低く抑えています。典型的なパターンは以下の通りです:
http {
# 標準パス:ページキャッシュからのゼロコピー
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# 大容量ファイル:キャッシュをバイパスして非同期で読み込み
aio threads;
directio 4m; # は 4 MiB 以上のファイルにのみ適用
output_buffers 1 512k; # の directio パス用バッファ
sendfile_max_chunk 1m; # 高負荷時の公平性確保
}
この段階的な処理により、小さなアセットは極めて効率的に処理され、一方で非常に大規模な転送でもメモリが溢れかえることはありません。重要:directioは、対象となるファイルに対してsendfileパスを無効にします。これはまさに、私が大容量ファイルのユースケースで意図している通りです。.
負荷下における公平性とフロー制御
負荷が高い時期には、1つのストリームがCPUやソケットを独占してしまうのを避けたいと考えています。そこで、 sendfile_max_chunk, 、これによりNGINXは定義されたバイト数に達すると接続を解放し、他の接続に余裕を持たせます。帯域幅制御には、 limit_rate そして limit_rate_after, 、例えば、UIアセットの読み込み速度を維持しつつ、一括ダウンロードの速度を制限する場合などです。 postpone_output NGINXが送信を開始するレスポンスサイズを制御します。tcp_nopushと組み合わせることで、パケットの切り分けを適切に行えるようにしています。さらに、以下の点にも注意を払っています。 lingering_close, 、これにより、残りのパケットが正常に送信され、ソケットが突然終了することを防ぐためです。.
ファイルシステム、リードアヘッド、およびストレージパス
なぜなら sendfile ページキャッシュを利用する際、基盤となるファイルシステムが大きな役割を果たします。私はリードアヘッドの値を検証し、大きなファイルの順次読み取りが滞ることなく、かつ小さなアセットを押し出さないように調整しています。 エクステンドフォー 或いは xfs プリフェッチングとI/Oスケジューラが、私のスループットパターンとどれほど調和しているかを観察しています。ネットワークファイルシステム(NFS/SMB)では、rsize/wsize、キャッシング、レイテンシを厳密にテストしています。わずかな偏差でも、ゼロコピーの利点が打ち消されてしまうからです。 私の原則は変わりません。まずローカルパスを最大限に活用し、次に外部スタックを慎重に調整すること――そして、直感よりも常に測定値を優先することです。.
ネットワークスタックとNICオフロードの実用的な調整
接続数が多くなる場合は、最新のスタックが備える自動バッファ調整機能に依存していますが、必要に応じて送信および受信バッファを調整しています。 TSO、GSO、GROなどのNICオフロード機能はCPU負荷を著しく軽減しますが、オフロードによってパケットキャプチャの結果が歪む可能性があるため(一見するとセグメント数が少なく、1つあたりのサイズが非常に大きいように見える)、測定時には慎重に検証を行っています。そのため、私は以下の項目を相関分析しています。 pcapNGINXとカーネルのメトリクスを用いたトレースを行い、実際のワイヤサイズとオフロードによるアーティファクトを区別します。レイテンシのピークが発生した場合は、オフロードを無効にしてテストを一時的に中断し、その差を記録した上で、継続的な運用においてどちらがより有益かを判断します。.
ロケーションごとの設定パターン:対象を絞って有効化・無効化
その選択肢は残しておきたい、, sendfile パスやファイルの種類に応じて上書きします。静的なディレクトリの場合は有効のままにしますが、ストリーミングや動的なパスについては、バッファやフィルター(圧縮など)が優先される場合に、選択的に無効にします。簡単な例を挙げると:
server {
listen 80;
server_name static.example.com;
root /var/www/static;
# 静的アセット:ゼロコピー
location /assets/ {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
expires 7d;
}
# 動的コンテンツまたはストリーミング:ゼロコピーよりも柔軟性を優先
location /api/ {
sendfile off;
proxy_pass http://app_upstream;
}
}
この区別があるおかげで、別のパスに特別な要件があるからといって、一方の利点を失うことを防ぐことができます。.
範囲、スライス、および大規模なカタログ
大規模な物件の場合、 レンジ-リクエストの強みを生かしています。クライアントは必要な部分のみを読み込み、接続は安定した状態を維持します。非常に大きなファイルを含むコンテンツカタログでは、転送を論理的に分割するようにしています。これにより、サーバーへの負荷がより均等に分散され、中断などのエラーが発生した場合でも、その影響による時間の損失を最小限に抑えることができます。 キャッシュシナリオでは、レスポンスを適切にバッファリングしつつ、小さなチャンクや残りのデータを人為的に保持しないことで、「サンダーリング・ハード」を未然に防いでいます。この際、tcp_nopushとの連携が極めて重要です。初期セグメントは大きく保ちつつ、終了セグメントの送信を遅らせないようにしています。.
測定・試験戦略:効果を信頼性高く実証する
最適化については、再現可能なテストで実証しています。サーバー側ではCPUプロファイルを監視し、, 1TP4リクエスト時間, $バイト_送信, 、アクティブな接続、およびコンテキスト切り替え。ネットワーク側では、セグメントサイズ、再送信回数、RTTの分布を測定し、オフロード効果を考慮するためにパケットキャプチャをソケット統計と照合しています。 クライアント側では、現実的なRTTおよび帯域幅の下で、TTFB、First Contentful Paint、およびダウンロード時間を比較します。ベストケースの曲線だけが見えないように、MTU、キープアライブ設定、およびファイルサイズを変化させています。 最終的に、具体的な数値に基づいて、各ワークロードにおいてsendfile/tcp_nopushが望ましい安定性と効率性を提供しているかどうかを判断し、それが実現されるまで微調整を行います。.
違いを生むHTTPの詳細:Rangeとストリーミング
私はこうしている。 レンジ-大きなファイルでのリクエストにおいて、クライアントが必要な部分のみを再読み込みし、接続が安定した状態を保てるようにします。特に動画の早送りや更新の再開時には、バイト範囲を適切にサポートすることで、スループットを効率的に分散させることができます。詳細については、以下のページをご覧ください。 HTTP Rangeリクエスト. 本文が徐々に長くなる連続したレスポンスに対しては、ストリーミング戦略を検証し、バッファが意図せず長期間保持されないようにしています。その際、キャッシュを適切に扱い、プロキシやブラウザが正しく動作するよう適切なヘッダーを設定しています。 パケットサイズやフラッシュのタイミングが、体感速度に直接影響を与えるため、tcp_nopushとの相互作用にも注意を払っています。.
簡単にまとめると
と一緒に sendfile ファイルをカーネルに直接効率的に転送し、tcp_nopush を使用することで、パケットが回線を圧迫する前に適切に埋められるようにしています。これら2つのディレクティブは互いに補完し合う一方で、tcp_nodelay は最後の余剰バイトを遅延なく送信します。 実際のトラフィック下でその効果を検証し、ストレージパス、MTU、キープアライブ、圧縮に注意を払い、一貫して測定を行います。 WordPressやCDNのようなワークロードでは、リクエストの多くが静的アセットを対象としているため、そのメリットが特に早く現れます。これらの設定を的確に活用すれば、コアあたりのスループットを向上させ、オーバーヘッドを低減し、実際のトラフィック急増に備えた余裕を確保できます。.


