モチベーション

Elasticsearchへの大量のリクエストを捌ける仕組みとしてcacheを導入したい

記事概要

昨年頃からElasticsearchと呼ばれる全文検索エンジンが脚光を浴びており様々な企業で採用されてきている.話題になっている理由は幾つかあるが,その中にHTTPでやりとりすることができるRESTfulなインタフェースを持っていることが挙げられる.また,HTTPを話すことができるモダンなシステムなため,NginxなどのHTTPを話せるミドルウェアとの親和性が高いのも魅力的.

そんなElasticsearchだが,検索エンジンとして使うとなるとそれなりの量のリクエストを捌く必要がある.試験的にスループット(リクエスト/秒)を向上させる仕組み検討しているのだが,ひとまず,フロントにリバースプロキシサーバを配置してコンテンツcacheを効かせようと考えている.しかし,実はElasticsearch単体でもcacheの機能を持っていることがわかった.そこで,NginxをフロントにおいたNginx + Elasticsearchな構成とElasticsearch単体の性能試験を行うことでどちらのcacheを採用するかの判断材料にしようと思う.

検証結果

結論から言うと、正しい検証結果が得られているとは言いがたい。良くない試験として後学の為に残していく。

環境

ベンチマークサーバ

  • AWS EC2
  • OS:Amazon Linux AMI 2014.09.2 (HVM)
  • Instance Type:m3.medium
    • vCPU:1 cpu
    • RAM :3.75 GB
    • HDD :1 x 4 (SSD)GB
    • NW Perfomance: Moderate

ベンチマークサーバ1(Nginx + Elasticsearch)の設定

適切なところにElasticsearchへのリバースプロキシの設定を行う. ちなみにvCPUが1つなのでNginxのワーカもそれに対応して1つにしている.

http{
  proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=my-key:8m max_size=50m inactive=120m;

  server {
    server_name ec2-WW-XX-YY-ZZ-.ap-northeast-1.compute.amazonaws.com;

    location / {
      proxy_pass http://127.0.0.1:9200;
      proxy_cache my-key;
      proxy_cache_key $host$uri$is_args$args;
      proxy_cache_valid 1h;
      client_max_body_size 8M;
      add_header X-Cache-Status $upstream_cache_status;
    }
  }
}

また,Elasticsearchのcache機能はデフォルトで有効になっているためelasticsearch.ymlの設定を変更する.

index.cache.filter.type: none
indices.fielddata.cache.size: 0%

このとき,index.cache.filter.type: noneはfilter cache機能を無効にする設定. また,indices.fielddata.cache.size: zeroはfield data cacheの容量を0にする設定 これで無効になるはず..

ベンチマークサーバ2(Elasticsearch)の設定

Elasticsearchのcache周りの設定はelasticsearch.ymlに記載する

indices.fielddata.cache.size: 10%
indices.fielddata.cache.expire: 120m 

wrkについて

wrkはHTTPリクエストを生成するベンチマークツールです.オプションを変化させるだけで多岐に富んだ試験を非常に簡単に行えるので,Webサーバなどの性能試験を行う時はこれを使うことにしている.インストール方法はコンパイルする方法もあるが,Macでbrewを使っている場合は,brew install wrkでもインストールできる.

wrkは以下のようなオプションを持っており.希望のHTTPリクエストを簡単に生成することができる.また,Luaでスクリプトを書いてそれを読み込ませてHTTPリクエストを生成することも可能.

➤  wrk --help
Usage: wrk <options> <url>
  Options:
    -c, --connections <N>  Connections to keep open
    -d, --duration    <T>  Duration of test
    -t, --threads     <N>  Number of threads to use

    -s, --script      <S>  Load Lua script file
    -H, --header      <H>  Add header to request
        --latency          Print latency statistics
        --timeout     <T>  Socket/request timeout
    -v, --version          Print version details

  Numeric arguments may include a SI unit (1k, 1M, 1G)
  Time arguments may include a time unit (2s, 2m, 2h)

この中で今回指定するオプションは,connectionthreadsdurationtimeoutあたりで,試験の時はthreads,duration,timeoutを固定にしてconnectionを変えていく感じがいいかな.

試験結果

wrk -c XX -t 5 -d 30s --timeout 10s http://対象サーバのアドレス/twitter/tweets/1?pretty=trueをそれぞれのサーバで実行する.この時-cで指定するコネクション数:XXの値を20から100まで20刻みで変化させてみる.結果は以下のとおり.

perfomance_tests_result

結果の分析

当初の予定だとNginx+Elasticsearchの構成の方が多くのリクエストを捌けると思っていたが,実験結果はElasticsearch単体の方がパフォーマンスが良かった.Nginxのcacheが効いているかヘッダーのX-Cache-Statusを確認したところHITとなっていたのでcacheは有効になっている.

Nginxのチューニングができておらず,何かがボトルネックになってパフォーマンスが上がらなかった可能性も有るが,そもそもNginxのバックエンドはファイルでElasticsearchのバックエンドはメモリなので速度差は出るだろう.また,Nginx(cache有り)とElasticsearch単体(cache)無しを比べても後者の方がリクエストを捌けていることから,Nginx + Elasticsearchを1つのVMで実現したのは無理があったのかもしれない.

今回のお題目が,m3.mediumのリソース下でできる最大限の努力での性能試験だったので,Nginx + Elasticsearchの構成を取るのは筋の良い手段じゃなかったのかな.とりあえず,EC2のインスタンスタイプm3.medium1つのリソース下でElasticsearchのスループットを上げるには,Elasticsearchが持っているcache機能を有効にすれば良さそう.日をおいて,もう少し分析をしてみよう.

まとめ

今回,wrkを使ったNginxとElasticsearchのcache性能お比較するための試験を行った.結果は,Elasticsearch単体の方が多くのリクエストを捌けるということになった.ただし,今回はElasticsearchのcacheが有利な条件で試験を行っているのでリソース量が変わればNginx + Elasticsearchの方が良いパフォーマンスを発揮する可能性がある.(例えば,Elasticsearchのcache用メモリが枯渇する場合,劇的にパフォーマンス落ちるはず.)

Nginxのチューニングについて何かアドバイス,お知恵がある方のご意見をお待ちしております.

参考

書籍

ハイパフォーマンスHTTPサーバ Nginx入門
  • Author: Clement Nedelcu
  • Manufacturer: アスキー・メディアワークス
  • Publish date: 2011-04-21
  • 高速スケーラブル検索エンジン ElasticSearch Server (アスキー書籍)
  • Author: Rafal Kuc (lにストローク符号、cにアクサン・テギュ付く)
  • Manufacturer: 角川アスキー総合研究所
  • Publish date: 2014-03-25