Riak doc の Basho Bench を意訳してみた


# Basho Bench

大雑把な意訳、訳しにくい箇所は英文のまま転載します。
http://docs.basho.com/riak/1.3.2/cookbooks/Benchmarking/

## Overview

Basho Bench は、反復可能なパフォーマンステストとストレステストを正確に行なうために作成されたベンチマークツールです。パフォーマングラフの生成も行ないます。

オリジナル版は、Riak をベンチマークするために Dave Smith (Dizzy) によって開発されました。プラグイン可能なドライバーのインタフェースが公開されており、様々なプロジェクトに対するベンチマークツールとして役立つように拡張されました。新しいドライバーは Erlang で書くことができ、一般的に 200 行より少ないコードです。

## Download

Bash Bench のメインレポジトリは github にあります。
http://github.com/basho/basho_bench/

## How does it work?

Basho Bench のスクリプト (basho_bench.erl) を開始すると、設定ファイル (basho_bench_config.erl) を読み込み、結果を格納するディレクトリを新しく作成してから、テストがセットアップ (basho_bench_app.erl/basho_bench_sup.erl) されます。テストがセットアップされると、Basho Bench は下記を作成します。

* ひとつの stats プロセス (basho_bench_stats.erl):
 * stats プロセスは、オペレーションが完了したときに通知を受け取ります。オペレーションの経過時間をヒストグラムに格納します。ヒストグラムは定期的に summary.csv とオペレーション個別の csv にダンプされます。例えば、PUT オペレーションは put_latencies.csv にダンプされます。

* 設定された N 個の worker プロセス (basho_bench_worker.erl):
 * worker プロセスは、ドライバー構成の設定によって指定されたドライバーモジュールをラップします。ドライバーは、オペレーション構成の設定によって指定されたオペレーションの distribution を使用して、ランダムに呼び出されます。ドライバーがオペレーションを呼び出すレートは、mode 設定によって管理されます。

一度、これらのプロセスが作成および初期化されれば、Basho Bench は全ての worker プロセスに run コマンドを送信し、worker にテストを始めさせます。各 worker はランダムな数字を生成するための共通の seed で初期化されます。これにより、生成されたワークロードは後で反復できます。

During the test, the workers repeatedly call driver:run/4, passing in the next operation to run, a keygen function, a valuegen function, and the last state of the driver. worker プロセスはオペレーション時間を計り、オペレーションが完了すると stats プロセスにオペレーション時間を報告します。

最後に、テストが設定ファイルで指定された持続時間に達すると、全ての worker プロセスと stats プロセスが終了し、ベンチマークが終わります。テストの主な遅延とスループットは ./tests/current/ で確認できます。前回の結果は ./tests/YYYYMMDD-HHMMSS/ 形式で残ります。

## Installation

Erlang をインストールする必要があります。もしグラフを生成したければ R 言語をインストールする必要があります。後述する Generating Benchmark Graphs を参照してください。

Basho Bench は、現在のところソースコードのみが利用できます。Github 上の basho_bench レポジトリから最新のコードをクローンしてください。

```
git clone git://github.com/basho/basho_bench.git
cd basho_bench
make
```
## Usage

Basho Bench を実行します。

```
./basho_bench myconfig.config
```

これにより ./tests/current/ に結果が生成されます。設定ファイルを生成する必要があります。推奨されるアプローチは、"examples" ディレクトリのファイルを、後述する Configuration セクションを使用して設定を修正することです。

## Generating Benchmark Graphs

Basho Bench の出力を使用してグラフを作成できます。

* Throughput
 * テストの毎秒オペレーション数です。

* Latency
 * 99.9th percentile and max latency for the selected operations.

* Median latency
 * 95th percentile latency for the selected operations.

### Prerequisites

グラフを生成するには R 言語が必要です。必要であれば、テストを実施するサーバとは異なるサーバに R 言語をインストールできます。その場合は、テスト結果をテストを実施した端末から、グラフを生成する端末にコピーする必要があります。

