Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transactions #1

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 11 additions & 128 deletions README.org
Original file line number Diff line number Diff line change
@@ -1,48 +1,21 @@
* basho_bench
** Overview
[[http://travis-ci.org/basho/basho_bench][Travis-CI]] :: [[https://secure.travis-ci.org/basho/basho_bench.png]]

[[http://docs.basho.com/riak/latest/cookbooks/Benchmarking/][Additional documentation on docs.basho.com]]
[[https://github.com/basho/basho_bench/blob/master/README.org][For general information about basho_bench, please refer to the original README]]

Basho Bench is a benchmarking tool created to conduct accurate and
repeatable performance tests and stress tests, and produce
performance graphs.

** Modification

Originally developed to benchmark Riak, it exposes a pluggable
driver interface and has been extended to serve as a benchmarking
tool across a variety of projects.

Basho Bench focuses on two metrics of performance:

- Throughput: number of operations performed in a timeframe,
captured in aggregate across all operation types
- Latency: time to complete single operations, captured in
quantiles per-operation

** Quick Start

You must have [[http://erlang.org/download.html][Erlang/OTP R13B03]] or later to build and run Basho
Bench, and [[http://www.r-project.org/][R]] to generate graphs of your benchmarks. A sane
GNU-style build system is also required if you want to use =make=
to build the project.

#+BEGIN_SRC shell
git clone git://github.com/basho/basho_bench.git
cd basho_bench
make all
#+END_SRC

This will build an executable script, =basho_bench=, which you can
use to run one of the existing benchmark configurations from the
=examples/= directory. You will likely have to make some minor directory
changes to the configs in order to get the examples running (see, e.g., the
source of the bitcask and innostore benchmark config files for direction).
Two files are added for benchmarking floppystore:
- src/basho_bench_driver_floppystore.erl: defines the initialization of a benchmarking thread and how it executes put/get operations.
- examples/floppstore.config: contains benchmark parameters.

** Run a benchmark
#+BEGIN_SRC shell
$ ./basho_bench examples/riakc_pb.config
INFO: Est. data size: 95.37 MB
INFO: Using target ip {127,0,0,1} for worker 1
INFO: Starting max worker: <0.55.0>
$ ./basho_bench examples/floppystore.config
#+END_SRC

At the end of the benchmark, results will be available in CSV
Expand All @@ -51,99 +24,9 @@ INFO: Starting max worker: <0.55.0>

#+BEGIN_SRC shell
$ make results
priv/summary.r -i tests/current
Loading required package: proto
Loading required package: reshape
Loading required package: plyr
Loading required package: digest
null device
1
$ open tests/current/summary.png
#+END_SRC

** Troubleshooting Graph Generation

If make results fails with the error =/usr/bin/env: Rscript --vanilla: No such file or directory=
please edit priv/summary.r and replace the first line with the full path to the Rscript binary on your system

If you receive the error message =Warning: unable to access index for repository http://lib.stat.cmu.edu/R/CRAN/src/contrib=
it means the default R repo for installing additional packages is broken, you can change it as follows:

#+BEGIN_SRC shell
$ R
> chooseCRANmirror()
Selection: 69
quit()
make results
#+END_SRC

** Customizing your Benchmark
Basho Bench has many drivers, each with its own configuration, and
a number of key and value generators that you can use to customize
your benchmark. It is also straightforward -- with less than 200
lines of Erlang code -- to create custom drivers that can exercise
other systems or perform custom operations. These are covered more
in detail in the [[http://docs.basho.com/riak/latest/cookbooks/Benchmarking/][documentation]].

** Benchmarking with riak-java-client
The [[https://github.com/basho/riak-java-client][riak-java-client]] can be used to benchmark a Riak cluster. There
is an example configuration in =examples/riakc_java.config=. You
will need the [[https://github.com/basho/bench_shim][bench_shim]] project. You will also need to uncomment
and edit the following line in basho_bench's =rebar.config=, adding
your own erlang cookie value:

#+BEGIN_SRC shell
%% {escript_emu_args, "%%! -name [email protected] -setcookie YOUR_ERLANG_COOKIE\n"}.
#+END_SRC

** Alternative Graph Generation by gnuplot
You can generate graphs using gnuplot.

#+BEGIN_SRC shell
$ ./priv/gp_throughput.sh
#+END_SRC

#+BEGIN_SRC shell
$ ./priv/gp_latency.sh
#+END_SRC

By passing =-h= option to each script, help messages are shown.

Some of options for these scripts are:

- =-d TEST_DIR= : comma separated list of directories which include
test result CSV files
- =-t TERMINAL_TYPE= : gnuplot terminal type
- =-P= : just print gnuplot script without drawing graph

For example, you can draw graphs with ASCII characters
by the option =-t dumb=, which is useful in non-graphical
environment or quick sharing of result in chat.

Also, you can plot multiple test runs on a single plot by using "-d" switch.

** Contributing
We encourage contributions to Basho Bench from the community.

1) Fork the =basho_bench= repository on [[https://github.com/basho/basho_bench][Github]].
2) Clone your fork or add the remote if you already have a clone of
the repository.
#+BEGIN_SRC shell
git clone [email protected]:yourusername/basho_bench.git
# or
git remote add mine [email protected]:yourusername/basho_bench.git
#+END_SRC
3) Create a topic branch for your change.
#+BEGIN_SRC shell
git checkout -b some-topic-branch
#+END_SRC
4) Make your change and commit. Use a clear and descriptive commit
message, spanning multiple lines if detailed explanation is
needed.
5) Push to your fork of the repository and then send a pull-request
through Github.
#+BEGIN_SRC shell
git push mine some-topic-branch
#+END_SRC
6) A Basho engineer or community maintainer will review your patch
and merge it into the main repository or send you feedback.
** Limitations
Right now it only has put/get interfaces and there is no support for transaction.
It only put/get for riak_dt_gcounter.
26 changes: 26 additions & 0 deletions examples/floppstore.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{mode, max}.

{duration, 1}.

{concurrent, 1}.

{driver, basho_bench_driver_floppystore}.

{key_generator, {uniform_int, 50000}}.

{value_generator, {fixed_bin, 10}}.

%%{operations, [{append, 1}, {read, 1}]}.
{operations, [{stx, 1}, {itx, 1}]}.
%%[{append, 1}, {read, 1}]}.
%%[{stx, 1}, {itx,1}]}. %% , {append, 1}, {read, 1}]}.

%% the second element in the list below (e.g., "../../public/bitcask") must point to
%% the relevant directory of a bitcask installation
{code_paths, ["../floppystore/ebin"]}.

{floppystore_nodes, ['[email protected]']}.
{floppystore_cookie, floppy}.

{floppystore_mynode, ['[email protected]', longnames]}.
{floppystore_types, [{riak_dt_gcounter, [increment]}, {riak_dt_gset, [add]}]}.
211 changes: 211 additions & 0 deletions src/basho_bench_driver_floppystore.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
%% -------------------------------------------------------------------
%%
%% basho_bench: Benchmarking Suite
%%
%% Copyright (c) 2009-2010 Basho Techonologies
%%
%% This file is provided to you under the Apache License,
%% Version 2.0 (the "License"); you may not use this file
%% except in compliance with the License. You may obtain
%% a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing,
%% software distributed under the License is distributed on an
%% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
%% KIND, either express or implied. See the License for the
%% specific language governing permissions and limitations
%% under the License.
%%
%% -------------------------------------------------------------------
-module(basho_bench_driver_floppystore).

-export([new/1,
run/4]).

-include("basho_bench.hrl").

-define(TIMEOUT, 1000).
-record(state, {node,
worker_id,
time,
type_dict}).
%key_dict}).

%% ====================================================================
%% API
%% ====================================================================

new(Id) ->
%% Make sure bitcask is available
case code:which(floppy) of
non_existing ->
?FAIL_MSG("~s requires floppystore to be available on code path.\n",
[?MODULE]);
_ ->
ok
end,

Nodes = basho_bench_config:get(floppystore_nodes),
Cookie = basho_bench_config:get(floppystore_cookie),
MyNode = basho_bench_config:get(floppystore_mynode, [basho_bench, longnames]),
Types = basho_bench_config:get(floppystore_types),

%% Try to spin up net_kernel
case net_kernel:start(MyNode) of
{ok, _} ->
?INFO("Net kernel started as ~p\n", [node()]);
{error, {already_started, _}} ->
ok;
{error, Reason} ->
?FAIL_MSG("Failed to start net_kernel for ~p: ~p\n", [?MODULE, Reason])
end,

%% Initialize cookie for each of the nodes
[true = erlang:set_cookie(N, Cookie) || N <- Nodes],
%true = erlang:set_cookie(Node, Cookie),

%% Try to ping each of the nodes
ping_each(Nodes),

%% Choose the node using our ID as a modulus
TargetNode = lists:nth((Id rem length(Nodes)+1), Nodes),
?INFO("Using target node ~p for worker ~p\n", [TargetNode, Id]),
%KeyDict= dict:new(),
TypeDict = dict:from_list(Types),
{ok, #state{node=TargetNode, time={1,1,1}, worker_id=Id, type_dict=TypeDict}}.

%% @doc Read a key
run(read, KeyGen, _ValueGen, State=#state{node=Node}) ->
Key = KeyGen(),
KeyType = get_key_type(Key),
BinaryKey = Key, %%<<(Key):32/big>>,
Res = rpc:call(Node, floppy, read, [BinaryKey, KeyType], ?TIMEOUT),
case Res of
{ok, _Value} ->
{ok, State};
{error, Reason} ->
{error, Reason};
{badrpc, Reason} ->
{badrpc, Reason};
_Reason ->
{ok, State}
end;
%% @doc Write to a key
run(append, KeyGen, ValueGen, State=#state{node=Node, worker_id=Id, type_dict=TypeDict}) ->
Key = KeyGen(),
Type = get_key_type(Key),
BinaryKey = Key, %%<<(Key):32/big>>,
{Type, KeyParam} = get_random_param(TypeDict, Type, Id, ValueGen()),
Res = rpc:call(Node, floppy, append, [BinaryKey, Type, KeyParam], ?TIMEOUT),
case Res of
{ok, _Result} ->
{ok, State};
{error, Reason} ->
{error, Reason};
{badrpc, Reason} ->
{badrpc, Reason};
_ ->
{ok, State}
end;
%% @doc Start a static transaction
run(stx, KeyGen, ValueGen, State=#state{node=Node, time=ClientTime, worker_id=Id, type_dict=Dict}) ->
random:seed(now()),
NumAppend = random:uniform(10),
NumRead = random:uniform(10),
ListAppends = get_random_append_ops(NumAppend, Dict, Id, KeyGen, ValueGen),
ListReads = get_random_read_ops(NumRead, KeyGen),
ListOps = ListAppends++ListReads,
Res = rpc:call(Node, floppy, clocksi_execute_tx, [ClientTime, ListOps], ?TIMEOUT),
case Res of
{ok, _ReadSet, CommitTime} ->
{ok, State#state{time=CommitTime}};
{error, Reason} ->
{error, Reason};
{badrpc, Reason} ->
{badrpc, Reason};
_Reason ->
{ok, State}
end;
run(itx, KeyGen, ValueGen, State=#state{node=Node, worker_id=Id, type_dict=Dict}) ->
random:seed(now()),
NumAppend = random:uniform(10),
NumRead = random:uniform(10),
ListAppends = get_random_append_ops(NumAppend, Dict, Id, KeyGen, ValueGen),
ListReads = get_random_read_ops(NumRead, KeyGen),
ListOps = ListAppends++ListReads,
RandomOps = [X||{_,X} <- lists:sort([ {random:uniform(), N} || N <- ListOps])],
{ok, TxId} = rpc:call(Node, floppy, clocksi_istart_tx, [now()], ?TIMEOUT),
ExecuteFun = fun(X) -> case X of
{update, UKey, UType, UParam} -> ok = rpc:call(Node, floppy, clocksi_iupdate, [TxId, UKey, UType, UParam]);
{read, RKey, RType} -> {ok, _} = rpc:call(Node, floppy, clocksi_iread, [TxId, RKey, RType])
end
end,
lists:foreach(ExecuteFun, RandomOps),
{ok, _} = rpc:call(Node, floppy, clocksi_iprepare, [TxId]),
End=rpc:call(Node, floppy, clocksi_icommit, [TxId]),
case End of
{ok, _} ->
{ok, State};
{error, Reason} ->
{error, Reason};
{badrpc, Reason} ->
{badrpc, Reason};
_Reason ->
{ok, State}
end.



%% Private
ping_each([]) ->
ok;
ping_each([Node | Rest]) ->
case net_adm:ping(Node) of
pong ->
?INFO("Finished pinging ~p", [Node]),
ping_each(Rest);
pang ->
?FAIL_MSG("Failed to ping node ~p\n", [Node])
end.

get_key_type(Key) ->
Rem = Key rem 10,
case Rem > 5 of
true ->
riak_dt_gcounter;
false ->
riak_dt_gset
end.

get_random_param(Dict, Type, Actor, Value) ->
Params = dict:fetch(Type, Dict),
random:seed(now()),
Num = random:uniform(length(Params)),
case Type of
riak_dt_gcounter ->
{riak_dt_gcounter, {lists:nth(Num, Params), Actor}};
riak_dt_gset ->
{riak_dt_gset, {{lists:nth(Num, Params), Value}, Actor}}
end.


get_random_append_op(Key, Dict, Actor, Value) ->
Type = get_key_type(Key),
{Type, Params} = get_random_param(Dict, Type, Actor, Value),
{update, Key, Type, Params}.

get_random_read_op(Key) ->
Type = get_key_type(Key),
{read, Key, Type}.

get_random_append_ops(Num, Dict, Actor, KeyGen, ValueGen) ->
%KeyList = [<<(KeyGen()):32/big>> || _ <- lists:seq(1, Num)],
KeyList = [KeyGen() || _ <- lists:seq(1, Num)],
[get_random_append_op(Key, Dict, Actor, ValueGen()) || Key <- KeyList].

get_random_read_ops(Num, KeyGen) ->
%KeyList = [<<(KeyGen()):32/big>> || _ <- lists:seq(1, Num)],
KeyList = [KeyGen() || _ <- lists:seq(1, Num)],
[get_random_read_op(Key) || Key <- KeyList].