From 0a8d7850d7764729b7694ad0dbe690972a1fde6e Mon Sep 17 00:00:00 2001 From: Alexander Chudnovets Date: Fri, 11 Jul 2014 14:25:20 -0400 Subject: [PATCH] Added locust integration --- README.md | 10 +++-- bench_runner.cfg | 4 -- benchmark_runner.cfg | 16 ++++++++ benchmark_runner.py | 76 ++++++++++++++++++++++++++++-------- magnetodb.py | 57 --------------------------- query.json | 12 ------ token => tests/test_query.py | 62 +++++++++++++++++++++++++++++ 7 files changed, 144 insertions(+), 93 deletions(-) delete mode 100644 bench_runner.cfg create mode 100644 benchmark_runner.cfg delete mode 100644 magnetodb.py delete mode 100644 query.json rename token => tests/test_query.py (59%) diff --git a/README.md b/README.md index 454ff4c..979f10c 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ -to run master: +To run benchmark: -locust -f magnetodb.py -H http://192.168.56.101:8480 --master -n 1000 +sudo python benchmark_runner.py /path/to/benchmark_runner.cfg /path/to/locust_file.py -to run slave: +Example: +sudo python benchmark_runner.py /home/alex/benchmark_runner.cfg /home/alex/locust/test_query.py -locust -f magnetodb.py -H http://192.168.56.101:8480 --no-web --slave +FIXME: +locust should be installed as package. I used venv in this script. diff --git a/bench_runner.cfg b/bench_runner.cfg deleted file mode 100644 index e15732b..0000000 --- a/bench_runner.cfg +++ /dev/null @@ -1,4 +0,0 @@ -[locust] -slave_count = 1 -locust_count = 100 -hatch_rate = 10 diff --git a/benchmark_runner.cfg b/benchmark_runner.cfg new file mode 100644 index 0000000..27db2f2 --- /dev/null +++ b/benchmark_runner.cfg @@ -0,0 +1,16 @@ +[global] +base_dir=/home/alex +result_dir_prefix=test + +[locust] +host_to_test=http://192.168.56.101:8480 +requests_count=1000 +master_ip=192.168.56.102 +master_port=5557 +worker_ips=192.168.56.102,192.168.56.102 +master_user=alex +master_password=password + +[192.168.56.102] +user=alex +password=password diff --git a/benchmark_runner.py b/benchmark_runner.py index d65d090..ee3a9da 100644 --- a/benchmark_runner.py +++ b/benchmark_runner.py @@ -1,7 +1,13 @@ import datetime +import ConfigParser import os import re import subprocess +import sys +import uuid + +from fabric.operations import run, sudo, put +from fabric.context_managers import settings, prefix, cd def change_rrd_dir(conf, rrd_dir): @@ -40,12 +46,44 @@ def set_collectd_conf(conf, conf_path='/etc/collectd/collectd.conf'): open(conf_path, 'w').write(conf) -def start_load(): - # Run loading tool here - # Simulate test run for now - import time - import random - time.sleep(random.randrange(60, 180)) +def start_load(cfg, locust_file): + host = cfg.get('locust', 'host_to_test') + requests_count = cfg.get('locust', 'requests_count') + master_ip = cfg.get('locust', 'master_ip') + master_port = cfg.get('locust', 'master_port') + master_user = cfg.get('locust', 'master_user') + master_password = cfg.get('locust', 'master_password') + + worker_ips = cfg.get('locust', 'worker_ips') + if not worker_ips: + # TODO: shutdown all + sys.exit(-1) + + for slave_ip in worker_ips.split(','): + slave_user = cfg.get(slave_ip, 'user') + slave_password = cfg.get(slave_ip, 'password') + start_locust_slave(slave_ip, slave_user, slave_password, locust_file, host, master_ip, master_port) + + start_locust_master(master_ip, master_port, master_user, master_password, locust_file, host, requests_count) + + +def runbg(cmd, sockname="dtach"): + return run('dtach -n `mktemp -u /tmp/%s.XXXX` %s' % (sockname, cmd)) + +def start_locust_master(master_ip, master_port, master_user, master_password, locust_file, host, requests_count): + with (settings(host_string=master_ip, user=master_user, password=master_password)): + with cd('locust'), prefix('source .venv/bin/activate'): + cmd = 'locust -f %s -H %s --master -n %s --master-bind-host=%s --master-bind-port=%s' + run(cmd % (locust_file, host, requests_count, master_ip, master_port)) + + +def start_locust_slave(slave_ip, slave_user, slave_password, locust_file, host, master_ip, master_port): + with (settings(host_string=slave_ip, user=slave_user, password=slave_password)): + with cd('locust'), prefix('source .venv/bin/activate'): + cmd = 'locust -f %s -H %s --no-web --slave --master-host=%s --master-port=%s' + slave_locust_file = '/tmp/%s.py' % uuid.uuid4() + put(locust_file, slave_locust_file) + runbg(cmd % (slave_locust_file, host, master_ip, master_port)) def get_timestamp_str(timestamp=None): @@ -59,10 +97,19 @@ def store_results(results_dir): os.rename(results_dir, '%s_%s' % (results_dir, get_timestamp_str())) -def run_bench(results_dir): + +def main(cfg_file, locust_file): + cfg = ConfigParser.ConfigParser() + cfg.read(cfg_file) + + base_dir =cfg.get('global', 'base_dir') + prefix = cfg.get('global', 'result_dir_prefix') + dir_name = '%s_%s' % (prefix, get_timestamp_str()) + results_dir = os.path.join(base_dir, dir_name) + print ("Setup monitioring...") stop_monitoring() - + rrd_dir = os.path.join(results_dir, 'rrd') os.makedirs(rrd_dir) conf = get_collectd_conf() @@ -71,7 +118,7 @@ def run_bench(results_dir): start_monitoring() print ("Start loading...") - start_load() + start_load(cfg, locust_file) print ("Saving results...") store_results(results_dir) @@ -79,11 +126,8 @@ def run_bench(results_dir): print ("Done.") -def main(): - base_dir = '/home/alex' - dir_name = 'test_%s' % get_timestamp_str() - run_bench(os.path.join(base_dir, dir_name)) - - if __name__ == '__main__': - main() + if len(sys.argv) < 3: + print "Usage: %s /path/to/config.cfg /path/to/locust_file.py" % sys.argv[0] + sys.exit(-1) + main(sys.argv[1], sys.argv[2]) diff --git a/magnetodb.py b/magnetodb.py deleted file mode 100644 index aa3200e..0000000 --- a/magnetodb.py +++ /dev/null @@ -1,57 +0,0 @@ -import ConfigParser - -import locust - - -cfg = ConfigParser.ConfigParser() -cfg.read('bench_runner.cfg') - -first_run = False - - -class UserBehavior(locust.TaskSet): - @locust.task - def query(self): - token = open('/home/alex/locust/token').read().strip() - req_body = open('/home/alex/locust/query.json').read() - req_url = ('/v1/e852b5ba507440fd99eee75593b3a35f' - '/data/tables/Thread/query') - req_headers = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'X-Auth-Token': token - } - self.client.post(req_url, req_body, headers=req_headers) - - -class MagnetoDBUser(locust.HttpLocust): - task_set = UserBehavior - min_wait=5000 - max_wait=9000 - - -# Slave code -def on_report_to_master(client_id, data): - global first_run - - if not first_run: - data["first_run"] = 1 - first_run = True - - -# Master code -def on_slave_report(client_id, data): - global first_run - runner = locust.runners.locust_runner - slave_count = cfg.getint('locust', 'slave_count') - locust_count = cfg.getint('locust', 'locust_count') - hatch_rate = cfg.getint('locust', 'hatch_rate') - - if (not first_run and slave_count and - runner.slave_count == slave_count): - runner.start_hatching(locust_count, hatch_rate) - first_run = True - - -locust.events.report_to_master += on_report_to_master -locust.events.slave_report += on_slave_report diff --git a/query.json b/query.json deleted file mode 100644 index 81bbfe5..0000000 --- a/query.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "key_conditions": { - "ForumName": { - "attribute_value_list": [ - { - "S": "MagnetoDB" - } - ], - "comparison_operator": "EQ" - } - } -} diff --git a/token b/tests/test_query.py similarity index 59% rename from token rename to tests/test_query.py index 40ea8e6..cfb0918 100644 --- a/token +++ b/tests/test_query.py @@ -1 +1,63 @@ +import locust + + +IS_FIRST_RUN = True +SLAVE_COUNT = 2 +LOCUST_COUNT = 100 +HATCH_RATE = 10 + +QUERY_RQ = """ +{ + "key_conditions": { + "ForumName": { + "attribute_value_list": [ + { + "S": "MagnetoDB" + } + ], + "comparison_operator": "EQ" + } + } +} +""" + +TOKEN = """ MIIIAQYJKoZIhvcNAQcCoIIH8jCCB+4CAQExCTAHBgUrDgMCGjCCBlcGCSqGSIb3DQEHAaCCBkgEggZEeyJ0b2tlbiI6IHsibWV0aG9kcyI6IFsicGFzc3dvcmQiXSwgInJvbGVzIjogW3siaWQiOiAiYWVlNzBhM2ZlY2QyNGViZGFiZGZiN2NlZjNjNGNjNTEiLCAibmFtZSI6ICJNZW1iZXIifV0sICJleHBpcmVzX2F0IjogIjIwMTQtMDctMThUMTg6Mjg6MjYuMDcxMzc0WiIsICJwcm9qZWN0IjogeyJkb21haW4iOiB7ImlkIjogIjE0MDI2OGUxZjgzMzRkYmU4ZDc2OTM3MjcxYWIxMWEyIiwgIm5hbWUiOiAiZG9tYWluMSJ9LCAiaWQiOiAiZTg1MmI1YmE1MDc0NDBmZDk5ZWVlNzU1OTNiM2EzNWYiLCAibmFtZSI6ICJwcm9qZWN0MSJ9LCAiY2F0YWxvZyI6IFt7ImVuZHBvaW50cyI6IFt7InVybCI6ICJodHRwOi8vMTkyLjE2OC41Ni4xMDE6ODQ4MC92MS9lODUyYjViYTUwNzQ0MGZkOTllZWU3NTU5M2IzYTM1ZiIsICJyZWdpb24iOiAiUmVnaW9uT25lIiwgImludGVyZmFjZSI6ICJhZG1pbiIsICJpZCI6ICIxODYxYTFkYjk5ZWQ0NzZlODg5YzE1Y2IzYmNmMjBhYyJ9LCB7InVybCI6ICJodHRwOi8vMTkyLjE2OC41Ni4xMDE6ODQ4MC92MS9lODUyYjViYTUwNzQ0MGZkOTllZWU3NTU5M2IzYTM1ZiIsICJyZWdpb24iOiAiUmVnaW9uT25lIiwgImludGVyZmFjZSI6ICJwdWJsaWMiLCAiaWQiOiAiM2FiZjlkMGQzNzI2NGU5Mjg1NDU4MjFlZDU0NzIxOWUifSwgeyJ1cmwiOiAiaHR0cDovLzE5Mi4xNjguNTYuMTAxOjg0ODAvdjEvZTg1MmI1YmE1MDc0NDBmZDk5ZWVlNzU1OTNiM2EzNWYiLCAicmVnaW9uIjogIlJlZ2lvbk9uZSIsICJpbnRlcmZhY2UiOiAiaW50ZXJuYWwiLCAiaWQiOiAiNTU0MDJjYTgwNmU3NGM2MDg2ZjIyYjFlMDZlMmZhODkifV0sICJ0eXBlIjogImt2LXN0b3JhZ2UiLCAiaWQiOiAiZTlmMmMzOWIxMDI5NDUwZWI4Y2RiZDZlZTZkMzk0ZjMiLCAibmFtZSI6ICJtYWduZXRvZGIifSwgeyJlbmRwb2ludHMiOiBbeyJ1cmwiOiAiaHR0cDovLzE5Mi4xNjguNTYuMTAxOjM1MzU3L3YyLjAiLCAicmVnaW9uIjogIlJlZ2lvbk9uZSIsICJpbnRlcmZhY2UiOiAiYWRtaW4iLCAiaWQiOiAiMTRmYzAyNTY2YjQwNGFjNGI0YTc5OTk5MTlkNDZiYjcifSwgeyJ1cmwiOiAiaHR0cDovLzE5Mi4xNjguNTYuMTAxOjUwMDAvdjIuMCIsICJyZWdpb24iOiAiUmVnaW9uT25lIiwgImludGVyZmFjZSI6ICJpbnRlcm5hbCIsICJpZCI6ICIyMDEyMTdiMjJlMGY0NDc3OTg5ZTQ5Mzc1YzQzZTkxZSJ9LCB7InVybCI6ICJodHRwOi8vMTkyLjE2OC41Ni4xMDE6NTAwMC92Mi4wIiwgInJlZ2lvbiI6ICJSZWdpb25PbmUiLCAiaW50ZXJmYWNlIjogInB1YmxpYyIsICJpZCI6ICI1NGEwMTdkZGQxZjg0ODQ2YjNmN2FkNzhmYjM4ZTI5YiJ9XSwgInR5cGUiOiAiaWRlbnRpdHkiLCAiaWQiOiAiZjlmOWY4NTEzMzkzNDllYWIxZGY4OGFkMTA4OTAzOWIiLCAibmFtZSI6ICJrZXlzdG9uZSJ9XSwgImV4dHJhcyI6IHt9LCAidXNlciI6IHsiZG9tYWluIjogeyJpZCI6ICIxNDAyNjhlMWY4MzM0ZGJlOGQ3NjkzNzI3MWFiMTFhMiIsICJuYW1lIjogImRvbWFpbjEifSwgImlkIjogImExMTMxMzA5Y2Y4MjRhMjY5MDIyNDExNmZlMjM2MjY1IiwgIm5hbWUiOiAidXNlcjEifSwgImlzc3VlZF9hdCI6ICIyMDE0LTA2LTE4VDE4OjI4OjI2LjA3MTQzMVoifX0xggGBMIIBfQIBATBcMFcxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVVbnNldDEOMAwGA1UEBwwFVW5zZXQxDjAMBgNVBAoMBVVuc2V0MRgwFgYDVQQDDA93d3cuZXhhbXBsZS5jb20CAQEwBwYFKw4DAhowDQYJKoZIhvcNAQEBBQAEggEAhzdBEX+wTCNO0IXVtOkVoDjuk-TGZbq17s12WxczFg8pUIIwa+5jaXeIw9s6cfacP5tSs+7rghZz+ClXEsI8SIVrLroPJsp5uQMQmmHYKZhLbBnUL2xnhibaD8zTlzCn7ExXnP0lBQ5zMS78Z1tGwodj29DQfLGxsbzwYlk4yrdLT-vcRWpclpiQDCwV8ABBT4ME4jv7qWYSS229DNHAYui2Aponbln8Pe785XYOC01VipLW-BOAyZik1zdeVfuU2IIZjylLCgVibAY1-bnfFT6J0acGmeol+vbT1F+T1yPHLfHPmUUcx0dyJ8vcDktlM0CaJpPqNWGFQvxUtGOY6Q== +""" + + +class UserBehavior(locust.TaskSet): + @locust.task + def query(self): + req_url = ('/v1/e852b5ba507440fd99eee75593b3a35f' + '/data/tables/Thread/query') + req_headers = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'X-Auth-Token': TOKEN.strip() + } + self.client.post(req_url, QUERY_RQ.strip(), headers=req_headers) + + +class MagnetoDBUser(locust.HttpLocust): + task_set = UserBehavior + min_wait = 5000 + max_wait = 9000 + + +# Master code +def on_slave_report(client_id, data): + global IS_FIRST_RUN + runner = locust.runners.locust_runner + + if IS_FIRST_RUN and runner.slave_count == SLAVE_COUNT: + runner.start_hatching(LOCUST_COUNT, HATCH_RATE) + IS_FIRST_RUN = False + + num_rq = sum([val.num_requests for val in + runner.request_stats.itervalues()]) + if runner.num_requests and num_rq >= runner.num_requests: + raise KeyboardInterrupt() + + +locust.events.slave_report += on_slave_report