drnbench 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,296 @@
1
+ # Drnbench
2
+
3
+ ## Description
4
+
5
+ Drnbench is a benchmark tool for Droonga.
6
+
7
+ It may be used for other HTTP servers.
8
+
9
+ Drnbench provides features to send multiple random requests with different settings periodically.
10
+ Number of clients (requests) in each period will be automatically increased gradually.
11
+ So you'll be able to guess the limit performance of the throughput of a server, via the report like following:
12
+
13
+ n_clients,total_n_requests,queries_per_second,min_elapsed_time,max_elapsed_time,average_elapsed_time,200
14
+ 1,33,3.3,0.164632187,0.164632187,0.19133309036363635,0
15
+ 2,70,7.0,0.161510877,0.161510877,0.1846983412285715,0
16
+ 3,87,8.7,0.1658357,0.1658357,0.24303329366666668,0
17
+ ...
18
+
19
+ Drnbench provides two commands, for different styles of benchmarked servers.
20
+
21
+ * `drnbench-request-response`: benchmarks simple request-response style APIs.
22
+ * `drnbench-publish-subscribe`: benchmarks publish-subscribe style (including HTTP streaming) APIs.
23
+ This command is not implemented yet.
24
+
25
+ ## How to run benchmark?
26
+
27
+ ### Benchmarking with an HTTP server
28
+
29
+ Drnbench can benchmark throughput performance of an HTTP server with random requests.
30
+
31
+ In this scenario, you have to do:
32
+
33
+ * setup an HTTP server.
34
+ * prepare patterns of requests.
35
+
36
+ Drnbench will start multiple clients and send many requests based on the patterns file.
37
+
38
+ 1. Create a patterns file in the format:
39
+
40
+ {
41
+ "(pattern type 1 name)": {
42
+ "frequency": (appearance ratio in all requests),
43
+ "path": "(path to the endpoint)",
44
+ "method": "(HTTP method)",
45
+ "patterns": [
46
+ { "body": (request body 1 sent by POST method) },
47
+ { "body": (request body 2 sent by POST method) },
48
+ ...
49
+ ]
50
+ }
51
+ "(patterns type 2 name)": {
52
+ "frequency": (appearance ratio in all requests),
53
+ "patterns": [
54
+ {
55
+ "path": "(path to the endpoint 1)",
56
+ "method": "(HTTP method)",
57
+ "body": (request body 1 sent by POST method)
58
+ },
59
+ {
60
+ "path": "(path to the endpoint 2)",
61
+ "method": "(HTTP method)",
62
+ "body": (request body 2 sent by POST method)
63
+ },
64
+ ...
65
+ ]
66
+ },
67
+ ...
68
+ }
69
+
70
+ For example, a file "patterns.json" like:
71
+
72
+ {
73
+ "user search": {
74
+ "frequency": 0.61,
75
+ "method": "GET",
76
+ "patterns": [
77
+ { "path": "/users?q=foo" },
78
+ { "path": "/users?q=bar" },
79
+ ...
80
+ ]
81
+ },
82
+ "item search": {
83
+ "frequency": 0.32,
84
+ "method": "GET",
85
+ "patterns": [
86
+ { "path": "/items?q=foo" },
87
+ { "path": "/items?q=bar" },
88
+ ...
89
+ ]
90
+ },
91
+ ...
92
+ }
93
+
94
+ 2. Setup an HTTP server. For example, localhost:80.
95
+ 3. Run drnbench with the pattern file.
96
+
97
+ # cd ~/drnbench
98
+ # bundle exec bin/drnbench-request-response \
99
+ --start-n-clients=1 \
100
+ --end-n-clients=32 \
101
+ --step=1 \
102
+ --duration=10 \
103
+ --wait=0.01 \
104
+ --mode=http \
105
+ --request-patterns-file=/tmp/patterns.json \
106
+ --host=localhost \
107
+ --port=80
108
+
109
+ 4. You'll get a report.
110
+
111
+
112
+ ### Benchmarking of request-responsne style commands, with a Droonga-based search system
113
+
114
+ Drnbench can benchmark throughput performance of a Droonga-based search system with random requests.
115
+
116
+ In this scenario, you have to do:
117
+
118
+ * setup a Droonga-based search system.
119
+ * prepare patterns of requests for commands.
120
+
121
+ Drnbench will start multiple clients and send many requests based on the patterns file.
122
+
123
+ 1. Create a patterns file in the format:
124
+
125
+ {
126
+ "(pattern type 1 name)": {
127
+ "frequency": (appearance ratio in all requests),
128
+ "command": "(command name)",
129
+ "patterns": [
130
+ { command parameters 1 },
131
+ { command parameters 2 },
132
+ { command parameters 3 },
133
+ ...
134
+ ]
135
+ }
136
+ "(patterns type 2 name)": {
137
+ ...
138
+ },
139
+ ...
140
+ }
141
+
142
+ For example, a file "patterns.json" like:
143
+
144
+ {
145
+ "user search": {
146
+ "frequency": 0.61,
147
+ "command": "search",
148
+ "patterns": [
149
+ {
150
+ "queries": {
151
+ "users": {
152
+ "source": "User",
153
+ "condition": "age >= 10",
154
+ "sortBy": { "keys": ["-birthday"], "offset": 0, "limit": 100" },
155
+ "output": {
156
+ "elements": [
157
+ "count",
158
+ "records"
159
+ ],
160
+ "attributes": ["_key", "name", "age", "birhtday"],
161
+ "offset": 0,
162
+ "limit": 100
163
+ }
164
+ }
165
+ }
166
+ },
167
+ ...
168
+ ]
169
+ },
170
+ "item search": {
171
+ "frequency": 0.32,
172
+ "command": "search",
173
+ "patterns": [
174
+ {
175
+ "queries": {
176
+ "users": {
177
+ "source": "Item",
178
+ "condition": "visible == true",
179
+ "sortBy": { "keys": ["title"], "offset": 0, "limit": 100" },
180
+ "output": {
181
+ "elements": [
182
+ "count",
183
+ "records"
184
+ ],
185
+ "attributes": ["title", "price"],
186
+ "offset": 0,
187
+ "limit": 100
188
+ }
189
+ }
190
+ }
191
+ },
192
+ ...
193
+ ]
194
+ },
195
+ ...
196
+ }
197
+
198
+ 2. Setup a Droonga Engine server. For example, localhost:23003.
199
+ 3. Setup a Protocol Adapter server. For example, localhost:3003.
200
+ 4. Run drnbench with the pattern file.
201
+
202
+ # cd ~/drnbench
203
+ # bundle exec bin/drnbench-request-response \
204
+ --start-n-clients=1 \
205
+ --end-n-clients=32 \
206
+ --step=1 \
207
+ --duration=10 \
208
+ --wait=0.01 \
209
+ --mode=http-droonga \
210
+ --request-patterns-file=/tmp/patterns.json \
211
+ --host=localhost \
212
+ --port=3003
213
+
214
+ 5. You'll get a report.
215
+
216
+
217
+ ### Benchmarking of HTTP streaming APIs, with a Droonga-based search system
218
+
219
+ Drnbench can benchmark an HTTP streaming API based on a publish-subscribe command.
220
+
221
+ In this scenario, you have to do:
222
+
223
+ * prepare configuration files "fluentd.conf" and "catalog.json" for a Droonga Engine.
224
+ * prepare an express application works as a Droonga Protocol Adapter.
225
+ * prepare pattern files for subscribe request and feeded data.
226
+
227
+ Drnbench will run benchmark like:
228
+
229
+ 1. Prepare subscribers.
230
+ 2. Send "feed" messages to the Droonga Engine.
231
+ All subscribers will receive all published messages.
232
+ 3. Increase the number of subscribers.
233
+ 4. Repeat 2, 3, and 4.
234
+
235
+ Steps to run:
236
+
237
+ 1. Create a patterns file for a subscribe request:
238
+
239
+ {
240
+ "path": "/path/to/endpoint",
241
+ "method": "HTTP method",
242
+ "headers": {
243
+ "X-xxxx": "xxxxx",
244
+ },
245
+ "body": (sent as the request body)
246
+ }
247
+
248
+ For example, a file "watch-subscribe.json" like:
249
+
250
+ {
251
+ "path": "/droonga-streaming/watch?condition=keyword"
252
+ }
253
+
254
+ 2. Create a patterns file for messages to be feeded:
255
+
256
+ {
257
+ "type": "(message type)",
258
+ "dataset": "(dataset name)",
259
+ "body": (message body)
260
+ }
261
+
262
+ For example, a file "watch-feed.json" like:
263
+
264
+ {
265
+ "type": "watch.feed",
266
+ "dataset": "Watch",
267
+ "body": {
268
+ "targets": {
269
+ "body": "a content including the keyword"
270
+ }
271
+ }
272
+ }
273
+
274
+ 3. Run drnbench with the pattern file.
275
+
276
+ # cd ~/drnbench
277
+ # bundle exec bin/drnbench-publish-subscribe \
278
+ --start-n-subscribers=1000 \
279
+ --n-publishings=1000 \
280
+ --n-steps=10 \
281
+ --timeout=5 \
282
+ --subscribe-request-file=/tmp/watch-subscribe.json \
283
+ --feed-file=/tmp/watch-feed.json \
284
+ --protocol-adapter-port=80 \
285
+ --engine-config-path=/tmp/engine/
286
+
287
+ 4. You'll get a report.
288
+
289
+
290
+ ## License
291
+
292
+ GPLv3 or later.
293
+
294
+ Copyright (c) 2013-2014 Droonga Project
295
+
296
+ See LICENSE.txt for details.
@@ -0,0 +1,33 @@
1
+ # -*- mode: ruby -*-
2
+ #
3
+ # Copyright (C) 2013-2014 Droonga Project
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require "bundler/gem_helper"
19
+ require "packnga"
20
+
21
+ base_dir = File.join(File.dirname(__FILE__))
22
+ helper = Bundler::GemHelper.new(base_dir)
23
+ def helper.version_tag
24
+ version
25
+ end
26
+
27
+ helper.install
28
+ spec = helper.gemspec
29
+
30
+ Packnga::DocumentTask.new(spec) do |task|
31
+ task.original_language = "en"
32
+ task.translate_languages = ["ja"]
33
+ end
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ #
4
+ # Copyright (C) 2013-2014 Droonga Project
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ require "drnbench"
20
+ require "optparse"
21
+ require "shellwords"
22
+
23
+ config = Drnbench::PublishSubscribe::Configuration.new
24
+ option_parser = OptionParser.new do |parser|
25
+ parser.on("--start-n-subscribers=N", Integer,
26
+ "initial number of subscribers") do |n_subscribers|
27
+ config.start_n_subscribers = n_subscribers
28
+ end
29
+ parser.on("--n-publishings=N", Integer,
30
+ "number of publish times") do |n_publishings|
31
+ config.n_publishings = n_publishings
32
+ end
33
+ parser.on("--n-steps=N", Integer,
34
+ "number of benchmark steps") do |n_steps|
35
+ config.n_steps = n_steps
36
+ end
37
+ parser.on("--timeout=SECONDS", Float,
38
+ "timeout for receiving") do |timeout|
39
+ config.timeout = timeout
40
+ end
41
+ parser.on("--output-path=PATH", String,
42
+ "path to the output CSV file") do |output_path|
43
+ config.output_path = output_path
44
+ end
45
+
46
+ parser.on("--subscribe-request-file=PATH", String,
47
+ "path to the file which defines a request to subscribe") do |path|
48
+ config.subscribe_request_file = path
49
+ end
50
+ parser.on("--feed-file=PATH", String,
51
+ "path to the file which defines a message feeded to the engine") do |path|
52
+ config.feed_file = path
53
+ end
54
+
55
+ parser.on("--protocol-adapter-port=PORT", Integer,
56
+ "port number for the Droonga Protocol Adapter which is used for clients") do |port|
57
+ config.protocol_adapter.port = port
58
+ end
59
+ parser.on("--protocol-adapter-receive-port=PORT", Integer,
60
+ "port number for the Droonga Protocol Adapter which is used for the engine") do |port|
61
+ config.protocol_adapter.receive_port = port
62
+ end
63
+ parser.on("--protocol-adapter-application-dir=PATH", String,
64
+ "path to the directory of the Droonga Protocol Adapter") do |path|
65
+ config.protocol_adapter.application_dir = path
66
+ end
67
+ parser.on("--node=PATH", String,
68
+ "path to the node.js executable") do |node|
69
+ config.protocol_adapter.node = node
70
+ end
71
+ parser.on("--node-options=OPTIONS",
72
+ "options for node.js",
73
+ "you can specify this option multiple times") do |options|
74
+ config.protocol_adapter.node_options = Shellwords.split(options)
75
+ end
76
+
77
+ parser.on("--engine-config-path=PATH", String,
78
+ "path to the configuration directory for Droonga Engine") do |path|
79
+ config.engine.engine_config_path = path
80
+ end
81
+ parser.on("--fluentd=PATH", String,
82
+ "path to the fluentd executable") do |fluentd|
83
+ config.engine.fluentd = fluentd
84
+ end
85
+ parser.on("--fluentd-options=OPTIONS",
86
+ "options for fluentd",
87
+ "you can specify this option multiple times") do |options|
88
+ config.engine.fluentd_options = Shellwords.split(options)
89
+ end
90
+ end
91
+ args = option_parser.parse!(ARGV)
92
+
93
+ config.validate
94
+
95
+ runner = Drnbench::PublishSubscribe::GradualRunner.new(config)
96
+ runner.run
97
+
98
+ File.open(config.output_path, "w") do |file|
99
+ runner.total_results.each do |row|
100
+ file.puts(CSV.generate_line(row))
101
+ puts row.join(",")
102
+ end
103
+ end
104
+ puts "Statistics has been saved to #{config.output_path}"
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ #
4
+ # Copyright (C) 2013-2014 Droonga Project
5
+ #
6
+ # This program is free software: you can redistribute it and/or modify
7
+ # it under the terms of the GNU General Public License as published by
8
+ # the Free Software Foundation, either version 3 of the License, or
9
+ # (at your option) any later version.
10
+ #
11
+ # This program is distributed in the hope that it will be useful,
12
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+ # GNU General Public License for more details.
15
+ #
16
+ # You should have received a copy of the GNU General Public License
17
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
18
+
19
+ require "drnbench"
20
+ require "optparse"
21
+
22
+ config = Drnbench::RequestResponse::Configuration.new
23
+ option_parser = OptionParser.new do |parser|
24
+ parser.on("--duration=SECONDS", Float,
25
+ "duration of the benmark") do |duration|
26
+ config.duration = duration
27
+ end
28
+ parser.on("--wait=SECONDS", Float,
29
+ "wait for each request") do |wait|
30
+ config.wait = wait
31
+ end
32
+ parser.on("--start-n-clients=N", Integer,
33
+ "initial number of clients (optional)") do |n_clients|
34
+ config.start_n_clients = n_clients
35
+ end
36
+ parser.on("--end-n-clients=N", Integer,
37
+ "final number of clients (optional)") do |n_clients|
38
+ config.end_n_clients = n_clients
39
+ end
40
+ parser.on("--step=COUNT", Integer,
41
+ "step to increase number of clients (optional)") do |step|
42
+ config.step = step
43
+ end
44
+
45
+ parser.on("--mode=MODE", String,
46
+ "mode of benchmark (optional)",
47
+ "available modes:",
48
+ " http",
49
+ " http-droonga-search") do |mode|
50
+ config.mode = mode.gsub(/-/, "_")
51
+ end
52
+ parser.on("--request-patterns-file=PATH",
53
+ "path to request patterns JSON file") do |path|
54
+ config.request_patterns_file = File.expand_path(path)
55
+ end
56
+
57
+ parser.on("--default-host=HOST", String,
58
+ "default host name (optional)") do |host|
59
+ config.default_host = host
60
+ end
61
+ parser.on("--default-port=PORT", Integer,
62
+ "default port number (optional)") do |port|
63
+ config.default_port = port
64
+ end
65
+ parser.on("--default-path=PATH", String,
66
+ "default path (optional)") do |path|
67
+ config.default_path = path
68
+ end
69
+ parser.on("--default-method=METHOD", String,
70
+ "default HTTP method (optional)") do |method|
71
+ config.default_method = method
72
+ end
73
+
74
+ parser.on("--output-path=PATH",
75
+ "path to output statistics as a CSV file (optional)") do |path|
76
+ config.output_path = File.expand_path(path)
77
+ end
78
+ end
79
+ args = option_parser.parse!(ARGV)
80
+
81
+ config.validate
82
+
83
+ runner = Drnbench::RequestResponse::GradualRunner.new(config)
84
+ runner.run
85
+
86
+ File.open(config.output_path, "w") do |file|
87
+ file.puts runner.result.to_csv
88
+ end
89
+ puts "Statistics has been saved to #{config.output_path}"