### Generating Graphs

次のコマンドを実行してグラフを生成します。生成されたグラフは "tests/current/summary.png" に保存されます。

```
make results
```

次のように、手動で実行することも可能です。

```
priv/summary.r -i tests/current
```

## Configuration

Basho Bench は /example/ ディレクトリに利用できる多くのサンプル設定ファイルがあります。

### Global Config Settings

#### mode

The mode setting controls the rate at which workers invoke the {driver:run/4} function with a new operation. There are two possible values:

* {max}
 * 毎秒できるだけ多くの OPS を生成します

* {rate, N}
 * generate N ops per second, with exponentially distributed interarrival times

この設定が各ドライバー個別に適用されることに注意してください。例えば {rate, 5} が 3 個の worker で適用されると、Basho Bench は毎秒 15 個のオペレーションを生成します。

```
% Run at max, i.e.: as quickly as possible
{mode, max}

% Run 15 operations per second per worker
{mode, {rate, 15}}
```

#### concurrent

同時に実行する worker プロセス数 (default:3)です。これは、テスト対象 API へリクエストを送信する同時クライアント数となります。

```
% Run 10 concurrent processes
{concurrent, 10}
```

#### duration

テストを実施する分数 (default:5) です。

```
% Run the test for one hour
{duration, 60}
```

#### operations

The possible operations that the driver will run, plus their “weight” or likelihood of being run. 初期値は [{get,4},{put,4},{delete, 1}] です。これは 9 回のオペレーションごとに平均して "get" は 4 回、"put" は 4 回、"delete" は 1 回呼ばれることを意味します。

```
% Run 80% gets, 20% puts
{operations, [{get, 4}, {put, 1}]}.
```

オペレーションはドライバー単位で定義されます。したがって、全てのドライバーが "get"/"put" を実装するとは限らないでしょう。有効なオペレーションを決めるために、ドライバーのソースを調べます。例えば、HTTP インタフェースをテストしている場合は、対応しているオペレーションは "get" と "update" です。もしドライバーが指定されたオペレーションを対応していない場合は、次のようなエラーメッセージが表示されるかもしれません。

```
DEBUG:Driver basho_bench_driver_null crashed: {function_clause,
                                          [},
                                           {{{basho_bench_worker,
                                            worker_next_op,1}}},
                                           {{{basho_bench_worker,
                                            max_worker_run_loop,1}}}]}
```

#### driver

ロードを生成するために Basho Bench が使用するであろうドライバーのモジュール名です。ドライバーは単に in-process で呼ばれる (DETS のパフォーマンスを測定するように) か、ネットワーク接続を行ないリモートシステム上 (Riak Cluster をテストするように) でロードを生成するかもしれません。利用可能なドライバーの一部を下記に記載します。

* basho_bench_driver_http_raw
 * Riak Server 上で get/update/insert を行なうために Riak の HTTP インタフェースを使用します。

* basho_bench_driver_riakc_pb
 * Riak Server 上で get/put/update/delete を行なうために Riak の Protocol Buffers インタフェースを使用します。

* basho_bench_driver_riakclient
 * Riak Server 上で get/put/update/delete を行なうために Riak の Distributed Erlang インタフェースを使用します。

* basho_bench_driver_bitcask
 * Bitcask API を直接呼びます。

* basho_bench_driver_dest
 * DEST API を直接呼びます。

On invocation of the driver:run/4 method, the driver may return one of the following results:

* {ok, NewState}
 * オペレーションが成功しました。

* {error, Reason, NewState}
 * オペレーションは失敗したが、ドライバーは処理を続けることができます。例えば回復可能なエラーなどがあげられます。

* {stop, Reason}
 * オペレーションは失敗しました。ドライバーは処理を続けられない、あるいはできません。

* {'EXIT', Reason}
 * オペレーションは失敗し、ドライバーはクラッシュしました。

#### code_paths

いくつかのドライバーは、実行するために追加の Erlang コードを必要とします。コードへのパスを、環境設定の code_paths に指定してください。

