drnbench 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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}"