Tengineはアジア最大級のECサイト「淘宝網」が公開しているWebサーバです。

Nginxをベースにいくつかの機能拡張を行い、また開発も続いていて最新のstableバージョンに追従しているようです。

主な機能拡張は上記のサイトにも上がっていますが、興味があるところを上げると、

  • nginx-1.6.2をベース。nginxと100%互換性がある
  • ダイナミックなモジュールの読み込みをサポート。モジュールの追加にTengineの再ビルドが必要ない
  • SO_REUSEPORT をサポート。接続がnginxの3倍高速化
  • SPDY v3をサポート
  • upstreamの負荷分散方式の追加。consistent hashやsticky session、upstreamのヘルスチェック、リクエスト処理中のホスト名の名前解決
  • access_logをremoteのsyslogに飛ばしたり、pipeを介しての出力に対応
  • cpu_affinityの自動設定

などなど、nginxを運用していていて(nginx plusにしかないとか、nginx plusにしかないとか、nginx plusにしかないとか)少し不満に思うところが強化されています。

このエントリではupstreamのヘルスチェックを試してみます。

Tengineのupstream health checkを試す

まず、Tengineをビルドします。環境はVagrant上のubuntu/trustyです。

sudo apt-get install -y language-pack-ja #警告避け
sudo apt-get install -y build-essential zlib1g-dev libjemalloc-dev
mkdir tengine
cd tengine
wget http://jaist.dl.sourceforge.net/project/pcre/pcre/8.36/pcre-8.36.tar.gz
tar zxf pcre-8.36.tar.gz
wget https://www.openssl.org/source/openssl-1.0.1k.tar.gz
tar zxf openssl-1.0.1k.tar.gz
wget http://tengine.taobao.org/download/tengine-2.1.0.tar.gz
tar zxf tengine-2.1.0.tar.gz
cd tengine-2.1.0
./configure --prefix=/home/vagrant/local/tengine \
        --without-dso \
        --with-http_stub_status_module \
        --with-pcre=../pcre-8.36 \
        --with-pcre-jit \
        --with-openssl=../openssl-1.0.1k \
        --with-jemalloc
make
make install

ここではpcreとopensslをstatic linkしていますが、システムのライブラリを使っても問題ありません。

upstream health checkの検証のために、tengineに8080、8081、8082の3つのポートをListenさせ、8080から他の2つへreverse proxyを行うように設定しました。

