NginxでリバースプロキシをKeepAliveしたときの性能検証

Nginx + Luaを用いた、ハイパフォーマンスで動的なプロキシサーバを考察中です。
そのための施策の一つとして
**上流サーバへのアクセスをKeepAliveする** という方法がありますが
その際、プロキシサーバにどの程度性能に変化があるのかを調査してみました。


# リバースプロキシのkeepalive設定

前提条件として Nginx > 1.1.4 が必要。  
upstreamに keepalive というattributeがあるのでそれを設定します。
それと同時に、プロキシヘッダーにHTTP/1.1設定などを行いましょう。

ちなみにproxy_passだけだとkeepaliveできないようです。upstream必須。

あと、もちろんバックエンドサーバ側もkeepalive設定しておきます。

```
upstream http_backend {
    server oreore.micro.service;

    # keepalive <connection> [single]
    #  connection: 持続する最大コネクション数
    #  single: 指定すると、複数ホスト時でも単一ホストとして扱う？
    keepalive 128;
}

server {
    ...

    location /http/ {
        proxy_pass http://http_backend;

        # HTTP 1.1を指定
        proxy_http_version 1.1;
        # Connectionヘッダーを指定
        proxy_set_header Connection "";
        ...
    }
}

```

# 性能検証

## サーバ構成(EC2)

| ロール   | インスタンスタイプ |
|----------|------------------|
| ベンチマークサーバ | t2.micro    |
| プロキシサーバ     | t2.micro     |
| バックエンドサーバ(ダミーレスポンスを返すだけ) | t2.micro    |

## OS/ミドルウェアなど

| - | - |
|---|---|
|OS|AmazonLinux 2014.09|
|プロキシサーバ|OpenResty 1.7.4.1|

## ざっくり構成

バックエンドサーバは外部ELB経由で、Webサーバへアクセスしています。

![スクリーンショット 2014-10-16 23.58.09.png](https://qiita-image-store.s3.amazonaws.com/0/9099/05ceb701-a884-d833-b85f-75dc3f30f898.png)


## ベンチマークコマンド

```
# clients:100 requests:50000 keepalive
# クライアントは常にhttp
weighttp -c 100 -n 50000 -k http://xx.xx.xx.xx/
```

## プロキシサーバのNginxコンフィグ

こんな感じ（イメージです）。

```
    #user  nobody;
    worker_processes  1;
    worker_rlimit_nofile 10000;

    #error_log  logs/error.log;
    #error_log  logs/error.log  notice;
    #error_log  logs/error.log  info;

    #pid        logs/nginx.pid;

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

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

        server_tokens off;

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

        #access_log  logs/access.log  main;

        keepalive_timeout      60;

        # upstream
        upstream http_backend {
            server oreore.micro.service;
        }
        upstream http_keepalive_backend {
            server oreore.micro.service;
            keepalive 128;
        }
        upstream https_backend {
            server oreore.micro.service:443;
        }
        upstream https_keepalive_backend {
            server oreore.micro.service:443;
            keepalive 128;
        }

        server {
            listen 80;
            server_name 0.0.0.0;

            #  match test(external http elb)
            location ~ /ex-elb-http/(\w+)/ {
              proxy_pass http://http_backend/?$args;
            }

            #  match test(external elb https)
            location ~ /ex-elb-https/(\w+)/ {
              proxy_pass https://https_backend/?$args;
            }

            #  match test(external http elb keepalive on)
            location ~ /ex-elb-http-keepalive/(\w+)/ {
              proxy_pass http://http_keepalive_backend/?$args;
              proxy_http_version 1.1;
              proxy_set_header Connection "";
            }

            #  match test(external https elb keepalive on)
            location ~ /ex-elb-https-keepalive/(\w+)/ {
              proxy_pass https://https_keepalive_backend/?$args;
              proxy_http_version 1.1;
              proxy_set_header Connection "";
            }

            # ...
        }

    }
```

## 評価軸

- a) リバースプロキシ配下のバックエンドサーバがhttpでkeepaliveなし
- b) リバースプロキシ配下のバックエンドサーバがhttpでkeepaliveあり
- c) リバースプロキシ配下のバックエンドサーバがhttpsでkeepaliveなし
- d) リバースプロキシ配下のバックエンドサーバがhttpsでkeepaliveあり

## 結果

| 評価軸 | プロキシサーバ:CPU利用率 | ベンチマーク結果：req/s |CPU1%辺りで捌けるreq/s|
|------|------------------|--------------|--------------|
| a) http + off|        22%       |     3400     |154.54|
| b) http + on|        38%       |     8060     |212.11|
| c) https + off|        41%       |     1746     |42|
| d) https + on|        45%       |     6375     |141.67|

※プロキシサーバのCPUを使い切れていないのはベンチマーククライアント限界です。
 そのため、CPU1%辺りに捌いた数も表に入れています（ざっくり数値になってしまいますが）

## まとめ

予想通り、keepalive時、特にhttps時のプロキシ負荷効率がだいぶ良くなりました。
プロキシサーバとバックエンドサーバ、双方の負荷軽減に
効果がありそうですね。

<br>

# おまけ

upstreamでhttpsをバックエンドに置く場合、ポート指定を忘れずに！！！
[Nginxでupstreamにhttpsなホストを設定する時の注意点](http://qiita.com/toritori0318/items/f15b4e165e7170c5055b)

# 参考

- [HttpUpstreamKeepaliveModule](http://wiki.nginx.org/HttpUpstreamKeepaliveModule)
- [ngx_http_upstream_module](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive)
- [Load Balancing with NGINX and NGINX Plus part 2](http://nginx.com/blog/load-balancing-with-nginx-plus-part2/)
- [nginx-1.1.x で httpなupstreamにもkeepaliveができるようになったので検証してみたAdd Star](http://blog.nomadscafe.jp/2012/02/nginx-11x-httpupstreamkeepalive.html)