Nginxのパフォーマンスを極限にするための考察

  • 344
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

ピクセルトラッキングを想定した設定で、Nginx on EC2(c3.large) という環境で、極限まで設定をして、どれぐらいさばけるのか運用中、パフォーマンステストしてる時は、別のところに問題があり、Nginx自体の性能限界までテストできなかったので、実際どこまでいけるのかは計測できてない。

秒間1万とか2万は行けてたと思う、ちなみに実際の運用では秒間9000以上とかを記録していて、サーバ自体にはかなり余裕があるので、記録はまだまだ伸びると思う。

ちなみに empty_gif は応答が短すぎて、Nginx の $request_time では記録できない... 全部 "0.000" だから、どれぐらい掛かってるのか分からん...。

nginx.confの設定

user  nginx;
worker_processes  auto;

error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;

worker_rlimit_nofile 150000;

events {
    worker_connections  65535;
    multi_accept on;
    use epoll;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for" "$request_time"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    tcp_nopush      on;

    keepalive_timeout 120;

    server_tokens   off;
    gzip  off;


    server {
        listen       80;
        server_name  example.jp;

        error_log  /var/log/nginx/example.jp.error.log;

        root /var/www/;

        location / {
            access_log  /var/log/nginx/example.jp.access.log main;
            empty_gif;
        }

    }

}

worker_connections

最大同時接続数は使用できるポート数以上設定しても意味ないので、上限の 65535 を設定

worker_rlimit_nofile

ファイルディスクリプタ上限数は、通常1つの接続につきエフェメラルポート用のソケットファイルと実際に返答するコンテンツファイルだとお思うので、worker_connections に対して2倍以上を設定しておけば良いと思うのですが、ふと HTTP Pipelining が利用された場合はこの比じゃない気がしたんだが、どうなんだろう...。

multi_accept

リクエストを同時に受け付けられるならその方が良いと思う...

use epoll

あれ、これって別に指定しなくても自動で選択されるよね??とりあえず、明示しておいた方が安心なので...

sendfile

empty_gif なので意味はない気がする...

tcp_nopush

なるべく少ないパケットで通信をした方が効率が良いように思うので...

keepalive_timeout

ELB配下のEC2環境なので、AWS推奨の120秒以上に設定

TCP カーネルパラメータ

sysctl -w net.ipv4.ip_local_port_range="18000 65535"
sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w net.ipv4.ip_dynaddr=1
sysctl -w net.ipv4.tcp_rfc1337=1
sysctl -w net.ipv4.tcp_fin_timeout=10
sysctl -w net.ipv4.tcp_keepalive_probes=5
sysctl -w net.ipv4.tcp_slow_start_after_idle=0
sysctl -w net.ipv4.tcp_max_syn_backlog=1024
sysctl -w net.core.somaxconn=65535

上記以外の設定に関しては、副作用の問題が報告されてたりして、ちょっと危険そうなのでやってないのと、そもそも、ここまでやっておけば、他のところがボトルネックになる可能性の方が高いと思うの、ひとまずここまでってのもある。

net.ipv4.ip_local_port_range

これを増やさないことには同時接続数を増やしても...。可能なら 1024-65535 とかの方が良いと思う
※iptablesやAWSだとNetworkACLとかで同様に必要に応じて開放しておかないとパケットが途中で止まってハマる

net.ipv4.tcp_tw_reuse

再利用した方が速いと思うよ...

net.ipv4.ip_dynaddr

DHCP環境なので設定しておいた方が良いかなと

net.ipv4.tcp_rfc1337

RFC1337に準拠させる。TIME_WAIT状態のときにRSTを受信した場合、TIME_WAIT期間の終了を待たずにそのソケットをクローズする

TIME_WAITは何かと問題になるし、待たなくて済むならその方が良いと思うので

net.ipv4.tcp_fin_timeout

タイムアウトはなるべく短い方がいいと思うので

net.ipv4.tcp_keepalive_probes

TCP が keepalive プローブを送る数。この数に達すると、 その接続が壊れたとみなします。デフォルトの値は 9 です。 この値に tcp_keepalive_intvl をかけると、 ある keepalive が送られた後に許される無反応時間が得られます。

あんまり待って欲しくないし、さっさと次へ行ってほしいので

net.ipv4.tcp_slow_start_after_idle

アイドルとかしなくて良いんじゃないか?

net.ipv4.tcp_max_syn_backlog

EC2だと128で少ないため増やしておく

net.core.somaxconn

上記同様EC2だと128しかないので最大値である65535まで引き上げておく

IRQ

TODO: smp_affinity
http://tsuchinoko.dmmlabs.com/?p=627
https://access.redhat.com/documentation/ja-JP/Red_Hat_Enterprise_Linux/6/html/Performance_Tuning_Guide/s-cpu-irq.html

RPS/RFS

http://yuuki.hatenablog.com/entry/linux-networkstack-tuning-rfs

Nginx参考:
http://nodejs.osser.jp/server/nginx-max-performance/
http://dak1n1.com/blog/12-nginx-performance-tuning
http://www.mk-mode.com/octopress/2014/04/13/nginx-file-discriptor-limit/
http://shinobra.com/2012/02/sawanoboly/smartos_nginx_too-many-open-files

TCP参考:
http://qiita.com/kuni-nakaji/items/c07004c7d9e5bb683bc2
http://linux.mini13i.com/?kernel%2F%A5%B7%A5%B9%A5%C6%A5%E0%A5%D1%A5%E9%A5%E1%A5%BF
http://linuxjf.sourceforge.jp/JFdocs/Adv-Routing-HOWTO/lartc.kernel.obscure.html
http://www.nateware.com/linux-network-tuning-for-2013.html