ときどき起きる

だいたい寝ている

運用中のElasticsearchからRallyを用いて負荷試験トラックを作成する

本記事はElastic Stack (Elasticsearch) Advent Calendar 2022の24日目の記事です。


こんにちは、pakioです。

本エントリでは、Rallyを用いて運用中のElasticsearchから負荷試験トラックを作成する方法、並びに複数負荷試験結果の比較方法を紹介したいと思います。 また、環境やその他要因による成約が一部あるため、そのあたりについても合わせて後半で開設予定です。

本エントリは2022/12/14に実施されたElasticsearchJP #51 LT大会で発表したRallyで支えるバージョン追従を補足する内容になります。

speakerdeck.com

ちなみに録画を見るとわかりますが、私のRallyのイントネーションは確実に熊本なまりに影響されたもので正しいものではないと思います。正しいイントネーション何なんだろう。

はじめに - Rallyとは?

RallyとはElastic社が開発するElasticsearch向けのベンチマークツールです。ツール自体はPythonで開発されており、pipでインストールが可能です。

esrally.readthedocs.io

ベンチマークの実行のほかにも、過去のベンチマーク結果との比較や、Elasticsearchクラスタのセットアップや各種メトリクスの監視なども行ってくれる、まさにオールインワンなツールとなっています。

  • Setup and teardown of an Elasticsearch cluster for benchmarking
  • Management of benchmark data and specifications even across Elasticsearch versions
  • Running benchmarks and recording results
  • Finding performance problems by attaching so-called telemetry devices
  • Comparing performance results

今回のブログでは、その中でも自らのインデックスをもとに負荷試験を実施できる、create-track機能およびrace機能の紹介を行います。

カスタムトラックの作成

以降、Rally 2.7.0 documentationからの翻訳および引用を一部含みます。 Define Custom Workloads: Tracks - Rally 2.7.0 documentation

1. 既存インデックスからカスタムトラックを作成

既存クラスター内のインデックスからカスタムトラックを作成したい場合、create-trackコマンドを利用することで基本的な負荷試験トラックが作成可能です。

esrally create-track --track=acme --target-hosts=127.0.0.1:9200 --indices="products,companies" --output-path=~/tracks

また、ロギングやメトリクス等のインデックスの場合日付ごとのインデックスになっているケースなどもあるかと思いますが、Rallyでは-*を指定しパターンにマッチしたインデックスを取得することも可能です。

esrally create-track --track=acme --target-hosts=127.0.0.1:9200 --data-streams="metrics-*,logs-*" --output-path=~/tracks

上記コマンドを実行すると、指定したoutput-path内にファイルが出力されます。

$ find tracks/acme
tracks/acme
tracks/acme/companies-documents.json
tracks/acme/companies-documents.json.bz2
tracks/acme/companies-documents-1k.json
tracks/acme/companies-documents-1k.json.bz2
tracks/acme/companies.json
tracks/acme/products-documents.json
tracks/acme/products-documents.json.bz2
tracks/acme/products-documents-1k.json
tracks/acme/products-documents-1k.json.bz2
tracks/acme/products.json
tracks/acme/track.json

ここで、-1kサフィックス付きのデータが存在します。Rallyではデータ全件を使ったベンチマーク以外にトラックの挙動を確かめられるテストモードが実装されており、この-1kのついたデータはテストで利用されるデータとなります。テストとはいえ実際のドキュメントからサンプリングされたものではあるため、十分な信頼性ですね。

オプションについて

コマンドを実行する際、認証情報やタイムアウト値、コネクション数など様々なオプションが指定でき、client-optionsにカンマ区切り文字列で指定します。

以下はその一例です。

▽ 通信の圧縮、basic authを有効

esrally create-track --track=acme --target-hosts=127.0.0.1:9200 --indices="products,companies" --output-path=~/tracks --client-options="basic_auth_user:'elastic',basic_auth_password:'secret-password',http_compress:true"

オプション一覧については公式ドキュメントをご覧ください。 Command Line Reference - Rally 2.7.0 documentation

2. ベンチマークの実施

作成されたトラックを用いてベンチマークを実行するには、raceコマンドを実行します。

esrally race --distribution-version=7.14.1 --track-path=~/tracks/acme

また、テストモードを用いて小規模データで試しに実行したい場合は--test-modeを引数に追加します。

esrally race --distribution-version=7.14.1 --track-path=~/tracks/acme --test-mode

各distribution versionの初回実行時にはダウンロードが発生しますが、完了次第それをもとにElasticsearchクラスタが構築され、トラックが実行されます。

    ____        ____
   / __ \____ _/ / /_  __
  / /_/ / __ `/ / / / / /
 / _, _/ /_/ / / / /_/ /
/_/ |_|\__,_/_/_/\__, /
                /____/

[INFO] Race id is [e72a728e-067f-44c8-b2f6-d4fc20591999]
[INFO] Preparing for race ...
[INFO] Racing on track [wiki] and car ['defaults'] with version [7.14.0].

Running delete-index                                                           [100% done]
Running create-index                                                           [100% done]
Running cluster-health                                                         [100% done]
Running bulk                                                                   [100% done]
Running search                                                                 [100% done]

------------------------------------------------------
    _______             __   _____
   / ____(_)___  ____ _/ /  / ___/_________  ________
  / /_  / / __ \/ __ `/ /   \__ \/ ___/ __ \/ ___/ _ \
 / __/ / / / / / /_/ / /   ___/ / /__/ /_/ / /  /  __/
