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

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

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

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

# nginx.confの設定

```nginx
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 カーネルパラメータ

```bash
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