4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

nginx〜go〜mongoDBを使ったREST-WebAPIサーバのパフォーマンスチューニング 第3回 バックエンドはコネクションプーリングで

Last updated at Posted at 2017-01-17

この記事ではAWS ec2上のCentOS7にインストールしたnginx 1.10.2を使っています。go1.7を追加しました。

連載一覧
[第1回 REST-WebAPIの特徴に合わせてチューニングしよう] (http://qiita.com/toast-uz/items/828bbb48d58eb65f1f9f)
[第2回 nginx基本チューニング(有効なのはtcp_nopushだけ)] (http://qiita.com/toast-uz/items/48754a95aa0c60db67f5)
[第3回 バックエンドはコネクションプーリングで] (http://qiita.com/toast-uz/items/b459100189efb995b9c5)
[第4回 DB接続もコネクションプーリングで] (http://qiita.com/toast-uz/items/9c1b97bee8f4a7c13bfc)

今回からは、testサーバ〜webサーバ〜apサーバの構成にして、apサーバにgo1.7をインストールしました。全てt2.microを利用しています。

goのインストールについては、How To Install Go 1.7 on CentOS 7を参考にしました。

1. 準備

nginxのバックエンド接続は、FastCGI方式、http_proxy方式があり、さらにhttp_proxy方式はkeepaliveありなしの区別があります。この3方式のapサーバを準備します。また、比較のためにwebサーバのデフォルトindex.htmlも参照できるようにするとともに、3方式のapサーバは、いずれも、index.htmlと同じコンテンツを返すようにします。

これらの3方式+1(index.html参照)が、任意に試せるような環境構築をします。

1.1 testサーバ

忘れずに遅延印加しておきます。

testサーバ
$ sudo tc qdisc add dev eth0 root netem delay 100ms

1.2 webサーバ(nginx.conf)

3方式+1を一度に表現します。

アクセス先 動作
/ index.html参照
/api1 FastCGI接続
/api2 http_proxy接続
/api2k http_proxy接続(KeepAliveあり)

nginx.confは第2回までの内容として、nginx.confにincludeされているdefault.confを修正することで、上記を実現します。

default.conf
upstream api1 {
     server 172.31.24.119:9000;
}
upstream api2 {
     server 172.31.24.119:8080;
}
upstream api2k {
     server 172.31.24.119:8080;
     keepalive 100;
}

server {

# 中略(元々記載されている内容 ※index.htmlを含む)

    location /api1 {
        fastcgi_pass api1;
        include fastcgi_params;
    }
    location /api2 {
        proxy_pass http://api2/;
    }
    location /api2k {
        proxy_pass http://api2k/;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}

なお、このまま実行すると、SELinuxに起因するセキュリティにより、http_proxyが動作しません。以下の設定により、動作できるようになります。

webサーバ
# setsebool -P httpd_can_network_relay on

1.3 apサーバ(Go言語)

apサーバのファイルディスクリプタを増やしておきます。これをしないと、同時接続が1000を超えたあたりで、アプリがダウンします。

apサーバ
$ sudo vi /etc/security/limits.conf
/* 以下を追記 */
* soft nofile 64000
* hard nofile 64000
$ sudo reboot now

FastCGI用のアプリapi1.goと、HTTP用のアプリapi2.goを作成します。

api1.go
package main

import (
    "fmt"
    "net"
    "net/http"
    "net/http/fcgi"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, `
/* nginxのデフォルトのindex.htmlを貼り付ける*/
`)
}

func main() {
    l, err := net.Listen("tcp", ":9000")
    if err != nil {
        return
    }
    http.HandleFunc("/", handler)
    fcgi.Serve(l, nil)
}
api2.go
package main

import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, `
/* nginxのデフォルトのindex.htmlを貼り付ける*/
`)
}

func main() {
    http.HandleFunc("/", handler)
    err := http.ListenAndServe(":8080", nil);
    if err != nil {
        return
    }
}

以下により、コンパイルして実行させておきます。

apサーバ
$ go build api1.go
$ go build api2.go
$ ./api1 &
$ ./api2 &

2. 測定結果

testサーバでabを実行させます。

testサーバ
$ ab -c 10000 -n 1000000 -r http://172.31.20.18/
$ ab -c 10000 -n 1000000 -r http://172.31.20.18/api1
$ ab -c 10000 -n 1000000 -r http://172.31.20.18/api2
$ ab -c 10000 -n 1000000 -r http://172.31.20.18/api2k

測定結果を以下に示します。

アクセス先 動作 Requests/sec エラー数
/ index.html参照 2,530 1,362
/api1 FastCGI接続 2,097 2,765
/api2 http_proxy接続 1,813 9,843
/api2k http_proxy接続(KeepAliveあり) 3,845 1,467

なんと、この条件では、webサーバのindex.htmlを参照するよりも、http_proxy(KeepAliveあり)でapサーバと通信した方が、速くなりました。

さらに、結果を分かりやすくするために、testサーバ〜webサーバのボトルネックの影響を外して、webサーバローカルでabをkeepaliveありでも測定してみます。

webサーバ
$ ab -c 100 -n 1000000 -k http://172.31.20.18/
$ ab -c 100 -n 1000000 -k http://172.31.20.18/api1
$ ab -c 100 -n 1000000 -k http://172.31.20.18/api2
$ ab -c 100 -n 1000000 -k http://172.31.20.18/api2k

測定結果を以下に示します。

アクセス先 動作 Requests/sec エラー数
/ index.html参照 38,754 0
/api1 FastCGI接続 2,251 0
/api2 http_proxy接続 2,150 0
/api2k http_proxy接続(KeepAliveあり) 10,378 0

さすがに、今度は、index.html参照が最速でしたが、これは比較対象用なので、apサーバとの通信に限定すると、http_proxy(KeepAliveあり)が最速となります。

以上の結果により、http_proxyでkeepaliveした状態が、明らかに性能が出ることがわかりました。keepaliveによりコネクションプーリング状態になり、コネクション接続切断のオーバーヘッドが無くなるためと考えられます。

なお、keepalive設定の数値は、コネクションプーリングの最小数ですが、最大値ではありません。最大値は別途、max_connsにより制限をする必要があります。詳細は、ngx_http_upstream_module モジュールを参照してください。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?