[tengine/8080] ---- [tengine/8081]
                 `- [tengine/8081]

設定ファイル

worker_processes  1;
daemon off;
error_log /dev/stderr info;
events {
  worker_connections  1024;
}

http {
  include     mime.types;
  default_type  application/octet-stream;
  access_log  off;
  upstream app {
    server localhost:8081;
    server localhost:8082;
    # 1000msec毎にチェックを行い、2回成功したらup、3回失敗したらdown、デフォルトはdown
    check interval=1000 rise=2 fall=3 timeout=1000 type=http default_down=true;
    check_http_send "GET /live.html HTTP/1.1\r\nConnection: close\r\nHost: localhost\r\n\r\n";
    check_http_expect_alive http_2xx;
  }
  server {
    listen 8080;
    location / {
      proxy_pass http://app;
    }
    location /status {
      check_status;
    }
  }
  server {
    listen 8081;
    location / {
      root html8081;
      index  index.html;
    }
  }
  server {
    listen 8082;
    location / {
      root html8082;
      index  index.html;
    }
  }
}

それぞれのドキュメントルートに、index.htmlとhealth check用のhtmlを置きます。

$ cd ~/local/tengine
$ mkdir html8081
$ echo "Hello World: 8081" >> html8081/index.html
$ echo "I'm live" >> html8081/live.html

$ mkdir html8082
$ echo "Hello World: 8082" >> html8082/index.html
$ echo "I'm live" >> html8082/live.html

そして、tengineを起動します。起動プログラム名はnginxのままです。

vagrant@vagrant-ubuntu-trusty-64:~/local/tengine$ ./sbin/nginx 
2015/01/14 06:08:26 [error] 1408#0: enable check peer: 127.0.0.1:8082 
2015/01/14 06:08:26 [error] 1408#0: enable check peer: 127.0.0.1:8081

さっそく何やらでてきました。チェックを行い、upstreamが2つ有効になったようです。ちなみに、上の設定では初期状態がダウンで、2回成功して初めてupstreamのサーバが有効になります。有効になる前にアクセスすると、502になってしまいます。

check_statusを設定したpathでupstreamの状態を取得できます。

vagrant@vagrant-ubuntu-trusty-64:~/local/tengine$ curl http://localhost:8080/status?format=json
{"servers": {
  "total": 2,
  "generation": 1,
  "server": [
    {"index": 0, "upstream": "app", "name": "127.0.0.1:8081", "status": "up", "rise": 59, "fall": 0, "type": "http", "port": 0},
    {"index": 1, "upstream": "app", "name": "127.0.0.1:8082", "status": "up", "rise": 60, "fall": 0, "type": "http", "port": 0}
  ]
}}

フォーマットは html, csv, jsonをサポートし、デフォルトはhtmlです。両方とも”up”となっています。残念ながらstatusを操作することはできないようです。

起動がちゃんとできているので、upstreamを一つ無効にしてみましょう。health check用のlive.htmlをrenameしてみます。

vagrant@vagrant-ubuntu-trusty-64:~/local/tengine$ mv html8082/live.html html8082/.live.html

するとエラーログに

2015/01/14 06:19:44 [error] 1426#0: *24 open() "/home/vagrant/local/tengine/html8082/live.html" failed (2: No such file or directory), client: 127.0.0.1, server: , request: "GET /live.html HTTP/1.1", host: "localhost"
2015/01/14 06:19:44 [error] 1426#0: check protocol http error with peer: 127.0.0.1:8082 
2015/01/14 06:19:45 [error] 1426#0: *28 open() "/home/vagrant/local/tengine/html8082/live.html" failed (2: No such file or directory), client: 127.0.0.1, server: , request: "GET /live.html HTTP/1.1", host: "localhost"
2015/01/14 06:19:45 [error] 1426#0: check protocol http error with peer: 127.0.0.1:8082 
2015/01/14 06:19:47 [error] 1426#0: *32 open() "/home/vagrant/local/tengine/html8082/live.html" failed (2: No such file or directory), client: 127.0.0.1, server: , request: "GET /live.html HTTP/1.1", host: "localhost"
2015/01/14 06:19:47 [error] 1426#0: check protocol http error with peer: 127.0.0.1:8082 
2015/01/14 06:19:47 [error] 1426#0: disable check peer: 127.0.0.1:8082

いくつかエラーが表示され、3回失敗しところで8082がdisableとなりました。check_statusでも確認します

vagrant@vagrant-ubuntu-trusty-64:~/local/tengine$ curl http://localhost:8080/status?format=json
{"servers": {
  "total": 2,
  "generation": 1,
  "server": [
    {"index": 0, "upstream": "app", "name": "127.0.0.1:8081", "status": "up", "rise": 103, "fall": 0, "type": "http", "port": 0},
    {"index": 1, "upstream": "app", "name": "127.0.0.1:8082", "status": "down", "rise": 0, "fall": 11, "type": "http", "port": 0}
  ]
}}

“down” と表示されました。

live.htmlを元に戻すと、

2015/01/14 06:22:51 [error] 1430#0: enable check peer: 127.0.0.1:8082

と表示され、再び8082が有効となりました。

health check機能は落ちたサーバを安全に切り離すのに使えるほか、デプロイ時にリクエストを取りこぼさないようにアプリケーションを再起動するのにも使えます。JVMなサーバを運用している場合はうれしいのではないでしょうか。あとはnginx plusと同じようにAPIで状態を操作できたら最高ですね

tengine、nginxのかゆいところに手が届く系のプロダクトとして覚えておくとよいかもしれません。

マスタリングNginxはisuconでも活躍しました

マスタリングNginx
マスタリングNginx
posted with amazlet at 15.01.14
Dimitri Aivaliotis
オライリージャパン
売り上げランキング: 260,111

このブログ記事について

このページは、Masahiro Naganoが2015年1月14日 15:47に書いたブログ記事です。

ひとつ前のブログ記事は「 Docker と SO_REUSEPORT を組み合わせてコンテナのHot Deployにチャレンジ」です。

次のブログ記事は「h2o と server_starter で graceful restart with Docker」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

ウェブページ

OpenID対応しています OpenIDについて
Powered by Movable Type 4.27-ja