/_/   /_/_/ /_/\__,_/_/   /____/\___/\____/_/   \___/
------------------------------------------------------

|                                                         Metric |   Task |          Value |   Unit |
|---------------------------------------------------------------:|-------:|---------------:|-------:|
|                     Cumulative indexing time of primary shards |        |    0.0711667   |    min |
...
|                                                     error rate | search |    0           |      % |


--------------------------------
[INFO] SUCCESS (took 27 seconds)
--------------------------------

ここで、ログの初めに表示されるRace IDは各実行ごとにユニークな値となっており、結果比較の際には各Race IDの差分を表示する形となります。

3. トラックのカスタマイズ

1の手順を実行して作成されたトラックにはbulkのオペレーションしか入っていませんが、負荷試験の多くのケースでは検索クエリのパフォーマンスも見たいかと思います。
RallyではトラックのカスタマイズにPythonで書いたスクリプトも利用可能なため、その機能を用いて検索クエリを投げるタスクを追加してみます。

3.1 クエリの用意

実行したい任意のクエリを用意します。クエリログを取得している方はそこから、していない方は実行したい任意のクエリを用意してください。
先ほど作成したトラック内に任意のディレクトリを作成(ここではqueriesとしています)、そこにクエリをJSON形式で保存して下さい。

$ tree queries

queries
├── query_1.json
├── query_2.json
└── query_3.json

3.2 スクリプト/トラックの用意

次に、用意した任意のクエリをランダムに読み込み、実行するPythonスクリプトを用意します。 ここでRallyではファイル名に制約があるため、track.pyというファイル名で保存します。

https://gist.github.com/pakio/749d7be3ea41abf2377608abed6c84e9#file-track-py Custom benchmarking track and script for EsRally · GitHub

上記のプログラムでは、作成したパラメータソースをmy-custom-param-sourceとして定義しており、これをtrack.json内に新規で追加したsearchオペレーションのparam-sourceとして呼び出すことでクエリを実行しています。

4. 履歴の比較

過去に実行したRaceは、以下のコマンドで表示できます。

$ esrally list races

    ____        ____
   / __ \____ _/ / /_  __
  / /_/ / __ `/ / / / / /
 / _, _/ /_/ / / / /_/ /
/_/ |_|\__,_/_/_/\__, /
                /____/


Recent races:

Race ID                               Race Timestamp    Track    Challenge    Car       ES Version    Revision                                  Rally Version    Track Revision    Team Revision    User Tags
------------------------------------  ----------------  -------  -----------  --------  ------------  ----------------------------------------  ---------------  ----------------  ---------------  -----------
e72a728e-067f-44c8-b2f6-d4fc20591999  20221224T061228Z  wiki                  defaults  7.14.0        dd5a0a2acaa2045ff9624f3729fc8a6f40835aa1  2.7.0                              d38ad85
47060ac5-61b6-46a6-86b3-ff1ffd7dfc3f  20221224T060401Z  wiki                  defaults  7.12.0        78722783c38caa25a70982b5b042074cde5d3b3a  2.7.0                              d38ad85
863a7d4f-d217-4852-8268-bf95a831f0bb  20221224T052447Z  wiki                  defaults  7.12.0        
-------------------------------
[INFO] SUCCESS (took 0 seconds)
-------------------------------

1列目がRace IDとなっており、race間の差分は以下のコマンドで確認できます。

esrally compare --baseline={比較元となるraceid} --contender={比較先となるraceid}

実行すると、改善した項目については緑で、悪化した項目については赤でハイライトした比較結果を表示します。

実行結果

制約について

Rallyを動かすうえで、いくつか環境によって制約が発生するようですので、その一部のご紹介です。

M1/2 Macを利用する場合

M1/2 Macを利用される場合、7.16.0以前のバージョンを利用したい場合、Rallyによる自動クラスタ構築ではなく、自前でクラスタを準備する必要があります。

Rallyは環境のセットアップ時に、ElasticのdownloadsからzipファイルでElasticsearchをダウンロードし実行しています。このサイト上でM1用であるMACOS AARCH64対応バイナリが配布開始されているのは7.16.0以降となっているため、それ以前のバージョンを利用したい場合には注意が必要です。

6系以前と7系以降の互換性

Elasticsearchの6系以前と7系以降では、主にmapping type廃止の影響でトラックを共有することができません。そのため、マッピングやbulkの形式など、一部人手を加えて調整してあげる必要があります。

終わりに

今回のブログではRallyを用いたカスタムトラックの作成方法と結果の比較方法について紹介しました。
個人的な印象ですが、この1年でRallyユーザの方や日本語で書かれたブログ記事なども多く見かけるようになってきた感じがします。実際に使ってみても便利なツールなので、まだ使われていない方は一度試してみることをお勧めします。

また、いろいろ調べながら書いている中で、約4ヵ月前に似たような内容のテックブログがビザスクさんから公開されているのを見つけましたが、書き直す時間もないので書ききってしまいました。かなり詳細にオプション等も解説されていたので、もし本ブログで不足する内容があればビザスクさんのテックブログ、もしくは公式ドキュメントをご参照ください。

tech.visasq.com