#### key_generator

key ジェネレータは keys を作成するために使用されます。key ジェネレータの初期値は後述する {uniform_int, 100000} です。key ジェネレータは basho_bench_keygen.erl に定義されています。利用可能な key ジェネレータの一部を下記に記載します。

* {sequential_int, MaxKey}
 * 0 から MaxKey までの整数を生成します。この keygen インスタンスは、それぞれ worker 個別に生成されることに注意してください。

* {partitioned_sequential_int, MaxKey}
 * 前述した {sequential_int} と同じですが、worker の間で keyspace を平等に分割します。これは大きなデータセットをあらかじめ読み込みために役立ちます。

* {partitioned_sequential_int, StartKey, NumKeys}
 * 前述した {partitioned_sequential_int} と同じですが、StartKey で定義された番号からはじまり、StartKey + NumKeys までの整数を生成します。

* {uniform_int, MaxKey}
 * 0 から MaxKey の一様分布から整数を選びます。全ての整数に置いて、選ばれる可能性は同じです。

* {pareto_int, MaxKey}
 * パレート分布から整数を選びます。such that 20% of the available keys get selected 80% of the time. Note that the current implementation of this generator MAY yield values larger than MaxKey due to the mathematical properties of the Pareto distribution.

* {truncated_pareto_int, MaxKey}
 * same as {pareto_int}, but will NOT yield values above MaxKey.

* {function, Module, Function, Args}
 * key ジェネレータを外部関数に指定します。この外部関数が呼ばれたとき、worker の "Id" は "Args" にプリペンドされるでしょう。

* {int_to_bin, Generator}
 * takes any of the above "_int" generators and converts the number to a 32-bit binary. これはいくつかの binary key を要求するドライバーに必要とされます。

* {int_to_str, Generator}
 *  takes any of the above "_int" generators and converts the number to a string. これはいくつかの string key を要求するドライバーに必要とされます。

例えば:

```
% Use a randomly selected integer between 1 and 10,000
{key_generator, {uniform_int, 10000}}.

% Use a randomly selected integer between 1 and 10,000, as binary.
{key_generator, {int_to_bin, {uniform_int, 10000}}}.

% Use a pareto distributed integer between 1 and 10,000; values < 2000
% will be returned 80% of the time.
{key_generator, {pareto_int, 10000}}.
```

#### value_generator

value ジェネレータは values を作成するために使用されます。value ジェネレータは basho_bench_valgen.erl に定義されています。利用可能な value ジェネレータの一部を下記に記載します。

* {fixed_bin, Size}
 * バイナリをランダムに生成します。各バイナリは同じサイズですが、内容は異なります。

* {exponential_bin, MinSize, Mean}
 * 指数関数的に分散されたサイズのバイナリをランダムに生成します。Most values will be approximately MinSize + Mean bytes in size, with a long-tail of larger values.

* {uniform_bin, MinSize, MaxSize}
 * MinSize と MaxSize の間で平等に分散されたサイズのバイナリをランダムに生成します。

* {function, Module, Function, Args}
 * value を生成する外部関数を指定します。この外部関数が呼ばれたとき、worker の "Id" は "Args" にプリペンドされるでしょう。

特に指定しなければ、ジェネレータは {value_generator, {fixed_bin, 100}} が選択されます。

例えば:

```
% Generate a fixed size random binary of 512 bytes
{value_generator, {fixed_bin, 512}}.

% Generate a random binary whose size is exponentially distributed
% starting at 1000 bytes and a mean of 2000 bytes
{value_generator, {exponential_bin, 1000, 2000}}.
```

#### rng_seed

最初に使用するランダム seed 値 (default: {rng_seed, {42, 23, 12}}) です。This is explicitly seeded, rather than seeded from the current time, so that a test can be run in a predictable, repeatable fashion.

```
% Seed to {12, 34, 56}
{rng_seed, {12, 34, 56}.
```

#### log_level

