The load test uses locustio to create configurable number of virtual TaskQueue users. There are two types of users:
- Producers (defined in
./producer_locust.pyscript). - Workers (defines in
./worker_locust.pyscript).
Each producer and worker repeatedly sends request to TaskQueue with delay about 1 second. Every action performed with a task is reported to validation log. The log is used for further consistency validation of TaskQueue activity.
This directory (AppTaskQueue/test/load) contains everything needed
for producing high load, measuring performance and validation of
TaskQueue behavior. But it requires existing TaskQueue servers
running behind a load balancer.
AppTaskQueue/test/suits/run-load-test.sh script can run entire
test automatically. It does number of things:
- Provisions TaskQueue service on VMs (started from appscale image).
- Initializes test project.
- Makes sure pull queue is defined and is empty.
- Starts specified number of users to produce high load.
- Analyses outcomes, reports result.
Assuming Python 3.6+ is installed on you local machine, Taskqueue and Zookeeper are available. Let's say TaskQueue address is 10.10.1.20:4000, Zookeeper is available at 10.10.1.25.
- Switch to
AppTaskQueue/test/loaddirectory. - Install required packages:
python3.6 -m venv "venv" venv/bin/pip install --upgrade pip venv/bin/pip install ../helpers venv/bin/pip install kazoo venv/bin/pip install locustio venv/bin/pip install requests venv/bin/pip install attr venv/bin/pip install psutil venv/bin/pip install tabulate - Make sure pull queue is defined and empty:
venv/bin/python ./prepare_queues.py --zookeeper-location 10.10.1.20:4000 \ --taskqueue-location 10.10.1.25 - Prepare logs directory and export environmental variables:
mkdir ./logs export VALIDATION_LOG=./logs export TEST_PROJECT=tq-test-proj
- Start producer and worker locusts, wait for processes to exit:
timeout 1800 \ venv/bin/locust --host 10.10.1.20:4000 --no-web \ --clients 2000 --hatch-rate 200 --num-request 10000 \ --csv-base-name "./logs/producers" \ --logfile "./logs/producers-log" \ --locustfile ./producer_locust.py \ > "./logs/producers-out" 2>&1 & PRODUCERS_PID=$! export PRODUCERS_PID # let workers know when producers are terminated timeout 2100 \ venv/bin/locust --host 10.10.1.20:4000 --no-web \ --clients 200 --hatch-rate 20 \ --csv-base-name "./logs/workers" \ --logfile "./logs/workers-log" \ --locustfile ./worker_locust.py \ > "./logs/workers-out" 2>&1 & WORKERS_PID=$! wait ${PRODUCERS_PID} wait ${WORKERS_PID} # It worth checking status 124 (timeout) and other non-zero codes - Check outcomes:
venv/bin/python ./check_consistency.py --validation-log ./logs \ --taskqueue-location 10.10.1.20:4000 \ --ignore-exceeded-retry-limit venv/bin/python ./check_performance.py --locust-log ./logs
Let's say you have 6 VMs started from appscale image and connected
to the same private network. Assuming your ssh key ~/.ssh/id_rsa is
authorized for ubuntu user on all of those machines (and ubuntu user has sudo
privileges).
- Create layout.txt file containing wanted TaskQueue cluster layout:
Read
cat > ./layout.txt << CONTENT ROLE PUBLIC_IP/HOST_NAME PRIVATE_IP postgres 192.168.100.41 10.10.8.21 zookeeper 192.168.100.42 10.10.8.22 loadbalancer 192.168.100.43 10.10.8.23 taskqueue 192.168.100.42 10.10.8.22 taskqueue 192.168.100.43 10.10.8.23 taskqueue 192.168.100.44 10.10.8.24 taskqueue 192.168.100.45 10.10.8.25 CONTENT
AppTaskQueue/test/suites/layout-example.txtfor more details on layout file. - Start the load test:
${APP_TASK_QUEUE_DIR}/test/suites/run-load-test.sh \ --key-location ~/.ssh/id_rsa \ --user-name ubuntu \ --layout-file ./layout.txt \ --tq-per-vm 10 \ --producers 2000 \ --workers 200 \ --locust-timeout 3600 \ --logs-dir .logs/
Every line in the validation log corresponds to a single task and describes what action has been done with it (ADDED, LEASED or DELETED). Here are examples of log entries:
1535025645514 ADDED b4ed57cb-4a5f-44f4-960d-9a1177159534 13950 37 8852
1535025922571 LEASED c4c49dea-fb75-4ec5-b50c-5ecc63e6e624 1535025952384
1535025925987 DELETED 34405b92-eafa-4d23-9afe-5e9536d5fc5e 5
Where items in line have a following meaning:
<TIMESTAMP_MS> ADDED <TASK_ID> <WORK_TIME_FOR_RETRIES>
<TIMESTAMP_MS> LEASED <TASK_ID> <LEASE_EXPIRES>
<TIMESTAMP_MS> DELETED <TASK_ID> <RETRY_COUNT_AT_DELETION_TIME>
./check_consistency.py script verifies that history of every task
matches the pattern:
ADDED > LEASED (> LEASED)* (DELETED)? Where:
- Task is not leased before previous lease is expired.
- Task is not leased more than retry_limit times (it's ignored for now as our implementation of TaskQueue allows more retries).
- Task should be retried until it's deleted (succeeded) or run out of retries.
- Task can't be deleted or leased before it's added.
Currently, main goal of the load test is to prove that TaskQueue behaves
consistently under load. ./check_performance.py script just parses locust
logs and prints some performance properties, it doesn't verify
if performance was improved or worsened comparing to master.
The test should fail if noticeable impairment is in place.
As of now, the test collect information about behavior consistency, service throughput, average response time response time distribution and failures percent.
It would be useful to track CPU, memory and traffic usage on all of machines in the cluster.
Push Queue producer and worker should be implemented. Current Pull Queue producer and worker should start using tags so more types of load will be covered.
Helper scripts need to be implemented for easier testing of different scenarios.
The test can be run outside particular folder, so it is currently problematic
to configure .gitignore to match venv, Python3.6.6, null, logs, etc.
files which are created by the test.
Probably we should force user to run the test from some particular folder so we know where artifact files are located.
A single locust process can run limited number (~thousands) of virtual clients. Simulation of higher load may require multiple locust processes, consequently, one machine may not be enough. Fortunately, locustio supports cluster mode. In this mode many locust processes are connected to a single cluster managed from master process.
So at some point of time we will have to implement mechanisms for starting locust cluster, optionally on multiple machines.