どのメッセージをコンソールおよびディスクに記録するかを決めるレベル (default:debug) です。有効なレベルは debug, info, warn, error です。

#### report_interval

ヒストグラムのデータをディスクに書き込む間隔秒 (default:10) です。

#### test_dir

テスト結果のデータが書き込まれるディレクトリ (default:./test/) です。

### basho_bench_driver_riakclient Settings

basho_bench_driver_riakclient の環境設定です。

#### riakclient_nodes

テストに使用する Riak ノードのリストです。

```
{riakclient_nodes, ['[riak1@127.0.0.1](mailto:riak1@127.0.0.1)',
'[riak2@127.0.0.1](mailto:riak2@127.0.0.1)']}.
```

#### riakclient_cookie

Riak clients に接続するために使用される Erlang の cookie (default:riak) です。

```
{riakclient_cookie, riak}.
```

#### riakclient_mynode

ローカルノードの名前です。This is passed into net_kernel:start/1.

```
{riakclient_mynode,
['[basho_bench@127.0.0.1](mailto:basho_bench@127.0.0.1)', longnames]}.
```

#### riakclient_replies

GET オペレーション時の R-value と、PUT オペレーション時の W-value です。

```
% Expect 1 reply.
{riakclient_replies, 1}.
```

#### riakclient_bucket

value を読み書きするために使用される bucket (default:test)です。

```
% Use the "bench" bucket.
{riakclient_bucket, &lt;&lt;"bench"&gt;&gt;}.
```

### basho_bench_driver_riakc_pb Settings

#### riakc_pb_ips

worker を接続する IP アドレスのリストです。各 worker はランダムに IP を選びます。

```
% Connect to a cluster of 3 machines
{riakc_pb_ips, [{10,0,0,1},{10,0,0,2},{10,0,0,3}]}
```

#### riakc_pb_port

PBC インタフェースで接続するためのポート番号 (default:8087) です。

#### riakc_pb_bucket

テストを行なうために使用されるバケット名 (default:test) です。

### basho_bench_driver_http_raw Settings

#### http_raw_ips

worker を接続する IP アドレスのリスト (default:{http_raw_ips, ["127.0.0.1"]}) です。各 worker はランドロビン方式で各 IP にリクエストを行ないます。

```
% Connect to a cluster of machines in the 10.x network
{http_raw_ips, ["10.0.0.1", "10.0.0.2", "10.0.0.3"]}.
```

#### http_raw_port

HTTP サーバに接続するポート (default:8098) です。

```
% Connect on port 8090
{http_raw_port, 8090}.
```

#### http_raw_path

riak に接続するために使用されるベースのパス (default:/riak/test) です。

```
% Place test data in another_bucket
{http_raw_path, "/riak/another_bucket"}.
``` 

#### http_raw_params

URL の後ろに付ける追加パラメータ (default:"") です。これは r/w/dw/rw パラメータを設定するために津かわります。

```
% Set R=1, W=1 for testing a system with n_val set to 1
{http_raw_params, "?r=1&w=1"}.
```

#### http_raw_disconnect_frequency

どれくらいの頻度で、HTTP Client (worker) をサーバから強制的に切断するかを設定します。初期値は "{http_raw_disconnect_frequency, infinity}." で、強制的に切断しないことを意味します。

```
% Disconnect after 60 seconds
{http_raw_disconnect_frequency, 60}.

% Disconnect after 200 operations
{http_raw_disconnect_frequency, {ops, 200}}.
```

## Custom Driver

Custom Driver は次の callback を公開しなければいけません。よし詳細な情報は[存在しているドライバー](https://github.com/basho/basho_bench/tree/master/src)を参照してください。

```
% Create the worker
% ID is an integer
new(ID) -> {ok, State} or {error, Reason}.

% Run an operation
run(Op, KeyGen, ValueGen, State) -> {ok, NewState} or {error, Reason, NewState}.
```

## End

色々できるんだなー、別記事で実際に試してみよう。